connection-context.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import {
  2. createContext,
  3. useContext,
  4. useEffect,
  5. useState,
  6. FC,
  7. useCallback,
  8. useMemo,
  9. } from 'react'
  10. import { ConnectionState } from '../connection/types/connection-state'
  11. import { ConnectionManager } from '@/features/ide-react/connection/connection-manager'
  12. import { Socket } from '@/features/ide-react/connection/types/socket'
  13. import { secondsUntil } from '@/features/ide-react/connection/utils'
  14. type ConnectionContextValue = {
  15. socket: Socket
  16. connectionState: ConnectionState
  17. isConnected: boolean
  18. isStillReconnecting: boolean
  19. secondsUntilReconnect: () => number
  20. tryReconnectNow: () => void
  21. registerUserActivity: () => void
  22. }
  23. const ConnectionContext = createContext<ConnectionContextValue | null>(null)
  24. export const ConnectionProvider: FC = ({ children }) => {
  25. const [connectionManager] = useState(() => new ConnectionManager())
  26. const [connectionState, setConnectionState] = useState(
  27. connectionManager.state
  28. )
  29. useEffect(() => {
  30. function handleStateChange(event: { state: ConnectionState }) {
  31. setConnectionState(event.state)
  32. }
  33. connectionManager.on('statechange', handleStateChange)
  34. return () => {
  35. connectionManager.off('statechange', handleStateChange)
  36. }
  37. }, [connectionManager])
  38. const isConnected = connectionState.readyState === WebSocket.OPEN
  39. const isStillReconnecting =
  40. connectionState.readyState === WebSocket.CONNECTING &&
  41. performance.now() - connectionState.lastConnectionAttempt > 1000
  42. const secondsUntilReconnect = useCallback(
  43. () => secondsUntil(connectionState.reconnectAt),
  44. [connectionState.reconnectAt]
  45. )
  46. const tryReconnectNow = useCallback(
  47. () => connectionManager.tryReconnectNow(),
  48. [connectionManager]
  49. )
  50. const registerUserActivity = useCallback(
  51. () => connectionManager.registerUserActivity(),
  52. [connectionManager]
  53. )
  54. const value = useMemo<ConnectionContextValue>(
  55. () => ({
  56. socket: connectionManager.socket,
  57. connectionState,
  58. isConnected,
  59. isStillReconnecting,
  60. secondsUntilReconnect,
  61. tryReconnectNow,
  62. registerUserActivity,
  63. }),
  64. [
  65. connectionManager.socket,
  66. connectionState,
  67. isConnected,
  68. isStillReconnecting,
  69. registerUserActivity,
  70. secondsUntilReconnect,
  71. tryReconnectNow,
  72. ]
  73. )
  74. return (
  75. <ConnectionContext.Provider value={value}>
  76. {children}
  77. </ConnectionContext.Provider>
  78. )
  79. }
  80. export function useConnectionContext(): ConnectionContextValue {
  81. const context = useContext(ConnectionContext)
  82. if (!context) {
  83. throw new Error(
  84. 'useConnectionContext is only available inside ConnectionProvider'
  85. )
  86. }
  87. return context
  88. }