mirror of
https://github.com/Corfirean/coa-server-manager.git
synced 2026-11-12 12:01:02 +00:00
PLAY turns into UPDATE CLIENT when a tracked client is outdated; with no client linked it offers choosing an existing folder or downloading from the community launcher servers (resumable, hash-verified, free-space checked, progress and stop). Files the player changed are kept on request or moved aside, never silently replaced. Existing clients can be adopted from Settings. Fresh downloads get a realmlist for each installed locale. Fixes zero-length files in the downloader (found by the live probe). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
52 lines
1.5 KiB
TypeScript
52 lines
1.5 KiB
TypeScript
import { useSyncExternalStore } from "react";
|
|
import { api, type ClientStatus } from "@/lib/api";
|
|
|
|
/**
|
|
* Game client status for the main screen: which client is linked and, for a client the Manager keeps up to date,
|
|
* whether a newer one has been published. Checked at start and every five minutes (one small request; no game file is read).
|
|
*/
|
|
interface State {
|
|
status: ClientStatus | null;
|
|
checking: boolean;
|
|
}
|
|
|
|
const EMPTY: State = { status: null, checking: false };
|
|
const states = new Map<string, State>();
|
|
const listeners = new Set<() => void>();
|
|
const CHECK_EVERY_MS = 5 * 60 * 1000;
|
|
|
|
const get = (id: string) => states.get(id) ?? EMPTY;
|
|
function set(id: string, next: Partial<State>) {
|
|
states.set(id, { ...get(id), ...next });
|
|
listeners.forEach((l) => l());
|
|
}
|
|
|
|
export async function checkClient(id: string): Promise<void> {
|
|
if (get(id).checking) return;
|
|
set(id, { checking: true });
|
|
try {
|
|
set(id, { status: await api.clientStatus(id) });
|
|
} catch {
|
|
// offline: keep what we knew
|
|
} finally {
|
|
set(id, { checking: false });
|
|
}
|
|
}
|
|
|
|
/** Check now and then every five minutes. Returns the function that stops it. */
|
|
export function startClientPolling(id: string): () => void {
|
|
void checkClient(id);
|
|
const t = setInterval(() => void checkClient(id), CHECK_EVERY_MS);
|
|
return () => clearInterval(t);
|
|
}
|
|
|
|
export function useClientStatus(id: string): State {
|
|
return useSyncExternalStore(
|
|
(l) => {
|
|
listeners.add(l);
|
|
return () => listeners.delete(l);
|
|
},
|
|
() => get(id),
|
|
);
|
|
}
|