mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-21 05:10:41 +00:00
feat: improve offline PWA resilience
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
export type NetworkStatus = 'online' | 'offline';
|
||||
|
||||
const STATUS_PROBE_TIMEOUT_MS = 3500;
|
||||
const STATUS_PROBE_CACHE_MS = 5000;
|
||||
const listeners = new Set<(status: NetworkStatus) => void>();
|
||||
let currentStatus: NetworkStatus = getInitialNetworkStatus();
|
||||
let pendingProbe: Promise<boolean> | null = null;
|
||||
let lastProbeAt = 0;
|
||||
let lastProbeResult = false;
|
||||
|
||||
export function browserReportsOffline(): boolean {
|
||||
return typeof navigator !== 'undefined' && navigator.onLine === false;
|
||||
}
|
||||
|
||||
export function getInitialNetworkStatus(): NetworkStatus {
|
||||
return 'offline';
|
||||
}
|
||||
|
||||
export function getCurrentNetworkStatus(): NetworkStatus {
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
export function setCurrentNetworkStatus(status: NetworkStatus): void {
|
||||
if (currentStatus === status) return;
|
||||
currentStatus = status;
|
||||
for (const listener of Array.from(listeners)) {
|
||||
listener(status);
|
||||
}
|
||||
}
|
||||
|
||||
export function subscribeNetworkStatus(listener: (status: NetworkStatus) => void): () => void {
|
||||
listeners.add(listener);
|
||||
return () => {
|
||||
listeners.delete(listener);
|
||||
};
|
||||
}
|
||||
|
||||
export async function probeNodeWardenService(): Promise<boolean> {
|
||||
if (browserReportsOffline()) {
|
||||
setCurrentNetworkStatus('offline');
|
||||
return false;
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
if (pendingProbe) return pendingProbe;
|
||||
if (now - lastProbeAt < STATUS_PROBE_CACHE_MS) return lastProbeResult;
|
||||
|
||||
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
||||
const timer = controller
|
||||
? window.setTimeout(() => controller.abort(), STATUS_PROBE_TIMEOUT_MS)
|
||||
: 0;
|
||||
|
||||
pendingProbe = (async () => {
|
||||
const response = await fetch(`/api/web-bootstrap?statusProbe=${Date.now()}`, {
|
||||
method: 'GET',
|
||||
cache: 'no-store',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
Pragma: 'no-cache',
|
||||
},
|
||||
signal: controller?.signal,
|
||||
});
|
||||
return response.ok;
|
||||
})()
|
||||
.catch(() => false)
|
||||
.then((result) => {
|
||||
lastProbeAt = Date.now();
|
||||
lastProbeResult = result;
|
||||
setCurrentNetworkStatus(result ? 'online' : 'offline');
|
||||
return result;
|
||||
})
|
||||
.finally(() => {
|
||||
if (timer) window.clearTimeout(timer);
|
||||
pendingProbe = null;
|
||||
});
|
||||
|
||||
return pendingProbe;
|
||||
}
|
||||
Reference in New Issue
Block a user