import { WebSocketMessage } from '../types'; export class WebSocketClient { private ws: WebSocket | null = null; private listeners: Map void>> = new Map(); private reconnectAttempts = 0; private maxReconnectAttempts = 5; private reconnectDelay = 3000; private getWebSocketUrl(): string { // Если задан VITE_WS_URL, используем его if (import.meta.env.VITE_WS_URL) { return import.meta.env.VITE_WS_URL; } // Иначе определяем автоматически на основе текущего location const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const host = window.location.host; return `${protocol}//${host}`; } connect() { if (this.ws?.readyState === WebSocket.OPEN) { return; } try { const wsUrl = this.getWebSocketUrl(); this.ws = new WebSocket(`${wsUrl}/ws/reviews`); this.ws.onopen = () => { console.log('WebSocket connected'); this.reconnectAttempts = 0; this.notifyListeners('connection', { status: 'connected' }); }; this.ws.onmessage = (event) => { try { const message: WebSocketMessage = JSON.parse(event.data); this.notifyListeners(message.type, message); } catch (error) { console.error('Failed to parse WebSocket message:', error); } }; this.ws.onerror = (error) => { console.error('WebSocket error:', error); this.notifyListeners('connection', { status: 'error', error }); }; this.ws.onclose = () => { console.log('WebSocket disconnected'); this.notifyListeners('connection', { status: 'disconnected' }); this.reconnect(); }; } catch (error) { console.error('Failed to create WebSocket:', error); this.reconnect(); } } disconnect() { if (this.ws) { this.ws.close(); this.ws = null; } } private reconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; console.log(`Reconnecting... Attempt ${this.reconnectAttempts}`); setTimeout(() => this.connect(), this.reconnectDelay); } } on(event: string, callback: (data: any) => void) { if (!this.listeners.has(event)) { this.listeners.set(event, new Set()); } this.listeners.get(event)!.add(callback); // Return unsubscribe function return () => { const callbacks = this.listeners.get(event); if (callbacks) { callbacks.delete(callback); } }; } private notifyListeners(event: string, data: any) { const callbacks = this.listeners.get(event); if (callbacks) { callbacks.forEach((callback) => callback(data)); } } send(message: any) { if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify(message)); } else { console.warn('WebSocket is not connected'); } } } // Create singleton instance export const wsClient = new WebSocketClient(); // Export helper to get WS URL export const getWebSocketUrl = (): string => { // Если задан VITE_WS_URL, используем его if (import.meta.env.VITE_WS_URL) { return import.meta.env.VITE_WS_URL; } // Иначе определяем автоматически на основе текущего location const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const host = window.location.host; return `${protocol}//${host}`; }; // Export WS_URL for direct usage export const WS_URL = `${getWebSocketUrl()}/ws/reviews`;