diff options
| author | soryu <soryu@soryu.co> | 2025-11-15 18:00:09 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2025-11-15 18:00:09 +0000 |
| commit | 3e7b2beca1136a42700a7e1aebfe4c0fb2861a00 (patch) | |
| tree | 6c896c31820681e360e50a73839fc2284c043dea /frontend/src/services/ws.ts | |
| download | soryu-3e7b2beca1136a42700a7e1aebfe4c0fb2861a00.tar.gz soryu-3e7b2beca1136a42700a7e1aebfe4c0fb2861a00.zip | |
Initial commit
Diffstat (limited to 'frontend/src/services/ws.ts')
| -rw-r--r-- | frontend/src/services/ws.ts | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/frontend/src/services/ws.ts b/frontend/src/services/ws.ts new file mode 100644 index 0000000..7d10512 --- /dev/null +++ b/frontend/src/services/ws.ts @@ -0,0 +1,69 @@ +// Minimal WS client with auto-reconnect for Rust backend interoperability. +// Point URL to your Rust server: ws://localhost:8080/ws (example) + +type Listener = (data: any) => void + +export class VNWebSocket { + private url: string + private ws: WebSocket | null = null + private reconnectDelay = 1000 + private maxReconnectDelay = 8000 + private shouldReconnect = true + private listeners: Record<string, Listener[]> = {} + + constructor(url: string) { + this.url = url + } + + on(event: 'open' | 'close' | 'error' | 'message', cb: Listener) { + if (!this.listeners[event]) this.listeners[event] = [] + this.listeners[event].push(cb) + } + + private emit(event: string, data?: any) { + ;(this.listeners[event] || []).forEach(cb => cb(data)) + } + + connect() { + this.ws = new WebSocket(this.url) + + this.ws.addEventListener('open', () => { + this.emit('open') + this.reconnectDelay = 1000 + }) + + this.ws.addEventListener('message', (evt) => { + try { + const parsed = JSON.parse(evt.data) + this.emit('message', parsed) + } catch { + this.emit('message', evt.data) + } + }) + + this.ws.addEventListener('close', () => { + this.emit('close') + if (this.shouldReconnect) { + setTimeout(() => this.connect(), this.reconnectDelay) + this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay) + } + }) + + this.ws.addEventListener('error', (e) => { + this.emit('error', e) + this.ws?.close() + }) + } + + send(data: any) { + const payload = typeof data === 'string' ? data : JSON.stringify(data) + if (this.ws && this.ws.readyState === WebSocket.OPEN) { + this.ws.send(payload) + } + } + + close() { + this.shouldReconnect = false + this.ws?.close() + } +} |
