refactor: deriva punt/set/servHome dalla striscia, estrai mixin WebSocket
La striscia è ora l'unica source of truth: punt, set vinti e servizio vengono calcolati via helper puri (punteggio/servizio/setVinti) invece di essere mantenuti come campi ridondanti nello stato. Il boilerplate WebSocket (~150 righe identiche in entrambi i componenti) è estratto in src/wsMixin.js con createWsMixin(role); i componenti diventano solo logica specifica del loro ruolo.
This commit is contained in:
+146
@@ -0,0 +1,146 @@
|
||||
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
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user