File size: 3,401 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"use client";

import { useCallback, useState } from "react";
import {
  useLiveDashboard,
  type UseLiveDashboardOptions,
  type WsEventPayload,
} from "./useLiveDashboard";
import {
  compressionEventToModel,
  stepEventsToRunModel,
  appendInFlightStep,
  clearInFlightOnComplete,
  type CompressionRunModel,
  type InFlightCompressionRun,
} from "@/app/(dashboard)/dashboard/compression/studio/compressionFlowModel";
import type { CompressionCompletedPayload, CompressionStepPayload } from "@/lib/events/types";

// ── Constants ─────────────────────────────────────────────────────────────

const MAX_RUNS = 100;

// ── Accumulator (pure reducer β€” exported for unit tests) ─────────────────

/**
 * Pure accumulator: prepend the new run and cap at `maxRuns`.
 * Most-recent-first order.
 */
export function accumulateRun(
  prev: CompressionRunModel[],
  payload: CompressionCompletedPayload,
  maxRuns = MAX_RUNS
): CompressionRunModel[] {
  const model = compressionEventToModel(payload);
  return [model, ...prev].slice(0, maxRuns);
}

// ── useLiveCompression hook ───────────────────────────────────────────────

export interface UseLiveCompressionReturn {
  /** All accumulated runs, most-recent-first. */
  runs: CompressionRunModel[];
  /** The most recently received run, or null. */
  lastRun: CompressionRunModel | null;
  /** Quick lookup by requestId. */
  getRunById: (requestId: string) => CompressionRunModel | undefined;
  isConnected: boolean;
  reconnect: () => void;
}

/**
 * Subscribes to the `compression` WS channel and accumulates
 * `CompressionRunModel[]` (most-recent-first, capped at 100).
 *
 * Mirrors the pattern of `useLiveComboStatus` and `useLiveRequests`.
 */
export function useLiveCompression(options?: UseLiveDashboardOptions): UseLiveCompressionReturn {
  const [runs, setRuns] = useState<CompressionRunModel[]>([]);
  const [inFlight, setInFlight] = useState<InFlightCompressionRun | null>(null);

  const handleEvent = useCallback((event: WsEventPayload) => {
    if (event.channel !== "compression") return;
    if (event.event === "compression.step") {
      setInFlight((prev) => appendInFlightStep(prev, event.data as CompressionStepPayload));
      return;
    }
    if (event.event === "compression.completed") {
      const payload = event.data as CompressionCompletedPayload;
      setInFlight((prev) => clearInFlightOnComplete(prev, payload.requestId));
      setRuns((prev) => accumulateRun(prev, payload));
    }
  }, []);

  const { connection, reconnect } = useLiveDashboard({
    channels: ["compression"],
    onEvent: handleEvent,
    ...options,
  });

  const getRunById = useCallback(
    (requestId: string) => runs.find((r) => r.requestId === requestId),
    [runs]
  );

  const inFlightRun =
    inFlight && inFlight.steps.length > 0 ? stepEventsToRunModel(inFlight.steps) : null;

  return {
    runs,
    // Prefer the live in-flight run so the studio shows engines as they stream in (F3.3),
    // falling back to the latest completed run.
    lastRun: inFlightRun ?? runs[0] ?? null,
    getRunById,
    isConnected: connection.isConnected,
    reconnect,
  };
}