import { createInitialState, punteggio, servizio, setVinti } from './gameState.js' export function createWsMixin(role) { return { data() { return { ws: null, wsConnected: false, isConnecting: false, reconnectTimeout: null, reconnectAttempts: 0, maxReconnectDelay: 30000, state: createInitialState(), } }, computed: { punt() { return punteggio(this.state.sp.striscia) }, servHome() { return servizio(this.state.sp.striscia) }, set() { return setVinti(this.state.sp.striscia) }, }, mounted() { this.connectWebSocket() if (import.meta.hot) { import.meta.hot.on('vite:beforeUpdate', () => { if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout) this.reconnectTimeout = null } }) } }, beforeUnmount() { if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout) this.reconnectTimeout = null } if (this.ws) { this.ws.onclose = null this.ws.onerror = null this.ws.onmessage = null this.ws.onopen = null try { if (this.ws.readyState === WebSocket.OPEN) { this.ws.close(1000, 'Component unmounting') } else if (this.ws.readyState === WebSocket.CONNECTING) { this.ws.close() } } catch (err) { console.error(`[${role}] Error closing WebSocket:`, err) } this.ws = null } }, methods: { connectWebSocket() { if (this.isConnecting) return if (this.ws) { this.ws.onclose = null this.ws.onerror = null this.ws.onmessage = null this.ws.onopen = null try { if (this.ws.readyState === WebSocket.OPEN) { this.ws.close(1000, 'Reconnecting') } else if (this.ws.readyState === WebSocket.CONNECTING) { this.ws.close() } } catch (err) { console.error(`[${role}] Error closing previous WebSocket:`, err) } this.ws = null } this.isConnecting = true const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:' const params = new URLSearchParams(location.search) const defaultHost = (location.hostname === 'localhost' || location.hostname === '::1') ? `127.0.0.1${location.port ? `:${location.port}` : ''}` : location.host const wsUrl = `${protocol}//${params.get('wsHost') || defaultHost}/ws` try { this.ws = new WebSocket(wsUrl) } catch (err) { console.error(`[${role}] Failed to create WebSocket:`, err) this.isConnecting = false this.scheduleReconnect() return } this.ws.onopen = () => { this.isConnecting = false this.wsConnected = true this.reconnectAttempts = 0 try { this.ws?.send(JSON.stringify({ type: 'register', role })) } catch (err) { console.error(`[${role}] Failed to register:`, err) } } this.ws.onmessage = (event) => { try { const msg = JSON.parse(event.data) if (msg.type === 'state') this.state = msg.state else this.onWsMessage?.(msg) } catch (e) { console.error(`[${role}] Error parsing message:`, e) } } this.ws.onclose = (event) => { this.isConnecting = false this.wsConnected = false if (event.code !== 1000 && event.code !== 1001) this.scheduleReconnect() } this.ws.onerror = () => { this.isConnecting = false this.wsConnected = false } }, scheduleReconnect() { if (this.reconnectTimeout) return const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), this.maxReconnectDelay) this.reconnectAttempts++ this.reconnectTimeout = setTimeout(() => { this.reconnectTimeout = null this.connectWebSocket() }, delay) }, sendWs(msg) { if (!this.wsConnected || this.ws?.readyState !== WebSocket.OPEN) return false try { this.ws.send(JSON.stringify(msg)) return true } catch (err) { console.error(`[${role}] Failed to send:`, err) return false } }, }, } }