mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-06-21 20:01:54 +03:00
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* start audio transcription post processor when enabled on any camera * Fetch embed key whenever an error occurs in case the llama server was restarted * mypy * add tooltips for colored dots in settings menu * add ability to reorder cameras from management pane * add ability to reorder birdseye * add reordering save text to camera management view * Include NPU in latency performance hint * Implement turbo for NPU on object detection * hide order fields * drop auto-derived field paths from camera value when unset globally * use correct field type for export hwaccel args * add debug replay to detail actions menu * clarify debug replay in docs * guard get_current_frame_time against missing camera state * Implement debug reply from export * Refactor debug replay to use sources for dynamic playback * Mypy * fix debug export replay source timestamp handling * skip replay cameras in stats immediately * broadcast debug replay state over ws and buffer pre-OPEN sends - push debug replay session state over the job_state ws topic so the status bar reacts instantly to start/stop without polling - fix child-effect-before-parent-effect race in WsProvider that silently dropped initial snapshot requests on cold load * fix debug replay test hang --------- Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
97 lines
2.7 KiB
TypeScript
97 lines
2.7 KiB
TypeScript
import { baseUrl } from "./baseUrl";
|
|
import { ReactNode, useCallback, useEffect, useRef } from "react";
|
|
import { WsSendContext } from "./wsContext";
|
|
import type { Update } from "./wsContext";
|
|
import { processWsMessage, resetWsStore } from "./ws";
|
|
|
|
export function WsProvider({ children }: { children: ReactNode }) {
|
|
const wsUrl = `${baseUrl.replace(/^http/, "ws")}ws`;
|
|
const wsRef = useRef<WebSocket | null>(null);
|
|
const reconnectTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
const reconnectAttempt = useRef(0);
|
|
const unmounted = useRef(false);
|
|
const pendingSends = useRef<Map<string, unknown>>(new Map());
|
|
|
|
const sendJsonMessage = useCallback((msg: unknown) => {
|
|
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
wsRef.current.send(JSON.stringify(msg));
|
|
} else if (msg && typeof msg === "object" && "topic" in msg) {
|
|
// Sends issued before the socket reaches OPEN (or during a reconnect
|
|
// window) are buffered here and flushed in onopen
|
|
pendingSends.current.set(String((msg as { topic: unknown }).topic), msg);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
unmounted.current = false;
|
|
const queue = pendingSends.current;
|
|
|
|
function connect() {
|
|
if (unmounted.current) return;
|
|
|
|
const ws = new WebSocket(wsUrl);
|
|
wsRef.current = ws;
|
|
|
|
ws.onopen = () => {
|
|
reconnectAttempt.current = 0;
|
|
ws.send(
|
|
JSON.stringify({ topic: "onConnect", message: "", retain: false }),
|
|
);
|
|
for (const queued of queue.values()) {
|
|
ws.send(JSON.stringify(queued));
|
|
}
|
|
queue.clear();
|
|
};
|
|
|
|
ws.onmessage = (event: MessageEvent) => {
|
|
processWsMessage(event.data as string);
|
|
};
|
|
|
|
ws.onclose = () => {
|
|
if (unmounted.current) return;
|
|
const delay = Math.min(1000 * 2 ** reconnectAttempt.current, 30000);
|
|
reconnectAttempt.current++;
|
|
reconnectTimer.current = setTimeout(connect, delay);
|
|
};
|
|
|
|
ws.onerror = () => {
|
|
ws.close();
|
|
};
|
|
}
|
|
|
|
connect();
|
|
|
|
return () => {
|
|
unmounted.current = true;
|
|
if (reconnectTimer.current) {
|
|
clearTimeout(reconnectTimer.current);
|
|
}
|
|
const ws = wsRef.current;
|
|
if (ws) {
|
|
ws.onopen = null;
|
|
ws.onmessage = null;
|
|
ws.onclose = null;
|
|
ws.onerror = null;
|
|
ws.close();
|
|
}
|
|
queue.clear();
|
|
resetWsStore();
|
|
};
|
|
}, [wsUrl]);
|
|
|
|
const send = useCallback(
|
|
(message: Update) => {
|
|
sendJsonMessage({
|
|
topic: message.topic,
|
|
payload: message.payload,
|
|
retain: message.retain,
|
|
});
|
|
},
|
|
[sendJsonMessage],
|
|
);
|
|
|
|
return (
|
|
<WsSendContext.Provider value={send}>{children}</WsSendContext.Provider>
|
|
);
|
|
}
|