mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-27 21:05:34 +00:00
91 lines
2.2 KiB
TypeScript
91 lines
2.2 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import { getBase } from './api';
|
|
|
|
export interface AgentEvent {
|
|
type: string;
|
|
timestamp: number;
|
|
data: Record<string, unknown>;
|
|
}
|
|
|
|
function buildWsUrl(agentId?: string): string {
|
|
const base = getBase();
|
|
let origin: string;
|
|
if (base) {
|
|
origin = base.replace(/^http/, 'ws');
|
|
} else {
|
|
const loc = window.location;
|
|
origin = `${loc.protocol === 'https:' ? 'wss:' : 'ws:'}//${loc.host}`;
|
|
}
|
|
const path = '/v1/agents/events';
|
|
return agentId
|
|
? `${origin}${path}?agent_id=${encodeURIComponent(agentId)}`
|
|
: `${origin}${path}`;
|
|
}
|
|
|
|
/**
|
|
* Subscribe to agent events over WebSocket.
|
|
* Auto-reconnects with backoff when the socket drops.
|
|
*/
|
|
export function useAgentEvents(
|
|
agentId: string | undefined,
|
|
onEvent: (event: AgentEvent) => void,
|
|
eventTypes?: readonly string[],
|
|
): void {
|
|
const onEventRef = useRef(onEvent);
|
|
onEventRef.current = onEvent;
|
|
const typesRef = useRef(eventTypes);
|
|
typesRef.current = eventTypes;
|
|
|
|
useEffect(() => {
|
|
if (!agentId) return;
|
|
let ws: WebSocket | null = null;
|
|
let closed = false;
|
|
let retry = 0;
|
|
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
const connect = () => {
|
|
if (closed) return;
|
|
try {
|
|
ws = new WebSocket(buildWsUrl(agentId));
|
|
} catch {
|
|
schedule();
|
|
return;
|
|
}
|
|
ws.onopen = () => {
|
|
retry = 0;
|
|
};
|
|
ws.onmessage = (msg) => {
|
|
try {
|
|
const payload = JSON.parse(msg.data) as AgentEvent;
|
|
const allowed = typesRef.current;
|
|
if (allowed && !allowed.includes(payload.type)) return;
|
|
onEventRef.current(payload);
|
|
} catch {
|
|
// ignore malformed payload
|
|
}
|
|
};
|
|
ws.onclose = () => {
|
|
if (!closed) schedule();
|
|
};
|
|
ws.onerror = () => {
|
|
ws?.close();
|
|
};
|
|
};
|
|
|
|
const schedule = () => {
|
|
if (closed) return;
|
|
const delay = Math.min(30000, 1000 * 2 ** Math.min(retry, 5));
|
|
retry += 1;
|
|
reconnectTimer = setTimeout(connect, delay);
|
|
};
|
|
|
|
connect();
|
|
|
|
return () => {
|
|
closed = true;
|
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
ws?.close();
|
|
};
|
|
}, [agentId]);
|
|
}
|