Files
openchamber/packages/ui/src/lib/desktopHosts.ts
T

111 lines
3.0 KiB
TypeScript
Raw Normal View History

import { isTauriShell } from '@/lib/desktop';
type TauriInvoke = (cmd: string, args?: Record<string, unknown>) => Promise<unknown>;
type TauriGlobal = {
core?: {
invoke?: TauriInvoke;
};
};
export type DesktopHost = {
id: string;
label: string;
url: string;
};
export type DesktopHostsConfig = {
hosts: DesktopHost[];
defaultHostId: string | null;
};
export type HostProbeResult = {
status: 'ok' | 'auth' | 'unreachable';
latencyMs: number;
};
const isRecord = (value: unknown): value is Record<string, unknown> => {
return typeof value === 'object' && value !== null;
};
const readString = (obj: Record<string, unknown>, key: string): string | null => {
const val = obj[key];
return typeof val === 'string' ? val : null;
};
const readNumber = (obj: Record<string, unknown>, key: string): number | null => {
const val = obj[key];
return typeof val === 'number' && Number.isFinite(val) ? val : null;
};
const parseHost = (value: unknown): DesktopHost | null => {
if (!isRecord(value)) return null;
const id = readString(value, 'id');
const label = readString(value, 'label');
const url = readString(value, 'url');
if (!id || !label || !url) return null;
return { id, label, url };
};
const getInvoke = (): TauriInvoke | null => {
if (!isTauriShell()) return null;
const tauri = (window as unknown as { __TAURI__?: TauriGlobal }).__TAURI__;
return typeof tauri?.core?.invoke === 'function' ? tauri.core.invoke : null;
};
export const desktopHostsGet = async (): Promise<DesktopHostsConfig> => {
const invoke = getInvoke();
if (!invoke) {
return { hosts: [], defaultHostId: 'local' };
}
const raw = await invoke('desktop_hosts_get');
if (!isRecord(raw)) {
return { hosts: [], defaultHostId: null };
}
const hostsRaw = raw.hosts;
const hosts = Array.isArray(hostsRaw)
? hostsRaw.map(parseHost).filter((h): h is DesktopHost => Boolean(h))
: [];
const defaultHostId =
readString(raw, 'defaultHostId') ||
readString(raw, 'default_host_id') ||
readString(raw, 'defaultHostID');
return { hosts, defaultHostId };
};
export const desktopHostsSet = async (config: DesktopHostsConfig): Promise<void> => {
const invoke = getInvoke();
if (!invoke) return;
await invoke('desktop_hosts_set', {
config: {
hosts: config.hosts,
defaultHostId: config.defaultHostId,
},
});
};
export const desktopHostProbe = async (url: string): Promise<HostProbeResult> => {
const invoke = getInvoke();
if (!invoke) {
return { status: 'unreachable', latencyMs: 0 };
}
const raw = await invoke('desktop_host_probe', { url });
if (!isRecord(raw)) {
return { status: 'unreachable', latencyMs: 0 };
}
const rawStatus = raw.status;
const status: HostProbeResult['status'] =
rawStatus === 'ok' || rawStatus === 'auth' || rawStatus === 'unreachable'
? rawStatus
: 'unreachable';
const latencyMs = readNumber(raw, 'latencyMs') ?? readNumber(raw, 'latency_ms') ?? 0;
return { status, latencyMs };
};