utp_service/frontend/src/hooks/useSSE.ts
2026-04-07 00:52:45 +03:00

40 lines
1.4 KiB
TypeScript

import { fetchEventSource } from '@microsoft/fetch-event-source'
import { useEffect, useRef } from 'react'
import { useAuthStore } from '../store/auth'
interface SSEHandlers {
onTaskEvent?: (data: { message: string; level: string; ts: string }) => void
onTaskResult?: (data: { device_id: number; device_ip: string; status: string; duration_ms: number }) => void
onTaskStatus?: (data: { status: string; total: number; ok: number; failed: number }) => void
}
export function useSSE(taskId: string | null | undefined, handlers: SSEHandlers) {
const accessToken = useAuthStore((s) => s.accessToken)
const handlersRef = useRef(handlers)
handlersRef.current = handlers
useEffect(() => {
if (!taskId || !accessToken) return
const ctrl = new AbortController()
fetchEventSource(`/api/v1/events?task_id=${taskId}`, {
headers: { Authorization: `Bearer ${accessToken}` },
signal: ctrl.signal,
onmessage(ev) {
try {
const data = JSON.parse(ev.data)
if (ev.event === 'task_event') handlersRef.current.onTaskEvent?.(data)
else if (ev.event === 'task_result') handlersRef.current.onTaskResult?.(data)
else if (ev.event === 'task_status') handlersRef.current.onTaskStatus?.(data)
} catch {
// ignore parse errors
}
},
onerror() {
ctrl.abort()
},
})
return () => ctrl.abort()
}, [taskId, accessToken])
}