* mse and misc messages fixes

* clean up
This commit is contained in:
Josh Hawkins 2024-05-18 13:55:17 -05:00 committed by GitHub
parent 8cddfc27fb
commit 5c609c7051
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 83 additions and 41 deletions

View File

@ -28,8 +28,6 @@ function MSEPlayer({
onPlaying, onPlaying,
setFullResolution, setFullResolution,
}: MSEPlayerProps) { }: MSEPlayerProps) {
let connectTS: number = 0;
const RECONNECT_TIMEOUT: number = 30000; const RECONNECT_TIMEOUT: number = 30000;
const CODECS: string[] = [ const CODECS: string[] = [
@ -46,6 +44,7 @@ function MSEPlayer({
const visibilityCheck: boolean = !pip; const visibilityCheck: boolean = !pip;
const [wsState, setWsState] = useState<number>(WebSocket.CLOSED); const [wsState, setWsState] = useState<number>(WebSocket.CLOSED);
const [connectTS, setConnectTS] = useState<number>(0);
const videoRef = useRef<HTMLVideoElement>(null); const videoRef = useRef<HTMLVideoElement>(null);
const wsRef = useRef<WebSocket | null>(null); const wsRef = useRef<WebSocket | null>(null);
@ -103,14 +102,14 @@ function MSEPlayer({
setWsState(WebSocket.CONNECTING); setWsState(WebSocket.CONNECTING);
// TODO may need to check this later setConnectTS(Date.now());
// eslint-disable-next-line
connectTS = Date.now();
wsRef.current = new WebSocket(wsURL); wsRef.current = new WebSocket(wsURL);
wsRef.current.binaryType = "arraybuffer"; wsRef.current.binaryType = "arraybuffer";
wsRef.current.addEventListener("open", () => onOpen()); wsRef.current.addEventListener("open", onOpen);
wsRef.current.addEventListener("close", () => onClose()); wsRef.current.addEventListener("close", onClose);
// we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wsURL]); }, [wsURL]);
const onDisconnect = useCallback(() => { const onDisconnect = useCallback(() => {
@ -121,7 +120,7 @@ function MSEPlayer({
} }
}, []); }, []);
const onOpen = useCallback(() => { const onOpen = () => {
setWsState(WebSocket.OPEN); setWsState(WebSocket.OPEN);
wsRef.current?.addEventListener("message", (ev) => { wsRef.current?.addEventListener("message", (ev) => {
@ -139,23 +138,25 @@ function MSEPlayer({
onmessageRef.current = {}; onmessageRef.current = {};
onMse(); onMse();
// only run once };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const onClose = useCallback(() => {
if (wsState === WebSocket.CLOSED) return;
const reconnect = (timeout?: number) => {
setWsState(WebSocket.CONNECTING); setWsState(WebSocket.CONNECTING);
wsRef.current = null; wsRef.current = null;
const delay = Math.max(RECONNECT_TIMEOUT - (Date.now() - connectTS), 0); const delay =
timeout ?? Math.max(RECONNECT_TIMEOUT - (Date.now() - connectTS), 0);
reconnectTIDRef.current = window.setTimeout(() => { reconnectTIDRef.current = window.setTimeout(() => {
reconnectTIDRef.current = null; reconnectTIDRef.current = null;
onConnect(); onConnect();
}, delay); }, delay);
}, [wsState, connectTS, onConnect]); };
const onClose = () => {
if (wsState === WebSocket.CLOSED) return;
reconnect();
};
const onMse = () => { const onMse = () => {
if ("ManagedMediaSource" in window) { if ("ManagedMediaSource" in window) {
@ -305,7 +306,13 @@ function MSEPlayer({
onLoadedData={onPlaying} onLoadedData={onPlaying}
onLoadedMetadata={handleLoadedMetadata} onLoadedMetadata={handleLoadedMetadata}
muted={!audioEnabled} muted={!audioEnabled}
onError={onClose} onError={() => {
if (wsRef.current) {
wsRef.current.close();
wsRef.current = null;
reconnect(5000);
}
}}
/> />
); );
} }

View File

@ -42,7 +42,7 @@ export default function MotionTuner({
const [changedValue, setChangedValue] = useState(false); const [changedValue, setChangedValue] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { addMessage, clearMessages } = useContext(StatusBarMessagesContext)!; const { addMessage, removeMessage } = useContext(StatusBarMessagesContext)!;
const { send: sendMotionThreshold } = useMotionThreshold(selectedCamera); const { send: sendMotionThreshold } = useMotionThreshold(selectedCamera);
const { send: sendMotionContourArea } = useMotionContourArea(selectedCamera); const { send: sendMotionContourArea } = useMotionContourArea(selectedCamera);
@ -148,21 +148,23 @@ export default function MotionTuner({
const onCancel = useCallback(() => { const onCancel = useCallback(() => {
setMotionSettings(origMotionSettings); setMotionSettings(origMotionSettings);
setChangedValue(false); setChangedValue(false);
clearMessages("motion_tuner"); removeMessage("motion_tuner", `motion_tuner_${selectedCamera}`);
}, [origMotionSettings, clearMessages]); }, [origMotionSettings, removeMessage, selectedCamera]);
useEffect(() => { useEffect(() => {
if (changedValue) { if (changedValue) {
addMessage( addMessage(
"motion_tuner", "motion_tuner",
"Unsaved motion tuner changes", `Unsaved motion tuner changes (${selectedCamera})`,
undefined, undefined,
"motion_tuner", `motion_tuner_${selectedCamera}`,
); );
} else { } else {
clearMessages("motion_tuner"); removeMessage("motion_tuner", `motion_tuner_${selectedCamera}`);
} }
}, [changedValue, addMessage, clearMessages]); // we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [changedValue, selectedCamera]);
useEffect(() => { useEffect(() => {
document.title = "Motion Tuner - Frigate"; document.title = "Motion Tuner - Frigate";

View File

@ -26,7 +26,7 @@ import {
toRGBColorString, toRGBColorString,
} from "@/utils/canvasUtil"; } from "@/utils/canvasUtil";
import { Polygon, PolygonType } from "@/types/canvas"; import { Polygon, PolygonType } from "@/types/canvas";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useContext, useMemo, useState } from "react";
import axios from "axios"; import axios from "axios";
import { Toaster } from "@/components/ui/sonner"; import { Toaster } from "@/components/ui/sonner";
import { toast } from "sonner"; import { toast } from "sonner";
@ -34,6 +34,7 @@ import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig"; import { FrigateConfig } from "@/types/frigateConfig";
import { reviewQueries } from "@/utils/zoneEdutUtil"; import { reviewQueries } from "@/utils/zoneEdutUtil";
import IconWrapper from "../ui/icon-wrapper"; import IconWrapper from "../ui/icon-wrapper";
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
type PolygonItemProps = { type PolygonItemProps = {
polygon: Polygon; polygon: Polygon;
@ -57,6 +58,7 @@ export default function PolygonItem({
const { data: config, mutate: updateConfig } = const { data: config, mutate: updateConfig } =
useSWR<FrigateConfig>("config"); useSWR<FrigateConfig>("config");
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const { addMessage } = useContext(StatusBarMessagesContext)!;
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const cameraConfig = useMemo(() => { const cameraConfig = useMemo(() => {
@ -198,6 +200,12 @@ export default function PolygonItem({
const handleDelete = () => { const handleDelete = () => {
setActivePolygonIndex(undefined); setActivePolygonIndex(undefined);
saveToConfig(polygon); saveToConfig(polygon);
addMessage(
"masks_zones",
"Restart required (masks/zones changed)",
undefined,
"masks_zones",
);
}; };
return ( return (

View File

@ -29,7 +29,7 @@ type StatusBarMessagesContextValue = {
color?: string, color?: string,
messageId?: string, messageId?: string,
link?: string, link?: string,
) => string; ) => string | undefined;
removeMessage: (key: string, messageId: string) => void; removeMessage: (key: string, messageId: string) => void;
clearMessages: (key: string) => void; clearMessages: (key: string) => void;
}; };
@ -52,26 +52,51 @@ export function StatusBarMessagesProvider({
messageId?: string, messageId?: string,
link?: string, link?: string,
) => { ) => {
const id = messageId || Date.now().toString(); if (!key || !message) return;
const msgColor = color || "text-danger";
setMessagesState((prevMessages) => ({ const id = messageId ?? Date.now().toString();
...prevMessages, const msgColor = color ?? "text-danger";
[key]: [
...(prevMessages[key] || []), setMessagesState((prevMessages) => {
{ id, text: message, color: msgColor, link }, const existingMessages = prevMessages[key] || [];
], // Check if a message with the same ID already exists
})); const messageIndex = existingMessages.findIndex((msg) => msg.id === id);
const newMessage = { id, text: message, color: msgColor, link };
// If the message exists, replace it, otherwise add the new message
let updatedMessages;
if (messageIndex > -1) {
updatedMessages = [
...existingMessages.slice(0, messageIndex),
newMessage,
...existingMessages.slice(messageIndex + 1),
];
} else {
updatedMessages = [...existingMessages, newMessage];
}
return {
...prevMessages,
[key]: updatedMessages,
};
});
return id; return id;
}, },
[], [],
); );
const removeMessage = useCallback((key: string, messageId: string) => { const removeMessage = useCallback(
setMessagesState((prevMessages) => ({ (key: string, messageId: string) => {
...prevMessages, if (!messages || !key || !messages[key]) return;
[key]: prevMessages[key].filter((msg) => msg.id !== messageId), setMessagesState((prevMessages) => ({
})); ...prevMessages,
}, []); [key]: prevMessages[key].filter((msg) => msg.id !== messageId),
}));
},
[messages],
);
const clearMessages = useCallback((key: string) => { const clearMessages = useCallback((key: string) => {
setMessagesState((prevMessages) => { setMessagesState((prevMessages) => {