chunker ui redo
This commit is contained in:
@@ -3,8 +3,6 @@ import type { PipelineEvent } from "../types";
|
||||
|
||||
/**
|
||||
* SSE hook — connects to /api/chunker/stream/{jobId} via native EventSource.
|
||||
*
|
||||
* Demonstrates: real-time event streaming from backend to UI.
|
||||
*/
|
||||
export function useEventStream(jobId: string | null) {
|
||||
const [events, setEvents] = useState<PipelineEvent[]>([]);
|
||||
@@ -20,6 +18,12 @@ export function useEventStream(jobId: string | null) {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
close();
|
||||
setEvents([]);
|
||||
setDone(false);
|
||||
}, [close]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!jobId) return;
|
||||
|
||||
@@ -35,21 +39,28 @@ export function useEventStream(jobId: string | null) {
|
||||
const handleEvent = (eventType: string) => (e: MessageEvent) => {
|
||||
try {
|
||||
const data = JSON.parse(e.data) as PipelineEvent;
|
||||
setEvents((prev) => [...prev, { ...data, status: eventType }]);
|
||||
setEvents((prev) => [...prev, { ...data, event_type: eventType }]);
|
||||
} catch {
|
||||
// ignore parse errors
|
||||
}
|
||||
};
|
||||
|
||||
// Listen to all chunker event types
|
||||
// Listen to all raw pipeline event types
|
||||
const eventTypes = [
|
||||
"waiting",
|
||||
"pending",
|
||||
"chunking",
|
||||
"processing",
|
||||
"collecting",
|
||||
"completed",
|
||||
"failed",
|
||||
"pipeline_start",
|
||||
"pipeline_info",
|
||||
"chunk_queued",
|
||||
"chunk_processing",
|
||||
"chunk_done",
|
||||
"chunk_retry",
|
||||
"chunk_error",
|
||||
"chunk_collected",
|
||||
"worker_status",
|
||||
"pipeline_progress",
|
||||
"pipeline_complete",
|
||||
"pipeline_error",
|
||||
"producer_error",
|
||||
"cancelled",
|
||||
"done",
|
||||
"timeout",
|
||||
@@ -77,5 +88,5 @@ export function useEventStream(jobId: string | null) {
|
||||
};
|
||||
}, [jobId]);
|
||||
|
||||
return { events, connected, done, close };
|
||||
return { events, connected, done, close, reset };
|
||||
}
|
||||
|
||||
103
ui/chunker/src/hooks/useGrpcStream.ts
Normal file
103
ui/chunker/src/hooks/useGrpcStream.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
|
||||
import { WorkerServiceClient } from "../../../common/api/grpc/worker.client";
|
||||
import type { ChunkPipelineEvent } from "../../../common/api/grpc/worker";
|
||||
import type { PipelineEvent } from "../types";
|
||||
|
||||
const GRPC_WEB_URL = "/grpc-web";
|
||||
|
||||
function toEvent(msg: ChunkPipelineEvent): PipelineEvent {
|
||||
return {
|
||||
event_type: msg.eventType,
|
||||
job_id: msg.jobId,
|
||||
sequence: msg.sequence || undefined,
|
||||
worker_id: msg.workerId || undefined,
|
||||
state: msg.state || undefined,
|
||||
queue_size: msg.queueSize || undefined,
|
||||
elapsed: msg.elapsed || undefined,
|
||||
throughput_mbps: msg.throughputMbps || undefined,
|
||||
total_chunks: msg.totalChunks || undefined,
|
||||
processed_chunks: msg.processedChunks || undefined,
|
||||
failed_chunks: msg.failedChunks || undefined,
|
||||
error: msg.error || undefined,
|
||||
processing_time: msg.processingTime || undefined,
|
||||
retries: msg.retries || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* gRPC-Web streaming hook — connects to WorkerService.StreamChunkPipeline
|
||||
* via Envoy proxy. Replaces useEventStream (SSE+Redis).
|
||||
*/
|
||||
export function useGrpcStream(jobId: string | null) {
|
||||
const [events, setEvents] = useState<PipelineEvent[]>([]);
|
||||
const [connected, setConnected] = useState(false);
|
||||
const [done, setDone] = useState(false);
|
||||
const abortRef = useRef<AbortController | null>(null);
|
||||
|
||||
const close = useCallback(() => {
|
||||
if (abortRef.current) {
|
||||
abortRef.current.abort();
|
||||
abortRef.current = null;
|
||||
setConnected(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
close();
|
||||
setEvents([]);
|
||||
setDone(false);
|
||||
}, [close]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!jobId) return;
|
||||
|
||||
setEvents([]);
|
||||
setDone(false);
|
||||
|
||||
const abort = new AbortController();
|
||||
abortRef.current = abort;
|
||||
|
||||
const transport = new GrpcWebFetchTransport({
|
||||
baseUrl: GRPC_WEB_URL,
|
||||
abort: abort.signal,
|
||||
});
|
||||
|
||||
const client = new WorkerServiceClient(transport);
|
||||
|
||||
const stream = client.streamChunkPipeline({ jobId });
|
||||
|
||||
setConnected(true);
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
for await (const msg of stream.responses) {
|
||||
const evt = toEvent(msg);
|
||||
setEvents((prev) => [...prev, evt]);
|
||||
|
||||
if (
|
||||
evt.event_type === "pipeline_complete" ||
|
||||
evt.event_type === "pipeline_error"
|
||||
) {
|
||||
setDone(true);
|
||||
setConnected(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (!abort.signal.aborted) {
|
||||
setConnected(false);
|
||||
}
|
||||
} finally {
|
||||
setConnected(false);
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
abort.abort();
|
||||
abortRef.current = null;
|
||||
};
|
||||
}, [jobId]);
|
||||
|
||||
return { events, connected, done, close, reset };
|
||||
}
|
||||
Reference in New Issue
Block a user