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