v0.21.0 scram password auth, cred and token management, browser tls-terminating proxy, viewer client
Test / test (push) Canceled after 0s
Test / test (push) Canceled after 0s
This commit is contained in:
1 parent
f192c26fa2
commit
9ab8c356d2
60 files changed
+6791
-747
No files matched your search
@@ -0,0 +1,67 @@
|
||||
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();
|
||||
Reference in new issue
Block a user