socket.ts 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import { useCallback, useEffect, useRef, useState } from 'react';
  2. import { useStorageState } from 'react-storage-hooks';
  3. import { socketKeepaliveTimeout } from '../constants/system';
  4. const url = 'ws://localhost:3002/pubsub'; // TODO
  5. export function useSocket(): {
  6. name: string | null;
  7. onIdentify: (name: string) => void;
  8. socket: WebSocket | null;
  9. error: boolean;
  10. connecting: boolean;
  11. connected: boolean;
  12. } {
  13. const [name, saveName] = useStorageState<string>(localStorage, 'client-name', '');
  14. const [socket, setSocket] = useState<WebSocket | null>(null);
  15. const [error, setError] = useState<boolean>(false);
  16. const [connecting, setConnecting] = useState<boolean>(false);
  17. const onIdentify = useCallback(
  18. (newName: string) => {
  19. setConnecting(true);
  20. const ws = new WebSocket(`${url}?client-name=${name}`);
  21. ws.onopen = (): void => {
  22. if (ws.readyState === ws.OPEN) {
  23. setError(false);
  24. setConnecting(false);
  25. saveName(newName);
  26. setSocket(ws);
  27. }
  28. };
  29. ws.onclose = (): void => {
  30. setError(false);
  31. setSocket(null);
  32. };
  33. },
  34. [saveName],
  35. );
  36. return {
  37. name,
  38. onIdentify,
  39. socket,
  40. error,
  41. connecting,
  42. connected: socket?.readyState === socket?.OPEN,
  43. };
  44. }
  45. export function useKeepalive(socket: WebSocket): void {
  46. const keepalive = useRef<number>();
  47. useEffect(() => {
  48. keepalive.current = window.setInterval(() => {
  49. if (socket.readyState === socket.OPEN) {
  50. socket.send(JSON.stringify({ type: 'PING' }));
  51. } else {
  52. socket.close();
  53. }
  54. }, socketKeepaliveTimeout);
  55. return (): void => {
  56. clearInterval(keepalive.current);
  57. };
  58. }, [socket]);
  59. }