45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
|
import { useEffect, useRef } from 'react'
|
|
import { useAuthStore } from '../store/auth'
|
|
|
|
interface DashboardMonitorHandlers {
|
|
onUpdate?: (eventType: string, data: Record<string, unknown>) => void
|
|
}
|
|
|
|
const DASHBOARD_MONITOR_CHANNEL = '__dashboard_monitor__'
|
|
|
|
export function useDashboardMonitorSSE(handlers: DashboardMonitorHandlers) {
|
|
const accessToken = useAuthStore((s) => s.accessToken)
|
|
const handlersRef = useRef(handlers)
|
|
handlersRef.current = handlers
|
|
|
|
useEffect(() => {
|
|
if (!accessToken) return
|
|
const ctrl = new AbortController()
|
|
|
|
fetchEventSource(`/api/v1/events?task_id=${DASHBOARD_MONITOR_CHANNEL}`, {
|
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
signal: ctrl.signal,
|
|
onmessage(ev) {
|
|
try {
|
|
const data = JSON.parse(ev.data)
|
|
if (
|
|
ev.event === 'dashboard_monitor_update' ||
|
|
ev.event === 'dashboard_monitor_cycle_done' ||
|
|
ev.event === 'dashboard_monitor_cycle_failed'
|
|
) {
|
|
handlersRef.current.onUpdate?.(ev.event, data)
|
|
}
|
|
} catch {
|
|
// ignore parse errors
|
|
}
|
|
},
|
|
onerror(err) {
|
|
ctrl.abort()
|
|
throw err
|
|
},
|
|
})
|
|
|
|
return () => ctrl.abort()
|
|
}, [accessToken])
|
|
}
|