"use strict"; import { $, $$$, tools } from "../tools.js"; import { fromNow } from "./relativeTime.js"; let loading = false; let firstRun = true; /********************************************************/ export function main() { $("rf").addEventListener("click", refresh); createWebSocket(); setInterval(updateOfflineTime, 5000); } 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) { if (loading) return; loading = true; let icon = $$$("#rf div.icon")[0]; icon.classList.toggle("spin"); getApiUpdate(x => { x.forEach(y => updateState(y)); setTimeout(() => { icon.classList.toggle("spin") loading = false; }, 950); }); } /********************************************************/ function guards(http) { if (http.readyState !== 4) { return false; } if (http.status === 401 || http.status === 403) { document.location.href = "/login"; return false; } if (http.status !== 200) { return false; } return true; } function getApiUpdate(callback) { let http = tools.makeRequest("POST", "/api/remote/update", () => { let response = http.responseText; if (! guards(http)) return; if (! response) return; let update = JSON.parse(response).result.update; callback(update); }); } function actionPerform(target, action) { let body = JSON.stringify({ target, action }); let contentType = "application/json"; let http = tools.makeRequest("POST", "/api/remote/control", () => { if (! guards(http)) return; let response = http.responseText; let result = JSON.parse(response).result; if (result.code != 0) { let state = $$$(`.host[name='${target}'] span.state`)[0]; state.innerHTML = '  ⦻  Failed'; setTimeout(update, 3000); } }, body, contentType); } /****************************************************/ function makeView(hosts) { let parent = $("bulletin"); if (! hosts) { parent.innerHTML = '

Error

'; return; } if (hosts.length == 0) { parent.innerHTML = '

No Hosts

'; return; } parent.innerHTML = `
`; for (const host of hosts) { let child = document.createElement("div"); child.setAttribute("name", host.name); child.classList.add("host"); child.innerHTML = `
${host.name}
`; let actions = child.querySelector(".remote-actions"); for (const action of host.actions) { let button = document.createElement("button"); button.classList.add("remote-action"); button.setAttribute("action", action); button.onclick = () => { child.setAttribute("state", "unknown"); child.querySelector("span.state") .innerHTML = '  ⇒  ' + action[0] + action.slice(1).toLowerCase(); actionPerform(host.name, action); }; actions.appendChild(button); } updateState(host, child); } } function updateState(host, child) { let parent = $("hosts"); let separator = $("separator"); let element = child ?? $$$(`div.host[name='${host.name}']`)[0]; element.setAttribute("state", host.online ? 'online' : 'offline'); element.setAttribute("last-seen", host.last_seen); if (host.online) { parent.insertBefore(element, separator); element.querySelector("span.state").innerHTML = ''; } else { separator.after(element); updateOfflineTime(host.name); } } function updateOfflineTime(name) { let attr = name ? `[name='${name}']` : ''; for (const element of $$$(`div.host${attr}[state='offline']`)) { let timestamp = element.getAttribute("last-seen"); let state = element.querySelector("span.state"); state.innerHTML = '  –  ' + fromNow(timestamp); } }