blakeblackshear.frigate/web/src/api/ws.jsx

150 lines
4.0 KiB
React
Raw Normal View History

2021-02-16 05:10:20 +01:00
import { h, createContext } from 'preact';
import { baseUrl } from './baseUrl';
import { produce } from 'immer';
2021-02-16 05:10:20 +01:00
import { useCallback, useContext, useEffect, useRef, useReducer } from 'preact/hooks';
const initialState = Object.freeze({ __connected: false });
export const WS = createContext({ state: initialState, connection: null });
2021-02-16 05:10:20 +01:00
const defaultCreateWebsocket = (url) => new WebSocket(url);
function reducer(state, { topic, payload, retain }) {
switch (topic) {
case '__CLIENT_CONNECTED':
return produce(state, (draftState) => {
draftState.__connected = true;
});
default:
return produce(state, (draftState) => {
let parsedPayload = payload;
try {
parsedPayload = payload && JSON.parse(payload);
} catch (e) {}
draftState[topic] = {
lastUpdate: Date.now(),
payload: parsedPayload,
retain,
};
});
}
}
export function WsProvider({
config,
2021-02-16 05:10:20 +01:00
children,
createWebsocket = defaultCreateWebsocket,
wsUrl = `${baseUrl.replace(/^http/, 'ws')}ws`,
2021-02-16 05:10:20 +01:00
}) {
const [state, dispatch] = useReducer(reducer, initialState);
const wsRef = useRef();
useEffect(() => {
Object.keys(config.cameras).forEach((camera) => {
const { name, record, detect, snapshots, audio } = config.cameras[camera];
2022-04-25 13:59:52 +02:00
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]);
2021-02-16 05:10:20 +01:00
useEffect(
() => {
const ws = createWebsocket(wsUrl);
2021-02-16 05:10:20 +01:00
ws.onopen = () => {
dispatch({ topic: '__CLIENT_CONNECTED' });
};
ws.onmessage = (event) => {
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
2021-02-16 05:10:20 +01:00
);
return <WS.Provider value={{ state, ws: wsRef.current }}>{children}</WS.Provider>;
2021-02-16 05:10:20 +01:00
}
export function useWs(watchTopic, publishTopic) {
const { state, ws } = useContext(WS);
2021-02-16 05:10:20 +01:00
const value = state[watchTopic] || { payload: null };
2021-02-16 05:10:20 +01:00
const send = useCallback(
2022-04-25 13:59:52 +02:00
(payload, retain = false) => {
ws.send(
JSON.stringify({
topic: publishTopic || watchTopic,
payload: typeof payload !== 'string' ? JSON.stringify(payload) : payload,
2022-04-25 13:59:52 +02:00
retain,
})
);
2021-02-16 05:10:20 +01:00
},
2021-07-06 14:22:48 +02:00
[ws, watchTopic, publishTopic]
2021-02-16 05:10:20 +01:00
);
return { value, send, connected: state.__connected };
}
export function useDetectState(camera) {
const {
value: { payload },
send,
connected,
} = useWs(`${camera}/detect/state`, `${camera}/detect/set`);
return { payload, send, connected };
}
export function useRecordingsState(camera) {
const {
value: { payload },
send,
connected,
} = useWs(`${camera}/recordings/state`, `${camera}/recordings/set`);
return { payload, send, connected };
}
export function useSnapshotsState(camera) {
const {
value: { payload },
send,
connected,
} = useWs(`${camera}/snapshots/state`, `${camera}/snapshots/set`);
return { payload, send, connected };
}
2021-06-21 17:07:14 +02:00
export function useAudioState(camera) {
const {
value: { payload },
send,
connected,
} = useWs(`${camera}/audio/state`, `${camera}/audio/set`);
return { payload, send, connected };
}
export function usePtzCommand(camera) {
const {
value: { payload },
send,
connected,
} = useWs(`${camera}/ptz`, `${camera}/ptz`);
return { payload, send, connected };
}
2021-06-21 17:07:14 +02:00
export function useRestart() {
const {
2021-07-06 14:22:48 +02:00
value: { payload },
2021-06-21 17:07:14 +02:00
send,
connected,
} = useWs('restart', 'restart');
2021-07-06 14:22:48 +02:00
return { payload, send, connected };
2021-06-21 17:07:14 +02:00
}