2.6.23: websocket memory leak fix, fixes for device page refresh on websocket notification

This commit is contained in:
Charles
2022-05-05 20:34:58 +01:00
parent d2fd895582
commit f008fd082e
10 changed files with 48 additions and 56 deletions

4
package-lock.json generated
View File

@@ -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",

View File

@@ -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",

View File

@@ -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}

View File

@@ -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);
}
};

View File

@@ -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(() => {

View File

@@ -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>;

View File

@@ -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;

View File

@@ -6,6 +6,7 @@ export const deviceNotificationTypes = [
'device_connection',
'device_disconnection',
'device_firmware_upgrade',
'device_statistics',
];
export const extractWebSocketResponse = (message) => {

View File

@@ -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();

View File

@@ -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,