frigate/web/src/api/ws.tsx

252 lines
6.0 KiB
TypeScript
Raw Normal View History

import { baseUrl } from "./baseUrl";
import {
ReactNode,
createContext,
useCallback,
useContext,
useEffect,
useReducer,
} from "react";
import { produce, Draft } from "immer";
import useWebSocket, { ReadyState } from "react-use-websocket";
import { FrigateConfig } from "@/types/frigateConfig";
import { FrigateEvent, FrigateReview, ToggleableSetting } from "@/types/ws";
import { FrigateStats } from "@/types/stats";
type ReducerState = {
[topic: string]: {
lastUpdate: number;
payload: any;
retain: boolean;
};
};
type ReducerAction = {
topic: string;
payload: any;
retain: boolean;
};
const initialState: ReducerState = {
_initial_state: {
lastUpdate: 0,
payload: "",
retain: false,
},
};
type WebSocketContextProps = {
state: ReducerState;
readyState: ReadyState;
sendJsonMessage: (message: any) => void;
};
export const WS = createContext<WebSocketContextProps>({
state: initialState,
readyState: ReadyState.CLOSED,
sendJsonMessage: () => {},
});
export const useWebSocketContext = (): WebSocketContextProps => {
const context = useContext(WS);
if (!context) {
throw new Error(
"useWebSocketContext must be used within a WebSocketProvider"
);
}
return context;
};
function reducer(state: ReducerState, action: ReducerAction): ReducerState {
switch (action.topic) {
default:
return produce(state, (draftState: Draft<ReducerState>) => {
let parsedPayload = action.payload;
try {
parsedPayload = action.payload && JSON.parse(action.payload);
} catch (e) {}
draftState[action.topic] = {
lastUpdate: Date.now(),
payload: parsedPayload,
retain: action.retain,
};
});
}
}
type WsProviderType = {
config: FrigateConfig;
children: ReactNode;
wsUrl?: string;
};
export function WsProvider({
config,
children,
wsUrl = `${baseUrl.replace(/^http/, "ws")}ws`,
}: WsProviderType) {
const [state, dispatch] = useReducer(reducer, initialState);
const { sendJsonMessage, readyState } = useWebSocket(wsUrl, {
onMessage: (event) => {
dispatch(JSON.parse(event.data));
},
onOpen: () => dispatch({ topic: "", payload: "", retain: false }),
shouldReconnect: () => true,
});
useEffect(() => {
Object.keys(config.cameras).forEach((camera) => {
const { name, record, detect, snapshots, audio } = config.cameras[camera];
dispatch({
topic: `${name}/recordings/state`,
payload: record.enabled ? "ON" : "OFF",
retain: false,
});
dispatch({
topic: `${name}/detect/state`,
payload: detect.enabled ? "ON" : "OFF",
retain: false,
});
dispatch({
topic: `${name}/snapshots/state`,
payload: snapshots.enabled ? "ON" : "OFF",
retain: false,
});
dispatch({
topic: `${name}/audio/state`,
payload: audio.enabled ? "ON" : "OFF",
retain: false,
});
});
}, [config]);
return (
<WS.Provider value={{ state, readyState, sendJsonMessage }}>
{children}
</WS.Provider>
);
}
export function useWs(watchTopic: string, publishTopic: string) {
const { state, readyState, sendJsonMessage } = useWebSocketContext();
const value = state[watchTopic] || { payload: null };
const send = useCallback(
(payload: any, retain = false) => {
if (readyState === ReadyState.OPEN) {
sendJsonMessage({
topic: publishTopic || watchTopic,
payload,
retain,
});
}
},
[sendJsonMessage, readyState, watchTopic, publishTopic]
);
return { value, send };
}
export function useDetectState(camera: string): {
Streamline live view (#9772) * Break out live page * Improving layouts and add chip component * Improve default camera player sizing * Improve live updating * Cleanup and fit figma * Use fixed height * Masonry layout * Fix stuff * Don't force heights * Adjust scaling * Cleanup * remove sidebar (#9731) * remove sidebar * keep sidebar on mobile for now and add icons * Fix revalidation * Cleanup * Cleanup width * Add chips for activity on cameras * Remove dashboard from header * Use Inter font (#9735) * Show still image when no activity is occurring * remove unused search params * add playing check for webrtc * Don't use grid at all for single column * Fix height on mobile * a few style updates to better match figma (#9745) * Remove active objects when they become stationary * Move to sidebar only and make settings separate component * Fix layout * Animate visibility of chips * Sidebar is full screen * Fix tall aspect ratio cameras * Fix complicated aspect logic * remove * Adjust thumbnail aspect and add text * margin on single column layout * Smaller event thumb text * Simplify basic image view * Only show the red dot when camera is recording * Improve typing for camera toggles * animate chips with react-transition-group (#9763) * don't flash when going to still image * revalidate * tooltips and active tracking outline (#9766) * tooltips * fix tooltip provider and add active tracking outline * remove unused icon * remove figma comment * Get live mode working for jsmpeg * add small gradient below timeago on event thumbnails (#9767) * Create live mode hook and make sure jsmpeg can be used * Enforce env var * Use print * Remove unstable * Add tooltips to thumbnails * Put back vite * Format * Update web/src/components/player/JSMpegPlayer.tsx --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Co-authored-by: Blake Blackshear <blake@frigate.video>
2024-02-10 15:30:53 +03:00
payload: ToggleableSetting;
send: (payload: ToggleableSetting, retain?: boolean) => void;
} {
const {
value: { payload },
send,
} = useWs(`${camera}/detect/state`, `${camera}/detect/set`);
return { payload, send };
}
export function useRecordingsState(camera: string): {
Streamline live view (#9772) * Break out live page * Improving layouts and add chip component * Improve default camera player sizing * Improve live updating * Cleanup and fit figma * Use fixed height * Masonry layout * Fix stuff * Don't force heights * Adjust scaling * Cleanup * remove sidebar (#9731) * remove sidebar * keep sidebar on mobile for now and add icons * Fix revalidation * Cleanup * Cleanup width * Add chips for activity on cameras * Remove dashboard from header * Use Inter font (#9735) * Show still image when no activity is occurring * remove unused search params * add playing check for webrtc * Don't use grid at all for single column * Fix height on mobile * a few style updates to better match figma (#9745) * Remove active objects when they become stationary * Move to sidebar only and make settings separate component * Fix layout * Animate visibility of chips * Sidebar is full screen * Fix tall aspect ratio cameras * Fix complicated aspect logic * remove * Adjust thumbnail aspect and add text * margin on single column layout * Smaller event thumb text * Simplify basic image view * Only show the red dot when camera is recording * Improve typing for camera toggles * animate chips with react-transition-group (#9763) * don't flash when going to still image * revalidate * tooltips and active tracking outline (#9766) * tooltips * fix tooltip provider and add active tracking outline * remove unused icon * remove figma comment * Get live mode working for jsmpeg * add small gradient below timeago on event thumbnails (#9767) * Create live mode hook and make sure jsmpeg can be used * Enforce env var * Use print * Remove unstable * Add tooltips to thumbnails * Put back vite * Format * Update web/src/components/player/JSMpegPlayer.tsx --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Co-authored-by: Blake Blackshear <blake@frigate.video>
2024-02-10 15:30:53 +03:00
payload: ToggleableSetting;
send: (payload: ToggleableSetting, retain?: boolean) => void;
} {
const {
value: { payload },
send,
} = useWs(`${camera}/recordings/state`, `${camera}/recordings/set`);
return { payload, send };
}
export function useSnapshotsState(camera: string): {
Streamline live view (#9772) * Break out live page * Improving layouts and add chip component * Improve default camera player sizing * Improve live updating * Cleanup and fit figma * Use fixed height * Masonry layout * Fix stuff * Don't force heights * Adjust scaling * Cleanup * remove sidebar (#9731) * remove sidebar * keep sidebar on mobile for now and add icons * Fix revalidation * Cleanup * Cleanup width * Add chips for activity on cameras * Remove dashboard from header * Use Inter font (#9735) * Show still image when no activity is occurring * remove unused search params * add playing check for webrtc * Don't use grid at all for single column * Fix height on mobile * a few style updates to better match figma (#9745) * Remove active objects when they become stationary * Move to sidebar only and make settings separate component * Fix layout * Animate visibility of chips * Sidebar is full screen * Fix tall aspect ratio cameras * Fix complicated aspect logic * remove * Adjust thumbnail aspect and add text * margin on single column layout * Smaller event thumb text * Simplify basic image view * Only show the red dot when camera is recording * Improve typing for camera toggles * animate chips with react-transition-group (#9763) * don't flash when going to still image * revalidate * tooltips and active tracking outline (#9766) * tooltips * fix tooltip provider and add active tracking outline * remove unused icon * remove figma comment * Get live mode working for jsmpeg * add small gradient below timeago on event thumbnails (#9767) * Create live mode hook and make sure jsmpeg can be used * Enforce env var * Use print * Remove unstable * Add tooltips to thumbnails * Put back vite * Format * Update web/src/components/player/JSMpegPlayer.tsx --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Co-authored-by: Blake Blackshear <blake@frigate.video>
2024-02-10 15:30:53 +03:00
payload: ToggleableSetting;
send: (payload: ToggleableSetting, retain?: boolean) => void;
} {
const {
value: { payload },
send,
} = useWs(`${camera}/snapshots/state`, `${camera}/snapshots/set`);
return { payload, send };
}
export function useAudioState(camera: string): {
Streamline live view (#9772) * Break out live page * Improving layouts and add chip component * Improve default camera player sizing * Improve live updating * Cleanup and fit figma * Use fixed height * Masonry layout * Fix stuff * Don't force heights * Adjust scaling * Cleanup * remove sidebar (#9731) * remove sidebar * keep sidebar on mobile for now and add icons * Fix revalidation * Cleanup * Cleanup width * Add chips for activity on cameras * Remove dashboard from header * Use Inter font (#9735) * Show still image when no activity is occurring * remove unused search params * add playing check for webrtc * Don't use grid at all for single column * Fix height on mobile * a few style updates to better match figma (#9745) * Remove active objects when they become stationary * Move to sidebar only and make settings separate component * Fix layout * Animate visibility of chips * Sidebar is full screen * Fix tall aspect ratio cameras * Fix complicated aspect logic * remove * Adjust thumbnail aspect and add text * margin on single column layout * Smaller event thumb text * Simplify basic image view * Only show the red dot when camera is recording * Improve typing for camera toggles * animate chips with react-transition-group (#9763) * don't flash when going to still image * revalidate * tooltips and active tracking outline (#9766) * tooltips * fix tooltip provider and add active tracking outline * remove unused icon * remove figma comment * Get live mode working for jsmpeg * add small gradient below timeago on event thumbnails (#9767) * Create live mode hook and make sure jsmpeg can be used * Enforce env var * Use print * Remove unstable * Add tooltips to thumbnails * Put back vite * Format * Update web/src/components/player/JSMpegPlayer.tsx --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Co-authored-by: Blake Blackshear <blake@frigate.video>
2024-02-10 15:30:53 +03:00
payload: ToggleableSetting;
send: (payload: ToggleableSetting, retain?: boolean) => void;
} {
const {
value: { payload },
send,
} = useWs(`${camera}/audio/state`, `${camera}/audio/set`);
return { payload, send };
}
export function usePtzCommand(camera: string): {
payload: string;
send: (payload: string, retain?: boolean) => void;
} {
const {
value: { payload },
send,
} = useWs(`${camera}/ptz`, `${camera}/ptz`);
return { payload, send };
}
export function useRestart(): {
payload: string;
send: (payload: string, retain?: boolean) => void;
} {
const {
value: { payload },
send,
} = useWs("restart", "restart");
return { payload, send };
}
export function useFrigateEvents(): { payload: FrigateEvent } {
const {
value: { payload },
} = useWs("events", "");
return { payload };
}
export function useFrigateReviews(): { payload: FrigateReview } {
const {
value: { payload },
} = useWs("reviews", "");
return { payload };
}
export function useFrigateStats(): { payload: FrigateStats } {
const {
value: { payload },
} = useWs("stats", "");
return { payload };
}
export function useMotionActivity(camera: string): { payload: string } {
const {
value: { payload },
} = useWs(`${camera}/motion`, "");
return { payload };
}
Streamline live view (#9772) * Break out live page * Improving layouts and add chip component * Improve default camera player sizing * Improve live updating * Cleanup and fit figma * Use fixed height * Masonry layout * Fix stuff * Don't force heights * Adjust scaling * Cleanup * remove sidebar (#9731) * remove sidebar * keep sidebar on mobile for now and add icons * Fix revalidation * Cleanup * Cleanup width * Add chips for activity on cameras * Remove dashboard from header * Use Inter font (#9735) * Show still image when no activity is occurring * remove unused search params * add playing check for webrtc * Don't use grid at all for single column * Fix height on mobile * a few style updates to better match figma (#9745) * Remove active objects when they become stationary * Move to sidebar only and make settings separate component * Fix layout * Animate visibility of chips * Sidebar is full screen * Fix tall aspect ratio cameras * Fix complicated aspect logic * remove * Adjust thumbnail aspect and add text * margin on single column layout * Smaller event thumb text * Simplify basic image view * Only show the red dot when camera is recording * Improve typing for camera toggles * animate chips with react-transition-group (#9763) * don't flash when going to still image * revalidate * tooltips and active tracking outline (#9766) * tooltips * fix tooltip provider and add active tracking outline * remove unused icon * remove figma comment * Get live mode working for jsmpeg * add small gradient below timeago on event thumbnails (#9767) * Create live mode hook and make sure jsmpeg can be used * Enforce env var * Use print * Remove unstable * Add tooltips to thumbnails * Put back vite * Format * Update web/src/components/player/JSMpegPlayer.tsx --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Co-authored-by: Blake Blackshear <blake@frigate.video>
2024-02-10 15:30:53 +03:00
export function useAudioActivity(camera: string): { payload: number } {
const {
value: { payload },
} = useWs(`${camera}/audio/rms`, "");
return { payload };
}