mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
104 lines
2.6 KiB
TypeScript
104 lines
2.6 KiB
TypeScript
|
import {
|
||
|
createContext,
|
||
|
useContext,
|
||
|
useEffect,
|
||
|
useState,
|
||
|
FC,
|
||
|
useCallback,
|
||
|
useMemo,
|
||
|
} from 'react'
|
||
|
import { ConnectionState } from '../connection/types/connection-state'
|
||
|
import { ConnectionManager } from '@/features/ide-react/connection/connection-manager'
|
||
|
import { Socket } from '@/features/ide-react/connection/types/socket'
|
||
|
import { secondsUntil } from '@/features/ide-react/connection/utils'
|
||
|
|
||
|
type ConnectionContextValue = {
|
||
|
socket: Socket
|
||
|
connectionState: ConnectionState
|
||
|
isConnected: boolean
|
||
|
isStillReconnecting: boolean
|
||
|
secondsUntilReconnect: () => number
|
||
|
tryReconnectNow: () => void
|
||
|
registerUserActivity: () => void
|
||
|
}
|
||
|
|
||
|
const ConnectionContext = createContext<ConnectionContextValue | null>(null)
|
||
|
|
||
|
export const ConnectionProvider: FC = ({ children }) => {
|
||
|
const [connectionManager] = useState(() => new ConnectionManager())
|
||
|
const [connectionState, setConnectionState] = useState(
|
||
|
connectionManager.state
|
||
|
)
|
||
|
|
||
|
useEffect(() => {
|
||
|
function handleStateChange(event: { state: ConnectionState }) {
|
||
|
setConnectionState(event.state)
|
||
|
}
|
||
|
connectionManager.on('statechange', handleStateChange)
|
||
|
|
||
|
return () => {
|
||
|
connectionManager.off('statechange', handleStateChange)
|
||
|
}
|
||
|
}, [connectionManager])
|
||
|
|
||
|
const isConnected = connectionState.readyState === WebSocket.OPEN
|
||
|
|
||
|
const isStillReconnecting =
|
||
|
connectionState.readyState === WebSocket.CONNECTING &&
|
||
|
performance.now() - connectionState.lastConnectionAttempt > 1000
|
||
|
|
||
|
const secondsUntilReconnect = useCallback(
|
||
|
() => secondsUntil(connectionState.reconnectAt),
|
||
|
[connectionState.reconnectAt]
|
||
|
)
|
||
|
|
||
|
const tryReconnectNow = useCallback(
|
||
|
() => connectionManager.tryReconnectNow(),
|
||
|
[connectionManager]
|
||
|
)
|
||
|
|
||
|
const registerUserActivity = useCallback(
|
||
|
() => connectionManager.registerUserActivity(),
|
||
|
[connectionManager]
|
||
|
)
|
||
|
|
||
|
const value = useMemo<ConnectionContextValue>(
|
||
|
() => ({
|
||
|
socket: connectionManager.socket,
|
||
|
connectionState,
|
||
|
isConnected,
|
||
|
isStillReconnecting,
|
||
|
secondsUntilReconnect,
|
||
|
tryReconnectNow,
|
||
|
registerUserActivity,
|
||
|
}),
|
||
|
[
|
||
|
connectionManager.socket,
|
||
|
connectionState,
|
||
|
isConnected,
|
||
|
isStillReconnecting,
|
||
|
registerUserActivity,
|
||
|
secondsUntilReconnect,
|
||
|
tryReconnectNow,
|
||
|
]
|
||
|
)
|
||
|
|
||
|
return (
|
||
|
<ConnectionContext.Provider value={value}>
|
||
|
{children}
|
||
|
</ConnectionContext.Provider>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
export function useConnectionContext(): ConnectionContextValue {
|
||
|
const context = useContext(ConnectionContext)
|
||
|
|
||
|
if (!context) {
|
||
|
throw new Error(
|
||
|
'useConnectionContext is only available inside ConnectionProvider'
|
||
|
)
|
||
|
}
|
||
|
|
||
|
return context
|
||
|
}
|