diff --git a/kvmd/apps/kvmd/api/remote.py b/kvmd/apps/kvmd/api/remote.py index 3ad0fe80..a42b4d5e 100644 --- a/kvmd/apps/kvmd/api/remote.py +++ b/kvmd/apps/kvmd/api/remote.py @@ -20,10 +20,10 @@ class RemoteApi: # ===== - @exposed_http("POST", "/remote") - async def __state_handler(self, _: Request) -> Response: + @exposed_http("POST", "/remote/update") + async def __remote_update_handler(self, _: Request) -> Response: return make_json_response({ - "hosts": await self.__remote.get_state(), + "update": await self.__remote.update(), }) @exposed_http("POST", "/remote/control") diff --git a/web/share/js/remote/main.js b/web/share/js/remote/main.js index fd06e05d..1f1f9449 100644 --- a/web/share/js/remote/main.js +++ b/web/share/js/remote/main.js @@ -5,22 +5,45 @@ import { $, $$$, tools } from "../tools.js"; import { fromNow } from "./relativeTime.js"; -let prev_state = {}; - let loading = false; +let firstRun = true; + /********************************************************/ export function main() { - loadRemoteApi(x => makeView(x)); - setInterval(update, 10000); - $("rf").addEventListener("click", refresh); + createWebSocket(); + setInterval(updateOfflineTime, 5000); } -function update() { - loadRemoteApi(x => x.forEach(y => updateState(y))); - updateOfflineTime(); +function createWebSocket() { + let address = `wss://${window.location.host}/api/ws`; + let socket = new WebSocket(address); + + socket.onopen = () => { + console.log("WebSocket connection established."); + }; + + socket.onmessage = (e) => { + let { event_type, event } = JSON.parse(e.data); + + if (event_type != "remote_state") { + return; + } + + if (firstRun) { makeView(event); firstRun = false; } + else event.forEach(x => updateState(x)); + }; + + socket.onerror = () => { + socket.close(); + }; + + socket.onclose = () => { + console.log("Websocket connection lost. Retrying in 5 seconds."); + setTimeout(createWebSocket, 5000); + }; } function refresh(event) { @@ -30,8 +53,7 @@ function refresh(event) { let icon = $$$("#rf div.icon")[0]; icon.classList.toggle("spin"); - prev_state = {}; - loadRemoteApi(x => { + getApiUpdate(x => { x.forEach(y => updateState(y)); setTimeout(() => { icon.classList.toggle("spin") @@ -59,17 +81,15 @@ function guards(http) { return true; } -function loadRemoteApi(callback) { - let http = tools.makeRequest("POST", "/api/remote", () => { +function getApiUpdate(callback) { + let http = tools.makeRequest("POST", "/api/remote/update", () => { let response = http.responseText; if (! guards(http)) return; if (! response) return; - let hosts = JSON.parse(response).result.hosts; - let diff = stateDiff(hosts); - - callback(diff); + let update = JSON.parse(response).result.update; + callback(update); }); } @@ -84,9 +104,7 @@ function actionPerform(target, action) { let result = JSON.parse(response).result; if (result.code != 0) { - delete prev_state[target]; let state = $$$(`.host[name='${target}'] span.state`)[0]; - state.innerHTML = ' ⦻ Failed'; setTimeout(update, 3000); } @@ -122,7 +140,7 @@ function makeView(hosts) { child.innerHTML = `