// --- AUTO-GENERATED --- // Generated by generator. Do not edit by hand (unless you know what you do). // Types export interface ReceiveValue { Field: string[]; Second: number; Uhhhh?: any; } export interface ReturnValue { Field: string[]; Second: number; Uhhhh?: any; } // Generic RPC method result export type RPCResult = { data: T; error?: any }; export interface RPCClient { ComplexThings(arg0: string[]): Promise>; EmptyParams(): Promise>; ManyParams(arg0: number, arg1: number, arg2: number, arg3: number, arg4: number, arg5: number, arg6: number, arg7: number, arg8: number): Promise>; Structs(receiveValue: ReceiveValue): Promise>; } export class WSBackend { private ws: WebSocket | null = null; private tokenProvider?: () => string; private url: string; private callbacks: Record void; timeout: ReturnType; }> = {}; private counter = 0; private _api: any = null; private queue: Array<{ id: string; method: string; params: any[]; resolve: Function; reject: Function }> = []; private reconnectDelay = 1000; private _connected = false; private connectedListeners: Array<() => void> = []; private disconnectedListeners: Array<() => void> = []; private callTimeout = 10000; // 10 second timeout for calls constructor(url: string) { this.url = url; this._api = new Proxy({}, { get: (_t, method: string) => (...args: any[]) => this.call(method, args) }); this.connect(); } public setTokenProvider(fn: () => string) { this.tokenProvider = fn; } public get api() { return this._api; } public get connected() { return this._connected; } public onConnected(cb: () => void) { this.connectedListeners.push(cb); } public onDisconnected(cb: () => void) { this.disconnectedListeners.push(cb); } public setCallTimeout(ms: number) { this.callTimeout = ms; } private connect() { this.ws = new WebSocket(this.url); this.ws.onopen = () => { console.log("[WS] Connected to", this.url); this._connected = true; this.connectedListeners.forEach(cb => cb()); this.queue.forEach(item => { this._send(item.id, item.method, item.params); }); this.queue = []; }; this.ws.onmessage = (evt) => { let msg: any; try { msg = JSON.parse(evt.data); } catch { return; } const callbackData = this.callbacks[msg.id]; if (!callbackData) return; clearTimeout(callbackData.timeout); if (msg.result && typeof msg.result === "object" && ("data" in msg.result || "error" in msg.result)) { const r = msg.result; callbackData.callback(r.error, r.data); } else { callbackData.callback(msg.error, msg.result); } delete this.callbacks[msg.id]; }; this.ws.onclose = () => { const wasConnected = this._connected; this._connected = false; Object.keys(this.callbacks).forEach(id => { const callbackData = this.callbacks[id]; clearTimeout(callbackData.timeout); callbackData.callback({ message: 'WebSocket disconnected' }, null); delete this.callbacks[id]; }); if (wasConnected) { this.disconnectedListeners.forEach(cb => cb()); } console.log("[WS] Disconnected. Reconnecting..."); setTimeout(() => this.connect(), this.reconnectDelay); }; this.ws.onerror = (e) => { console.warn("[WS] Error:", e); this.ws?.close(); }; } private call(method: string, params: any[]): Promise { const id = (++this.counter).toString(); return new Promise((resolve) => { const timeout = setTimeout(() => { if (this.callbacks[id]) { console.warn(`[WS] Call timeout for \${method} (id: \${id})`); this.callbacks[id].callback({ message: 'Request timeout' }, null); delete this.callbacks[id]; } }, this.callTimeout); this.callbacks[id] = { callback: (err, res) => { resolve({ data: res, error: err }); }, timeout }; if (this._connected && this.ws && this.ws.readyState === WebSocket.OPEN) { this._send(id, method, params); } else { console.log("[WS] Queueing call", method, id, params); this.queue.push({ id, method, params, resolve, reject: () => { } }); } }); } private _send(id: string, method: string, params: any[]) { if (!this.ws) throw new Error("WebSocket not initialized"); const msg: any = { id, method, params }; if (this.tokenProvider) msg.token = this.tokenProvider(); this.ws.send(JSON.stringify(msg)); } } let backendWrapper: WSBackend | null = null; let backendInstance: RPCClient | null = null; export function useBackend(url: string = '/ws'): { api: RPCClient, backend: WSBackend } { if (url.startsWith('/')) { const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; const host = window.location.host; url = `${protocol}://${host}${url}`; } if (!backendWrapper) { backendWrapper = new WSBackend(url); backendInstance = backendWrapper.api as unknown as RPCClient; } return { api: backendInstance!, backend: backendWrapper! }; }