refactored restart and format services to be non-blocking

This commit is contained in:
proddy
2024-08-31 16:12:30 +02:00
parent 382c46622d
commit 931827c526
19 changed files with 243 additions and 202 deletions

View File

@@ -1,52 +1,80 @@
import { type FC, useEffect, useRef, useState } from 'react';
import { useState } from 'react';
import {
Box,
CircularProgress,
Dialog,
DialogContent,
Typography
} from '@mui/material';
import { readHardwareStatus } from 'api/system';
import { useRequest } from 'alova/client';
import { FormLoader } from 'components';
import { dialogStyle } from 'CustomTheme';
import { useAutoRequest } from 'alova/client';
import MessageBox from 'components/MessageBox';
import { useI18nContext } from 'i18n/i18n-react';
const RESTART_TIMEOUT = 2 * 60 * 1000; // 2 minutes
const POLL_INTERVAL = 2000; // every 2 seconds
export interface RestartMonitorProps {
message?: string;
}
const RestartMonitor: FC<RestartMonitorProps> = ({ message }) => {
const [failed, setFailed] = useState<boolean>(false);
const [timeoutId, setTimeoutId] = useState<NodeJS.Timeout>();
const RestartMonitor = () => {
const [errorMessage, setErrorMessage] = useState<string>();
const { LL } = useI18nContext();
const timeoutAt = useRef(new Date().getTime() + RESTART_TIMEOUT);
let count = 0;
const { send } = useRequest(readHardwareStatus, { immediate: false });
const poll = useRef(async () => {
try {
await send();
document.location.href = '/';
} catch {
if (new Date().getTime() < timeoutAt.current) {
setTimeoutId(setTimeout(poll.current, POLL_INTERVAL));
} else {
setFailed(true);
const { data } = useAutoRequest(readHardwareStatus, {
pollingTime: 1000,
force: true,
initialData: { status: 'Getting ready...' },
async middleware(_, next) {
if (count++ >= 1) {
// skip first request (1 seconds) to allow AsyncWS to send its response
await next();
}
}
});
useEffect(() => {
setTimeoutId(setTimeout(poll.current, POLL_INTERVAL));
}, []);
useEffect(() => () => timeoutId && clearTimeout(timeoutId), [timeoutId]);
})
.onSuccess((event) => {
console.log(event.data.status); // TODO remove
if (event.data.status === 'ready' || event.data.status === undefined) {
document.location.href = '/';
}
})
.onError((error, _method) => {
setErrorMessage(error.message);
});
return (
<FormLoader
message={message ? message : LL.APPLICATION_RESTARTING() + '...'}
errorMessage={failed ? 'Timed out' : undefined}
/>
<Dialog fullWidth={true} sx={dialogStyle} open={true}>
<DialogContent dividers>
<Box m={2} py={2} display="flex" alignItems="center" flexDirection="column">
<Typography
color="secondary"
variant="h6"
fontWeight={400}
textAlign="center"
>
{data?.status === 'uploading'
? LL.WAIT_FIRMWARE()
: data?.status === 'restarting'
? LL.APPLICATION_RESTARTING()
: data?.status === 'ready'
? 'Reloading'
: 'Preparing'}
</Typography>
<Typography mt={2} variant="h6" fontWeight={400} textAlign="center">
{LL.PLEASE_WAIT()}&hellip;
</Typography>
{errorMessage ? (
<MessageBox my={2} level="error" message={errorMessage} />
) : (
<Box py={2}>
<CircularProgress size={48} />
</Box>
)}
</Box>
</DialogContent>
</Dialog>
);
};

View File

@@ -30,10 +30,11 @@ import {
} from '@mui/material';
import * as SystemApi from 'api/system';
import { API } from 'api/app';
import { dialogStyle } from 'CustomTheme';
import { useAutoRequest, useRequest } from 'alova/client';
import { busConnectionStatus } from 'app/main/types';
import { type APIcall, busConnectionStatus } from 'app/main/types';
import { FormLoader, SectionContent, useLayoutTitle } from 'components';
import ListMenuItem from 'components/layout/ListMenuItem';
import { AuthenticatedContext } from 'contexts/authentication';
@@ -54,7 +55,7 @@ const SystemStatus = () => {
const [confirmRestart, setConfirmRestart] = useState<boolean>(false);
const [restarting, setRestarting] = useState<boolean>();
const { send: restartCommand } = useRequest(SystemApi.restart(), {
const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
immediate: false
});
@@ -64,7 +65,12 @@ const SystemStatus = () => {
error
} = useAutoRequest(SystemApi.readSystemStatus, {
initialData: [],
pollingTime: 5000
pollingTime: 5000,
async middleware(_, next) {
if (!restarting) {
await next();
}
}
});
const theme = useTheme();
@@ -195,17 +201,14 @@ const SystemStatus = () => {
const activeHighlight = (value: boolean) =>
value ? theme.palette.success.main : theme.palette.info.main;
const restart = async () => {
await restartCommand()
.then(() => {
setRestarting(true);
})
.catch((error: Error) => {
const doRestart = async () => {
setConfirmRestart(false);
setRestarting(true);
await sendAPI({ device: 'system', cmd: 'restart', id: -1 }).catch(
(error: Error) => {
toast.error(error.message);
})
.finally(() => {
setConfirmRestart(false);
});
}
);
};
const renderRestartDialog = () => (
@@ -228,7 +231,7 @@ const SystemStatus = () => {
<Button
startIcon={<PowerSettingsNewIcon />}
variant="outlined"
onClick={restart}
onClick={doRestart}
color="error"
>
{LL.RESTART()}