96 lines
3.3 KiB
TypeScript
96 lines
3.3 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useMemo, useRef } from 'react'
|
|
import { usePresenceStore } from '@/app/lib/usePresenceStore'
|
|
import { useTelemetryStore } from '@/app/lib/useTelemetryStore'
|
|
|
|
type Status = 'idle'|'connecting'|'open'|'closed'|'error'
|
|
|
|
function makeWsUrl(host?: string, port?: string, path?: string, scheme?: string) {
|
|
const h = (host ?? '').trim() || '127.0.0.1'
|
|
const p = (port ?? '').trim() || '8081'
|
|
const pa = (path ?? '').trim() || '/telemetry'
|
|
const sch = (scheme ?? '').toLowerCase()
|
|
const pageHttps = typeof window !== 'undefined' && window.location.protocol === 'https:'
|
|
const useWss = sch === 'wss' || (sch !== 'ws' && (p === '443' || pageHttps))
|
|
const proto = useWss ? 'wss' : 'ws'
|
|
const portPart = (p === '80' || p === '443') ? '' : `:${p}`
|
|
return `${proto}://${h}${portPart}${pa}`
|
|
}
|
|
|
|
export default function TelemetrySocket() {
|
|
const url = useMemo(
|
|
() => makeWsUrl(
|
|
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_HOST,
|
|
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_PORT,
|
|
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_PATH,
|
|
process.env.NEXT_PUBLIC_CS2_TELEMETRY_WS_SCHEME
|
|
),
|
|
[]
|
|
)
|
|
|
|
const setSnapshot = usePresenceStore(s => s.setSnapshot)
|
|
const setJoin = usePresenceStore(s => s.setJoin)
|
|
const setLeave = usePresenceStore(s => s.setLeave)
|
|
|
|
const setMapKey = useTelemetryStore(s => s.setMapKey)
|
|
|
|
// interne Refs für saubere Handler
|
|
const aliveRef = useRef(true)
|
|
const retryRef = useRef<number | null>(null)
|
|
const wsRef = useRef<WebSocket | null>(null)
|
|
|
|
useEffect(() => {
|
|
aliveRef.current = true
|
|
|
|
const connect = () => {
|
|
if (!aliveRef.current || !url) return
|
|
const ws = new WebSocket(url)
|
|
wsRef.current = ws
|
|
|
|
ws.onopen = () => {
|
|
if (process.env.NODE_ENV !== 'production') console.debug('[TelemetrySocket] open')
|
|
}
|
|
ws.onerror = () => {
|
|
if (process.env.NODE_ENV !== 'production') console.debug('[TelemetrySocket] error')
|
|
}
|
|
ws.onclose = () => {
|
|
if (process.env.NODE_ENV !== 'production') console.debug('[TelemetrySocket] closed')
|
|
if (aliveRef.current) retryRef.current = window.setTimeout(connect, 2000)
|
|
}
|
|
|
|
ws.onmessage = (ev) => {
|
|
let msg: any = null
|
|
try { msg = JSON.parse(String(ev.data ?? '')) } catch {}
|
|
if (!msg) return
|
|
|
|
if (msg.type === 'players' && Array.isArray(msg.players)) {
|
|
// kompletter Presence-Snapshot
|
|
setSnapshot(msg.players)
|
|
} else if (msg.type === 'player_join' && msg.player) {
|
|
setJoin(msg.player)
|
|
} else if (msg.type === 'player_leave') {
|
|
const sid = msg.steamId ?? msg.steam_id ?? msg.id
|
|
if (sid != null) setLeave(sid)
|
|
}
|
|
|
|
// ⬇️ Map-Event aus /telemetry
|
|
if (msg.type === 'map' && typeof msg.name === 'string') {
|
|
const key = msg.name.toLowerCase()
|
|
if (process.env.NODE_ENV!=='production') console.debug('[TelemetrySocket] map:', key)
|
|
setMapKey(key)
|
|
}
|
|
}
|
|
}
|
|
|
|
connect()
|
|
return () => {
|
|
aliveRef.current = false
|
|
if (retryRef.current) window.clearTimeout(retryRef.current)
|
|
try { wsRef.current?.close(1000, 'telemetry socket unmounted') } catch {}
|
|
}
|
|
}, [url, setSnapshot, setJoin, setLeave])
|
|
|
|
return null
|
|
}
|