diff options
| author | Arseney300 <Arseney300@gmail.com> | 2026-03-05 09:47:09 +0700 |
|---|---|---|
| committer | Arseney300 <Arseney300@gmail.com> | 2026-03-05 09:47:09 +0700 |
| commit | 0885d20ac18c252f6735cd288448d5d93e95b80f (patch) | |
| tree | edfb6814e97d4000605d9f6a918c30c6aca9e10c /admin-panel/src/client/lib/ws.ts | |
| parent | 22749b796d7a5e4efa9494156a3fdcfe39028da7 (diff) | |
WIP: admin_panel: add featurefeature/admin_panel
Diffstat (limited to 'admin-panel/src/client/lib/ws.ts')
| -rw-r--r-- | admin-panel/src/client/lib/ws.ts | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/admin-panel/src/client/lib/ws.ts b/admin-panel/src/client/lib/ws.ts new file mode 100644 index 0000000..14e0cec --- /dev/null +++ b/admin-panel/src/client/lib/ws.ts @@ -0,0 +1,79 @@ +type EventHandler = (data: unknown) => void; + +class WsClient { + private ws: WebSocket | null = null; + private handlers = new Map<string, Set<EventHandler>>(); + private reconnectTimer: ReturnType<typeof setTimeout> | null = null; + private subscribedProjects = new Set<string>(); + + connect(): void { + if (this.ws?.readyState === WebSocket.OPEN) return; + + const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; + this.ws = new WebSocket(`${protocol}//${location.host}/ws`); + + this.ws.onopen = () => { + // Re-subscribe to projects + for (const project of this.subscribedProjects) { + this.send({ type: 'subscribe', project }); + } + }; + + this.ws.onmessage = (event) => { + try { + const data = JSON.parse(event.data); + const handlers = this.handlers.get(data.type); + if (handlers) { + for (const handler of handlers) { + handler(data); + } + } + // Also fire wildcard handlers + const wildcardHandlers = this.handlers.get('*'); + if (wildcardHandlers) { + for (const handler of wildcardHandlers) { + handler(data); + } + } + } catch { + // ignore + } + }; + + this.ws.onclose = () => { + this.reconnectTimer = setTimeout(() => this.connect(), 3000); + }; + } + + disconnect(): void { + if (this.reconnectTimer) clearTimeout(this.reconnectTimer); + this.ws?.close(); + this.ws = null; + } + + subscribe(project: string): void { + this.subscribedProjects.add(project); + this.send({ type: 'subscribe', project }); + } + + unsubscribe(project: string): void { + this.subscribedProjects.delete(project); + this.send({ type: 'unsubscribe', project }); + } + + on(event: string, handler: EventHandler): () => void { + if (!this.handlers.has(event)) { + this.handlers.set(event, new Set()); + } + this.handlers.get(event)!.add(handler); + return () => this.handlers.get(event)?.delete(handler); + } + + private send(data: unknown): void { + if (this.ws?.readyState === WebSocket.OPEN) { + this.ws.send(JSON.stringify(data)); + } + } +} + +export const wsClient = new WsClient(); |
