| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- import { useState, useEffect, useCallback } from 'react'
- import SocketIoShim from '@/ide/connection/SocketIoShim'
- import type { Socket } from '@/features/ide-react/connection/types/socket'
- import type { DebugInfo, SocketState } from './types'
- export function useSocketManager() {
- const [socket, setSocket] = useState<Socket | null>(null)
- const [autoping, setAutoping] = useState<boolean>(false)
- const [socketState, setSocketState] = useState<SocketState>({
- connected: false,
- connecting: false,
- lastError: '',
- })
- const [debugInfo, setDebugInfo] = useState<DebugInfo>({
- sent: 0,
- received: 0,
- latency: null,
- maxLatency: null,
- onLine: null,
- clockDelta: null,
- client: null,
- unansweredSince: null,
- lastReceived: null,
- })
- const connectSocket = useCallback(() => {
- const parsedURL = new URL('/socket.io', window.origin)
- setSocketState(prev => ({
- ...prev,
- connecting: true,
- lastAttempt: Date.now(),
- }))
- const newSocket = SocketIoShim.connect(parsedURL.origin, {
- resource: parsedURL.pathname.slice(1),
- 'auto connect': false,
- 'connect timeout': 30 * 1000,
- 'force new connection': true,
- query: new URLSearchParams({ debugging: 'true' }).toString(),
- reconnect: false,
- }) as unknown as Socket
- setSocket(newSocket)
- return newSocket
- }, [])
- const disconnectSocket = useCallback(() => {
- socket?.disconnect()
- setSocket(null)
- setSocketState(prev => ({
- ...prev,
- connected: false,
- connecting: false,
- lastError: 'Manually disconnected',
- }))
- }, [socket])
- const forceReconnect = useCallback(() => {
- disconnectSocket()
- setTimeout(connectSocket, 1000)
- }, [disconnectSocket, connectSocket])
- useEffect(() => {
- connectSocket()
- }, [connectSocket])
- const sendPing = useCallback(() => {
- if (socket?.socket.connected) {
- const time = Date.now()
- setDebugInfo(prev => ({
- ...prev,
- sent: prev.sent + 1,
- unansweredSince: prev.unansweredSince ?? time,
- }))
- socket.emit('debug', { time }, (info: any) => {
- const beforeTime = info.data.time
- const now = Date.now()
- const latency = now - beforeTime
- const clockDelta = (beforeTime + now) / 2 - info.serverTime
- setDebugInfo(prev => ({
- ...prev,
- received: prev.received + 1,
- latency,
- maxLatency: Math.max(prev.maxLatency ?? 0, latency),
- clockDelta,
- client: info.client,
- lastReceived: now,
- unansweredSince: null,
- }))
- })
- }
- }, [socket])
- useEffect(() => {
- if (!socket || !autoping) return
- const statsInterval = setInterval(sendPing, 2000)
- return () => {
- clearInterval(statsInterval)
- }
- }, [socket, autoping, sendPing])
- useEffect(() => {
- if (!socket) return
- socket.on('connect', () => {
- setSocketState(prev => ({
- ...prev,
- connected: true,
- connecting: false,
- lastSuccess: Date.now(),
- lastError: '',
- }))
- sendPing()
- })
- socket.on('disconnect', (reason: string) => {
- setSocketState(prev => ({
- ...prev,
- connected: false,
- connecting: false,
- lastError: `Disconnected: ${reason}`,
- }))
- })
- socket.on('connect_error', (error: Error) => {
- setSocketState(prev => ({
- ...prev,
- connecting: false,
- lastError: `Connection error: ${error?.message || 'Unknown'}`,
- }))
- })
- socket.socket.connect()
- return () => {
- socket.disconnect()
- }
- }, [sendPing, socket])
- useEffect(() => {
- const updateNetworkInfo = () => {
- setDebugInfo(prev => ({ ...prev, onLine: navigator.onLine }))
- }
- window.addEventListener('online', updateNetworkInfo)
- window.addEventListener('offline', updateNetworkInfo)
- updateNetworkInfo()
- return () => {
- window.removeEventListener('online', updateNetworkInfo)
- window.removeEventListener('offline', updateNetworkInfo)
- }
- }, [])
- return {
- socketState,
- debugInfo,
- connectSocket,
- disconnectSocket,
- forceReconnect,
- socket,
- autoping,
- setAutoping,
- }
- }
|