use react-use-websockets

This commit is contained in:
Josh Hawkins 2023-10-13 20:50:34 -05:00
parent dcafcc1320
commit 31db8e6a6d
3 changed files with 42 additions and 36 deletions

16
web/package-lock.json generated
View File

@ -20,6 +20,7 @@
"preact-router": "^4.1.0", "preact-router": "^4.1.0",
"react": "npm:@preact/compat@^17.1.2", "react": "npm:@preact/compat@^17.1.2",
"react-dom": "npm:@preact/compat@^17.1.2", "react-dom": "npm:@preact/compat@^17.1.2",
"react-use-websocket": "^3.0.0",
"strftime": "^0.10.1", "strftime": "^0.10.1",
"swr": "^1.3.0", "swr": "^1.3.0",
"video.js": "^8.5.2", "video.js": "^8.5.2",
@ -7721,6 +7722,15 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true "dev": true
}, },
"node_modules/react-use-websocket": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-3.0.0.tgz",
"integrity": "sha512-BInlbhXYrODBPKIplDAmI0J1VPM+1KhCLN09o+dzgQ8qMyrYs4t5kEYmCrTqyRuMTmpahylHFZWQXpfYyDkqOw==",
"peerDependencies": {
"react": ">= 16.8.0",
"react-dom": ">= 16.8.0"
}
},
"node_modules/read-cache": { "node_modules/read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@ -14902,6 +14912,12 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true "dev": true
}, },
"react-use-websocket": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/react-use-websocket/-/react-use-websocket-3.0.0.tgz",
"integrity": "sha512-BInlbhXYrODBPKIplDAmI0J1VPM+1KhCLN09o+dzgQ8qMyrYs4t5kEYmCrTqyRuMTmpahylHFZWQXpfYyDkqOw==",
"requires": {}
},
"read-cache": { "read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

View File

@ -24,6 +24,7 @@
"preact-router": "^4.1.0", "preact-router": "^4.1.0",
"react": "npm:@preact/compat@^17.1.2", "react": "npm:@preact/compat@^17.1.2",
"react-dom": "npm:@preact/compat@^17.1.2", "react-dom": "npm:@preact/compat@^17.1.2",
"react-use-websocket": "^3.0.0",
"strftime": "^0.10.1", "strftime": "^0.10.1",
"swr": "^1.3.0", "swr": "^1.3.0",
"video.js": "^8.5.2", "video.js": "^8.5.2",

View File

@ -1,13 +1,12 @@
import { h, createContext } from 'preact'; import { createContext } from 'preact';
import { baseUrl } from './baseUrl'; import { baseUrl } from './baseUrl';
import { produce } from 'immer'; import { produce } from 'immer';
import { useCallback, useContext, useEffect, useRef, useReducer } from 'preact/hooks'; import { useCallback, useContext, useEffect, useReducer } from 'preact/hooks';
import useWebSocket from 'react-use-websocket';
const initialState = Object.freeze({ __connected: false }); const initialState = Object.freeze({ __connected: false });
export const WS = createContext({ state: initialState, connection: null }); export const WS = createContext({ state: initialState, connection: null });
const defaultCreateWebsocket = (url) => new WebSocket(url);
function reducer(state, { topic, payload, retain }) { function reducer(state, { topic, payload, retain }) {
switch (topic) { switch (topic) {
case '__CLIENT_CONNECTED': case '__CLIENT_CONNECTED':
@ -33,14 +32,23 @@ function reducer(state, { topic, payload, retain }) {
export function WsProvider({ export function WsProvider({
config, config,
children, children,
createWebsocket = defaultCreateWebsocket,
wsUrl = `${baseUrl.replace(/^http/, 'ws')}ws`, wsUrl = `${baseUrl.replace(/^http/, 'ws')}ws`,
}) { }) {
const [state, dispatch] = useReducer(reducer, initialState); const [state, dispatch] = useReducer(reducer, initialState);
const wsRef = useRef(); console.log(dispatch);
const { sendJsonMessage } = useWebSocket(wsUrl, {
onMessage: (event) => {
dispatch(event.data);
},
onOpen: () => dispatch({ topic: '__CLIENT_CONNECTED' }),
shouldReconnect: () => true,
});
useEffect(() => { useEffect(() => {
Object.keys(config.cameras).forEach((camera) => { Object.keys(config.cameras).forEach((camera) => {
console.log("Setting up")
const { name, record, detect, snapshots, audio } = config.cameras[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}/recordings/state`, payload: record.enabled ? 'ON' : 'OFF', retain: false });
dispatch({ topic: `${name}/detect/state`, payload: detect.enabled ? 'ON' : 'OFF', retain: false }); dispatch({ topic: `${name}/detect/state`, payload: detect.enabled ? 'ON' : 'OFF', retain: false });
@ -49,46 +57,27 @@ export function WsProvider({
}); });
}, [config]); }, [config]);
useEffect(
() => {
const ws = createWebsocket(wsUrl);
ws.onopen = () => {
dispatch({ topic: '__CLIENT_CONNECTED' });
};
ws.onmessage = (event) => { return <WS.Provider value={{ state, sendJsonMessage }}>{children}</WS.Provider>;
dispatch(JSON.parse(event.data));
};
wsRef.current = ws;
return () => {
ws.close(3000, 'Provider destroyed');
};
},
// Forces reconnecting
[state.__reconnectAttempts, wsUrl] // eslint-disable-line react-hooks/exhaustive-deps
);
return <WS.Provider value={{ state, ws: wsRef.current }}>{children}</WS.Provider>;
} }
export function useWs(watchTopic, publishTopic) { export function useWs(watchTopic, publishTopic) {
const { state, ws } = useContext(WS); const { state, sendJsonMessage } = useContext(WS);
console.log(state);
const value = state[watchTopic] || { payload: null }; const value = state[watchTopic] || { payload: null };
const send = useCallback( const send = useCallback(
(payload, retain = false) => { (payload, retain = false) => {
ws.send( console.log("sending json");
JSON.stringify({ sendJsonMessage({
topic: publishTopic || watchTopic, topic: publishTopic || watchTopic,
payload: typeof payload !== 'string' ? JSON.stringify(payload) : payload, payload: payload,
retain, retain,
}) });
);
}, },
[ws, watchTopic, publishTopic] [sendJsonMessage, watchTopic, publishTopic]
); );
return { value, send, connected: state.__connected }; return { value, send, connected: state.__connected };