68 lines
2.3 KiB
JavaScript
68 lines
2.3 KiB
JavaScript
import { logout } from "./scram.js";
|
|
|
|
const base = new URL("..", location.href);
|
|
// The server writes its status path here, relative to the mount
|
|
const statusPath = document.querySelector('meta[name="logwisp-status"]').content;
|
|
const MAX_LINES = 5000;
|
|
const log = document.getElementById("log");
|
|
const state = document.getElementById("state");
|
|
let source = null;
|
|
|
|
function append(line) {
|
|
const atBottom = log.scrollTop + log.clientHeight >= log.scrollHeight - 4;
|
|
const row = document.createElement("div");
|
|
row.textContent = line;
|
|
log.append(row);
|
|
while (log.childElementCount > MAX_LINES) log.firstElementChild.remove();
|
|
if (atBottom) log.scrollTop = log.scrollHeight;
|
|
}
|
|
|
|
// The status answer names the stream path; its 401 is the only way to tell an
|
|
// expired session apart, since EventSource hides the status of a failure.
|
|
async function connect() {
|
|
let res;
|
|
try {
|
|
res = await fetch(new URL("./" + statusPath, base), { credentials: "same-origin", cache: "no-store", redirect: "error" });
|
|
} catch {
|
|
return retry("server unreachable");
|
|
}
|
|
if (res.status === 401) {
|
|
location.replace(new URL("login?next=view", location.href).href);
|
|
return;
|
|
}
|
|
const path = res.ok ? (await res.json().catch(() => ({})))?.endpoints?.stream : null;
|
|
if (typeof path !== "string" || !path.startsWith("/")) {
|
|
return retry(`status unavailable (${res.status})`);
|
|
}
|
|
// Stream paths are absolute in logwisp; the proxy may mount it under a prefix
|
|
source = new EventSource(new URL("./" + path.replace(/^\/+/, ""), base));
|
|
source.addEventListener("connected", () => { state.textContent = "live"; });
|
|
source.addEventListener("disconnect", () => {
|
|
source.close();
|
|
retry("server shut down");
|
|
});
|
|
source.onmessage = (event) => event.data.split("\n").forEach(append);
|
|
source.onerror = () => {
|
|
if (source.readyState === EventSource.CLOSED) retry("disconnected");
|
|
else state.textContent = "reconnecting…";
|
|
};
|
|
}
|
|
|
|
function retry(reason) {
|
|
state.textContent = `${reason}, retrying…`;
|
|
setTimeout(connect, 5000);
|
|
}
|
|
|
|
document.getElementById("logout").addEventListener("click", async () => {
|
|
source?.close();
|
|
try {
|
|
await logout(base);
|
|
} catch (err) {
|
|
state.textContent = err.message;
|
|
return;
|
|
}
|
|
location.replace(new URL("login", location.href).href);
|
|
});
|
|
|
|
connect();
|