feat(web): add chat UI with WebSocket streaming and conversation persistence
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
55
web/client/src/lib/websocket.ts
Normal file
55
web/client/src/lib/websocket.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
type MessageHandler = (data: Record<string, unknown>) => void;
|
||||
|
||||
class ChatSocket {
|
||||
private ws: WebSocket | null = null;
|
||||
private handlers: Map<string, MessageHandler[]> = new Map();
|
||||
private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
connect() {
|
||||
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const url = `${protocol}//${location.host}/ws`;
|
||||
this.ws = new WebSocket(url);
|
||||
|
||||
this.ws.onopen = () => {
|
||||
this.emit('connected', {});
|
||||
};
|
||||
|
||||
this.ws.onmessage = (event) => {
|
||||
try {
|
||||
const { type, data } = JSON.parse(event.data);
|
||||
this.emit(type, data);
|
||||
} catch {}
|
||||
};
|
||||
|
||||
this.ws.onclose = () => {
|
||||
this.reconnectTimer = setTimeout(() => this.connect(), 3000);
|
||||
};
|
||||
}
|
||||
|
||||
on(type: string, handler: MessageHandler) {
|
||||
if (!this.handlers.has(type)) this.handlers.set(type, []);
|
||||
this.handlers.get(type)!.push(handler);
|
||||
}
|
||||
|
||||
off(type: string, handler: MessageHandler) {
|
||||
const list = this.handlers.get(type);
|
||||
if (list) this.handlers.set(type, list.filter((h) => h !== handler));
|
||||
}
|
||||
|
||||
send(type: string, data: Record<string, unknown> = {}) {
|
||||
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(JSON.stringify({ type, ...data }));
|
||||
}
|
||||
}
|
||||
|
||||
private emit(type: string, data: Record<string, unknown>) {
|
||||
(this.handlers.get(type) || []).forEach((h) => h(data));
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
|
||||
this.ws?.close();
|
||||
}
|
||||
}
|
||||
|
||||
export const chatSocket = new ChatSocket();
|
||||
Reference in New Issue
Block a user