Fixed the timeskew second display
This commit is contained in:
parent
8e157cc3ad
commit
2023e12658
@ -11,16 +11,14 @@ import { API_ENDPOINT } from "../api/endpoint";
|
||||
* Positive offset => client is AHEAD by that many ms.
|
||||
*/
|
||||
const TIME_URL_ENDPOINT = API_ENDPOINT.v1.TIME;
|
||||
|
||||
export function useTimeSkew(opts?: {
|
||||
endpoint?: string; // e.g., "/api/time" or `${import.meta.env.BASE_URL}api/time`
|
||||
intervalMs?: number; // how often to recheck; default 5 min
|
||||
samples?: number; // take N measurements and median; default 1
|
||||
enabled?: boolean; // allow turning off; default true
|
||||
intervalMs?: number;
|
||||
samples?: number;
|
||||
enabled?: boolean;
|
||||
}) {
|
||||
const {
|
||||
intervalMs = 5 * 60_000,
|
||||
samples = 1,
|
||||
samples = 3, // ✅ small median sampling
|
||||
enabled = true,
|
||||
} = opts || {};
|
||||
|
||||
@ -31,15 +29,24 @@ export function useTimeSkew(opts?: {
|
||||
|
||||
const measureOnce = async () => {
|
||||
const t0 = Date.now();
|
||||
const res = await fetch(TIME_URL_ENDPOINT, { cache: "no-store" });
|
||||
const res = await fetch(TIME_URL_ENDPOINT, {
|
||||
cache: "no-store",
|
||||
headers: { Accept: "application/json" },
|
||||
});
|
||||
const t1 = Date.now();
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const data = await res.json();
|
||||
|
||||
if (typeof data?.now !== "number") {
|
||||
// Robust parsing: number or string, seconds or ms
|
||||
const data = await res.json() as any;
|
||||
let serverMs = typeof data?.now === "number" ? data.now : Number(data?.now);
|
||||
if (!Number.isFinite(serverMs)) {
|
||||
throw new Error("Bad time payload (expecting { now: number })");
|
||||
}
|
||||
const serverMs = data.now;
|
||||
// Heuristic: if it's too small to be ms epoch, treat as seconds
|
||||
if (serverMs < 1e12) { // ~Sat Sep 09 2001 ms epoch
|
||||
serverMs = serverMs * 1000; // seconds -> ms
|
||||
}
|
||||
|
||||
const rtt = t1 - t0;
|
||||
const offset = Math.round(((t0 + t1) / 2) - serverMs);
|
||||
return { offset, rtt };
|
||||
@ -48,20 +55,14 @@ export function useTimeSkew(opts?: {
|
||||
const measure = async () => {
|
||||
try {
|
||||
setError(null);
|
||||
if (samples <= 1) {
|
||||
const { offset, rtt } = await measureOnce();
|
||||
setSkewMs(offset);
|
||||
setRttMs(rtt);
|
||||
return;
|
||||
}
|
||||
// multiple samples → median offset, min RTT (more stable)
|
||||
const offsets: number[] = [];
|
||||
const rtts: number[] = [];
|
||||
for (let i = 0; i < samples; i++) {
|
||||
const N = Math.max(1, samples);
|
||||
for (let i = 0; i < N; i++) {
|
||||
const { offset, rtt } = await measureOnce();
|
||||
offsets.push(offset);
|
||||
rtts.push(rtt);
|
||||
if (i < samples - 1) await new Promise(r => setTimeout(r, 120)); // tiny gap
|
||||
if (i + 1 < N) await new Promise(r => setTimeout(r, 120));
|
||||
}
|
||||
offsets.sort((a, b) => a - b);
|
||||
const median = offsets[Math.floor(offsets.length / 2)];
|
||||
@ -75,14 +76,11 @@ export function useTimeSkew(opts?: {
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled) return;
|
||||
measure(); // initial check
|
||||
measure(); // initial
|
||||
if (intervalMs > 0) {
|
||||
timerRef.current = window.setInterval(measure, intervalMs);
|
||||
}
|
||||
return () => {
|
||||
if (timerRef.current) window.clearInterval(timerRef.current);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
return () => { if (timerRef.current) window.clearInterval(timerRef.current); };
|
||||
}, [intervalMs, samples, enabled]);
|
||||
|
||||
return { skewMs, rttMs, error, recheck: measure };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user