mirror of
https://github.com/optim-enterprises-bv/OptimCloud-gw-ui.git
synced 2025-10-29 17:32:20 +00:00
2.6.23: websocket memory leak fix, fixes for device page refresh on websocket notification
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ucentral-client",
|
||||
"version": "2.6.20",
|
||||
"version": "2.6.23",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ucentral-client",
|
||||
"version": "2.6.20",
|
||||
"version": "2.6.23",
|
||||
"dependencies": {
|
||||
"@coreui/coreui": "^3.4.0",
|
||||
"@coreui/icons": "^2.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ucentral-client",
|
||||
"version": "2.6.20",
|
||||
"version": "2.6.23",
|
||||
"dependencies": {
|
||||
"@coreui/coreui": "^3.4.0",
|
||||
"@coreui/icons": "^2.0.1",
|
||||
|
||||
@@ -18,6 +18,7 @@ const DeviceList = () => {
|
||||
const { t } = useTranslation();
|
||||
const { addToast } = useToast();
|
||||
const history = useHistory();
|
||||
const [overrides, setOverrides] = useState({});
|
||||
const [page, setPage] = useState(parseInt(sessionStorage.getItem('deviceTable') ?? 0, 10));
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const [upgradeStatus, setUpgradeStatus] = useState({
|
||||
@@ -58,6 +59,7 @@ const DeviceList = () => {
|
||||
|
||||
const getDeviceInformation = (selectedPage = page, devicePerPage = devicesPerPage) => {
|
||||
setLoading(true);
|
||||
setOverrides({});
|
||||
|
||||
const options = {
|
||||
headers: {
|
||||
@@ -357,6 +359,15 @@ const DeviceList = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const displayDevices = () =>
|
||||
devices.map((device) => ({
|
||||
...device,
|
||||
connected:
|
||||
overrides[device.serialNumber] !== undefined
|
||||
? overrides[device.serialNumber]
|
||||
: device.connected,
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
getCount();
|
||||
}, []);
|
||||
@@ -364,18 +375,11 @@ const DeviceList = () => {
|
||||
useEffect(() => {
|
||||
if (lastMessage && lastMessage.type === 'DEVICE') {
|
||||
const { serialNumber: msgSerial, isConnected } = lastMessage;
|
||||
if (devices.find(({ serialNumber }) => serialNumber === msgSerial)) {
|
||||
const newDevices = devices.map((device) => {
|
||||
if (device.serialNumber !== msgSerial) return device;
|
||||
return {
|
||||
...device,
|
||||
connected: isConnected,
|
||||
};
|
||||
});
|
||||
setDevices(newDevices);
|
||||
if (overrides[msgSerial] === undefined || overrides[msgSerial] !== isConnected) {
|
||||
setOverrides({ ...overrides, [msgSerial]: isConnected });
|
||||
}
|
||||
}
|
||||
}, [lastMessage, devices]);
|
||||
}, [lastMessage, overrides]);
|
||||
|
||||
useEffect(() => {
|
||||
if (upgradeStatus.result !== undefined) {
|
||||
@@ -400,7 +404,7 @@ const DeviceList = () => {
|
||||
currentPage={page}
|
||||
t={t}
|
||||
searchBar={<DeviceSearchBar />}
|
||||
devices={devices}
|
||||
devices={displayDevices()}
|
||||
loading={loading}
|
||||
updateDevicesPerPage={updateDevicesPerPage}
|
||||
devicesPerPage={devicesPerPage}
|
||||
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { useAuth, DeviceSearchBar as SearchBar } from 'ucentral-libs';
|
||||
import { checkIfJson } from 'utils/helper';
|
||||
import { toJson } from 'utils/helper';
|
||||
|
||||
const DeviceSearchBar = ({ action }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -44,11 +44,9 @@ const DeviceSearchBar = ({ action }) => {
|
||||
};
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
if (checkIfJson(event.data)) {
|
||||
const result = JSON.parse(event.data);
|
||||
if (result.serialNumbers) {
|
||||
setResults(result.serialNumbers);
|
||||
}
|
||||
const result = toJson(event.data);
|
||||
if (result && result.serialNumbers) {
|
||||
setResults(result.serialNumbers);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -87,12 +87,6 @@ const ActionModal = ({ show, toggleModal }) => {
|
||||
autohide: true,
|
||||
}),
|
||||
});
|
||||
addToast({
|
||||
title: t('common.success'),
|
||||
body: t('commands.reboot_start'),
|
||||
color: 'success',
|
||||
autohide: true,
|
||||
});
|
||||
toggleModal();
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
@@ -8,7 +8,6 @@ import { extractWebSocketResponse } from './utils';
|
||||
const WebSocketContext = React.createContext({
|
||||
webSocket: undefined,
|
||||
isOpen: false,
|
||||
allMessages: [],
|
||||
addDeviceListener: () => {},
|
||||
});
|
||||
|
||||
@@ -16,7 +15,7 @@ export const WebSocketProvider = ({ children }) => {
|
||||
const { currentToken, endpoints } = useAuth();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const ws = useRef(undefined);
|
||||
const { allMessages, lastMessage, dispatch } = useSocketReducer();
|
||||
const { lastMessage, dispatch } = useSocketReducer();
|
||||
const { pushNotification } = useWebSocketNotification();
|
||||
|
||||
const onMessage = useCallback((message) => {
|
||||
@@ -68,7 +67,6 @@ export const WebSocketProvider = ({ children }) => {
|
||||
}, [ws?.current]);
|
||||
const values = useMemo(
|
||||
() => ({
|
||||
allMessages,
|
||||
lastMessage,
|
||||
webSocket: ws.current,
|
||||
addDeviceListener: ({ serialNumber, types, addToast, onTrigger }) =>
|
||||
@@ -77,7 +75,7 @@ export const WebSocketProvider = ({ children }) => {
|
||||
dispatch({ type: 'REMOVE_DEVICE_LISTENER', serialNumber }),
|
||||
isOpen,
|
||||
}),
|
||||
[ws, isOpen, allMessages, lastMessage],
|
||||
[ws, isOpen, lastMessage],
|
||||
);
|
||||
|
||||
return <WebSocketContext.Provider value={values}>{children}</WebSocketContext.Provider>;
|
||||
|
||||
@@ -15,7 +15,7 @@ const reducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case 'NEW_NOTIFICATION': {
|
||||
const obj = { type: 'NOTIFICATION', data: action.notification, timestamp: new Date() };
|
||||
return { allMessages: [...state.allMessages, obj], lastMessage: obj };
|
||||
return { ...state, lastMessage: obj };
|
||||
}
|
||||
case 'NEW_COMMAND': {
|
||||
const obj = {
|
||||
@@ -24,7 +24,7 @@ const reducer = (state, action) => {
|
||||
timestamp: new Date(),
|
||||
id: action.data.command_response_id,
|
||||
};
|
||||
return { allMessages: [...state.allMessages, obj], lastMessage: obj };
|
||||
return { ...state, lastMessage: obj };
|
||||
}
|
||||
case 'NEW_DEVICE_NOTIFICATION': {
|
||||
const newListeners = state.deviceListeners;
|
||||
@@ -59,11 +59,7 @@ const reducer = (state, action) => {
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
allMessages: state.allMessages,
|
||||
lastMessage: obj ?? state.lastMessage,
|
||||
deviceListeners: newListeners,
|
||||
};
|
||||
return { ...state, lastMessage: obj ?? state.lastMessage, deviceListeners: newListeners };
|
||||
}
|
||||
case 'ADD_DEVICE_LISTENER': {
|
||||
let newListeners = action.types.map((actionType) => ({
|
||||
@@ -73,29 +69,18 @@ const reducer = (state, action) => {
|
||||
onTrigger: action.onTrigger,
|
||||
}));
|
||||
newListeners = newListeners.concat(state.deviceListeners);
|
||||
return {
|
||||
allMessages: state.allMessages,
|
||||
lastMessage: state.lastMessage,
|
||||
deviceListeners: newListeners,
|
||||
};
|
||||
return { ...state, lastMessage: state.lastMessage, deviceListeners: newListeners };
|
||||
}
|
||||
case 'REMOVE_DEVICE_LISTENER': {
|
||||
const newListeners = state.deviceListeners.filter(
|
||||
(listener) =>
|
||||
listener.serialNumber !== action.serialNumber || listener.onTrigger === undefined,
|
||||
);
|
||||
return {
|
||||
allMessages: state.allMessages,
|
||||
lastMessage: state.lastMessage,
|
||||
deviceListeners: newListeners,
|
||||
};
|
||||
return { ...state, lastMessage: state.lastMessage, deviceListeners: newListeners };
|
||||
}
|
||||
case 'UNKNOWN': {
|
||||
const obj = { type: 'UNKNOWN', data: action.newMessage, timestamp: new Date() };
|
||||
return {
|
||||
allMessages: [...state.allMessages, obj],
|
||||
lastMessage: obj,
|
||||
};
|
||||
return { ...state, lastMessage: obj };
|
||||
}
|
||||
default:
|
||||
throw new Error();
|
||||
@@ -103,12 +88,11 @@ const reducer = (state, action) => {
|
||||
};
|
||||
|
||||
const useSocketReducer = () => {
|
||||
const [{ allMessages, lastMessage, deviceListeners }, dispatch] = useReducer(reducer, {
|
||||
allMessages: [],
|
||||
const [{ lastMessage, deviceListeners }, dispatch] = useReducer(reducer, {
|
||||
deviceListeners: [],
|
||||
});
|
||||
|
||||
return { allMessages, lastMessage, deviceListeners, dispatch };
|
||||
return { lastMessage, deviceListeners, dispatch };
|
||||
};
|
||||
|
||||
export default useSocketReducer;
|
||||
|
||||
@@ -6,6 +6,7 @@ export const deviceNotificationTypes = [
|
||||
'device_connection',
|
||||
'device_disconnection',
|
||||
'device_firmware_upgrade',
|
||||
'device_statistics',
|
||||
];
|
||||
|
||||
export const extractWebSocketResponse = (message) => {
|
||||
|
||||
@@ -119,8 +119,13 @@ const DevicePage = () => {
|
||||
if (deviceId) {
|
||||
addDeviceListener({
|
||||
serialNumber: deviceId,
|
||||
types: ['device_connection', 'device_disconnection', 'device_firmware_upgrade'],
|
||||
onTrigger: () => getData(),
|
||||
types: [
|
||||
'device_connection',
|
||||
'device_disconnection',
|
||||
'device_firmware_upgrade',
|
||||
'device_statistics',
|
||||
],
|
||||
onTrigger: () => refresh(),
|
||||
});
|
||||
getDevice();
|
||||
getData();
|
||||
|
||||
@@ -59,6 +59,14 @@ export const checkIfJson = (string) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
export const toJson = (string) => {
|
||||
try {
|
||||
return JSON.parse(string);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const secondsToDetailed = (
|
||||
seconds,
|
||||
dayLabel,
|
||||
|
||||
Reference in New Issue
Block a user