All files / src/hooks useLiveSessionEvents.ts

83.63% Statements 46/55
73.33% Branches 11/15
83.33% Functions 5/6
83.63% Lines 46/55

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 711x         1x 1x   1x 2x 2x   2x 2x 2x   2x 2x           2x 2x   2x 2x 2x   2x 3x 3x 3x   3x 1x 1x 1x   3x 1x     1x 1x   3x 1x 1x 1x 1x 1x 1x 1x   3x     3x   2x   2x 2x 2x 2x 2x 2x 2x  
import { useEffect, useRef } from "react";
import { websocketUrl } from "../api";
import { useSessionStore } from "../store";
import type { WebEvent } from "../types";
 
const INITIAL_DELAY = 1000;
const MAX_DELAY = 30000;
 
export function useLiveSessionEvents(
  sessionKey: string | null,
  liveSessionId: string | null,
): void {
  const applyEvent = useSessionStore((state) => state.applyEvent);
  const setConnection = useSessionStore((state) => state.setConnection);
  const retryDelay = useRef(INITIAL_DELAY);
 
  useEffect(() => {
    if (!sessionKey || !liveSessionId) {
      if (sessionKey) {
        setConnection(sessionKey, "disconnected");
      }
      return;
    }
    const currentSessionKey = sessionKey;
    const currentLiveSessionId = liveSessionId;
 
    let socket: WebSocket | null = null;
    let retryTimer: ReturnType<typeof setTimeout> | null = null;
    let disposed = false;
 
    function connect() {
      if (disposed) return;
      setConnection(currentSessionKey, "connecting");
      socket = new WebSocket(websocketUrl(`/api/events/${currentLiveSessionId}`));
 
      socket.onopen = () => {
        retryDelay.current = INITIAL_DELAY;
        setConnection(currentSessionKey, "connected");
      };
 
      socket.onmessage = (message) => {
        if (typeof message.data !== "string") {
          return;
        }
        applyEvent(currentSessionKey, JSON.parse(message.data) as WebEvent);
      };
 
      socket.onclose = () => {
        if (disposed) return;
        setConnection(currentSessionKey, "disconnected");
        retryTimer = setTimeout(() => {
          retryDelay.current = Math.min(retryDelay.current * 2, MAX_DELAY);
          connect();
        }, retryDelay.current);
      };
 
      socket.onerror = () => {
        socket?.close();
      };
    }
 
    connect();
 
    return () => {
      disposed = true;
      if (retryTimer) clearTimeout(retryTimer);
      socket?.close();
    };
  }, [applyEvent, sessionKey, liveSessionId, setConnection]);
}