This commit is contained in:
2025-12-28 05:37:19 +01:00
commit 87c722b5ae
74 changed files with 10264 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
import { Injectable, signal, computed } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class TimeSyncService {
// serverTime - clientTime offset (milliseconds)
private readonly _offset = signal<number>(0);
private _lastSyncAt = 0;
readonly offset = computed(() => this._offset());
// Returns a server-adjusted now() using the current offset
now(): number {
return Date.now() + this._offset();
}
// Set offset based on a serverTime observed at approximately receiveAt
setFromServerTime(serverTime: number, receiveAt?: number): void {
const observedAt = receiveAt ?? Date.now();
const offset = serverTime - observedAt;
this._offset.set(offset);
this._lastSyncAt = Date.now();
}
// Perform an HTTP-based sync using a simple NTP-style roundtrip
async syncWithEndpoint(baseApiUrl: string, timeoutMs = 5000): Promise<void> {
try {
const controller = new AbortController();
const t0 = Date.now();
const timer = setTimeout(() => controller.abort(), timeoutMs);
const resp = await fetch(`${baseApiUrl}/time`, { signal: controller.signal });
const t2 = Date.now();
clearTimeout(timer);
if (!resp.ok) return;
const data = await resp.json();
// Estimate one-way latency and offset
const serverNow = Number(data?.now) || Date.now();
const midpoint = (t0 + t2) / 2;
const offset = serverNow - midpoint;
this._offset.set(offset);
this._lastSyncAt = Date.now();
} catch {
// ignore sync failures; retain last offset
}
}
}