mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 08:49:52 +03:00
95 lines
2.5 KiB
TypeScript
95 lines
2.5 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
import Sockette from 'sockette';
|
|
import { debounce } from 'lodash';
|
|
|
|
import { addAccessTokenParameter } from '../api/authentication';
|
|
|
|
interface WebSocketIdMessage {
|
|
type: 'id';
|
|
id: string;
|
|
}
|
|
|
|
interface WebSocketPayloadMessage<D> {
|
|
type: 'payload';
|
|
origin_id: string;
|
|
payload: D;
|
|
}
|
|
|
|
export type WebSocketMessage<D> = WebSocketIdMessage | WebSocketPayloadMessage<D>;
|
|
|
|
export const useWs = <D>(wsUrl: string, wsThrottle: number = 100) => {
|
|
const ws = useRef<Sockette>();
|
|
const clientId = useRef<string>();
|
|
|
|
const [connected, setConnected] = useState<boolean>(false);
|
|
const [data, setData] = useState<D>();
|
|
const [transmit, setTransmit] = useState<boolean>();
|
|
const [clear, setClear] = useState<boolean>();
|
|
|
|
const onMessage = useCallback((event: MessageEvent) => {
|
|
const rawData = event.data;
|
|
if (typeof rawData === 'string' || rawData instanceof String) {
|
|
const message = JSON.parse(rawData as string) as WebSocketMessage<D>;
|
|
switch (message.type) {
|
|
case 'id':
|
|
clientId.current = message.id;
|
|
break;
|
|
case 'payload':
|
|
if (clientId.current) {
|
|
setData((existingData) => (clientId.current === message.origin_id && existingData) || message.payload);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}, []);
|
|
|
|
const doSaveData = useCallback((newData: D, clearData: boolean = false) => {
|
|
if (!ws.current) {
|
|
return;
|
|
}
|
|
if (clearData) {
|
|
setData(undefined);
|
|
}
|
|
ws.current.json(newData);
|
|
}, []);
|
|
|
|
const saveData = useRef(debounce(doSaveData, wsThrottle));
|
|
|
|
const updateData = (
|
|
newData: React.SetStateAction<D | undefined>,
|
|
transmitData: boolean = true,
|
|
clearData: boolean = false
|
|
) => {
|
|
setData(newData);
|
|
setTransmit(transmitData);
|
|
setClear(clearData);
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!transmit) {
|
|
return;
|
|
}
|
|
data && saveData.current(data, clear);
|
|
setTransmit(false);
|
|
setClear(false);
|
|
}, [doSaveData, data, transmit, clear]);
|
|
|
|
useEffect(() => {
|
|
const instance = new Sockette(addAccessTokenParameter(wsUrl), {
|
|
onmessage: onMessage,
|
|
onopen: () => {
|
|
setConnected(true);
|
|
},
|
|
onclose: () => {
|
|
clientId.current = undefined;
|
|
setConnected(false);
|
|
setData(undefined);
|
|
}
|
|
});
|
|
ws.current = instance;
|
|
return instance.close;
|
|
}, [wsUrl, onMessage]);
|
|
|
|
return { connected, data, updateData } as const;
|
|
};
|