mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-31 09:52:24 +00:00
Add relay health summary banner
This commit is contained in:
1 parent
9c8cc465ce
commit
09c0ac8127
3 files changed
+76
-2
No files matched your search
@@ -716,6 +716,18 @@
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
id="relayHealthSummary"
|
||||
class="rounded-md border border-border/70 bg-surface/40 p-3"
|
||||
>
|
||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||
<p class="text-2xs font-semibold uppercase tracking-extra-wide text-muted-strong">
|
||||
Relay status
|
||||
</p>
|
||||
<p id="relayHealthCounts" class="text-xs font-semibold text-text"></p>
|
||||
</div>
|
||||
<p id="relayHealthMessage" class="mt-1 text-xs text-muted"></p>
|
||||
</div>
|
||||
<label
|
||||
for="relayHealthTelemetryOptIn"
|
||||
class="inline-flex items-center gap-2 text-xs font-medium text-muted-strong"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { devLogger, userLogger } from "../utils/logger.js";
|
||||
|
||||
const TELEMETRY_STORAGE_KEY = "bitvid:relay-health-telemetry-opt-in";
|
||||
const PERSISTENT_FAILURE_THRESHOLD = 3;
|
||||
const USER_LOG_COOLDOWN_MS = 5 * 60 * 1000;
|
||||
|
||||
function resolveLogger(logger) {
|
||||
if (logger && logger.dev && logger.user) {
|
||||
@@ -90,8 +92,10 @@ class RelayHealthService {
|
||||
connected: false,
|
||||
lastLatencyMs: null,
|
||||
errorCount: 0,
|
||||
consecutiveFailures: 0,
|
||||
lastCheckedAt: null,
|
||||
lastErrorAt: null,
|
||||
lastUserLogAt: null,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -129,6 +133,7 @@ class RelayHealthService {
|
||||
const state = this.ensureRelayState(relayUrl);
|
||||
state.connected = true;
|
||||
state.lastCheckedAt = Date.now();
|
||||
state.consecutiveFailures = 0;
|
||||
if (Number.isFinite(latencyMs)) {
|
||||
state.lastLatencyMs = Math.max(0, Math.round(latencyMs));
|
||||
}
|
||||
@@ -140,10 +145,12 @@ class RelayHealthService {
|
||||
|
||||
recordRelayFailure(relayUrl, error) {
|
||||
const state = this.ensureRelayState(relayUrl);
|
||||
const now = Date.now();
|
||||
state.connected = false;
|
||||
state.errorCount += 1;
|
||||
state.lastCheckedAt = Date.now();
|
||||
state.lastErrorAt = Date.now();
|
||||
state.consecutiveFailures += 1;
|
||||
state.lastCheckedAt = now;
|
||||
state.lastErrorAt = now;
|
||||
|
||||
if (this.nostrClient && typeof this.nostrClient.markRelayUnreachable === "function") {
|
||||
this.nostrClient.markRelayUnreachable(relayUrl, 60000, {
|
||||
@@ -155,6 +162,18 @@ class RelayHealthService {
|
||||
relayUrl,
|
||||
error,
|
||||
});
|
||||
|
||||
if (
|
||||
state.consecutiveFailures >= PERSISTENT_FAILURE_THRESHOLD &&
|
||||
(!state.lastUserLogAt || now - state.lastUserLogAt >= USER_LOG_COOLDOWN_MS)
|
||||
) {
|
||||
state.lastUserLogAt = now;
|
||||
this.logger.user.warn("[relayHealth] Relay unreachable after repeated failures.", {
|
||||
relayUrl,
|
||||
errorCount: state.consecutiveFailures,
|
||||
lastError: error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async checkRelay(relayUrl) {
|
||||
|
||||
@@ -1252,6 +1252,9 @@ export class ProfileModalController {
|
||||
this.addRelayButton = null;
|
||||
this.restoreRelaysButton = null;
|
||||
this.relayHealthPanel = null;
|
||||
this.relayHealthSummary = null;
|
||||
this.relayHealthCounts = null;
|
||||
this.relayHealthMessage = null;
|
||||
this.relayHealthList = null;
|
||||
this.relayHealthStatus = null;
|
||||
this.relayHealthRefreshButton = null;
|
||||
@@ -1579,6 +1582,12 @@ export class ProfileModalController {
|
||||
document.getElementById("restoreRelaysBtn") || null;
|
||||
this.relayHealthPanel =
|
||||
document.getElementById("relayHealthPanel") || null;
|
||||
this.relayHealthSummary =
|
||||
document.getElementById("relayHealthSummary") || null;
|
||||
this.relayHealthCounts =
|
||||
document.getElementById("relayHealthCounts") || null;
|
||||
this.relayHealthMessage =
|
||||
document.getElementById("relayHealthMessage") || null;
|
||||
this.relayHealthList =
|
||||
document.getElementById("relayHealthList") || null;
|
||||
this.relayHealthStatus =
|
||||
@@ -7294,11 +7303,45 @@ export class ProfileModalController {
|
||||
this.relayHealthStatus.textContent = text;
|
||||
}
|
||||
|
||||
updateRelayHealthSummary(snapshot = []) {
|
||||
if (!this.relayHealthCounts || !this.relayHealthMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entries = Array.isArray(snapshot) ? snapshot : [];
|
||||
const total = entries.length;
|
||||
const healthy = entries.filter((entry) => entry.connected).length;
|
||||
const failed = Math.max(0, total - healthy);
|
||||
|
||||
this.relayHealthCounts.textContent = `${healthy} healthy • ${failed} failed`;
|
||||
|
||||
let message = "";
|
||||
if (!total) {
|
||||
message = "No relays configured.";
|
||||
} else if (failed > 0) {
|
||||
message =
|
||||
failed === total
|
||||
? "All relays are unreachable. Check your connection or update your relay list."
|
||||
: `${failed} relay${failed === 1 ? "" : "s"} unreachable. Playback and publishing may be delayed.`;
|
||||
} else {
|
||||
message = "All relays reachable.";
|
||||
}
|
||||
|
||||
this.relayHealthMessage.className = "mt-1 text-xs text-muted";
|
||||
if (failed > 0) {
|
||||
this.relayHealthMessage.classList.add("text-status-warning");
|
||||
} else if (total > 0) {
|
||||
this.relayHealthMessage.classList.add("text-status-success");
|
||||
}
|
||||
this.relayHealthMessage.textContent = message;
|
||||
}
|
||||
|
||||
renderRelayHealthSnapshot(snapshot = []) {
|
||||
if (!this.relayHealthList) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateRelayHealthSummary(snapshot);
|
||||
this.relayHealthList.innerHTML = "";
|
||||
|
||||
if (!snapshot.length) {
|
||||
|
||||
Reference in new issue
Block a user