Can stop sync thread from UI

This commit is contained in:
2025-11-19 18:41:26 +01:00
parent 564e606ac7
commit 0d8905d842
4 changed files with 152 additions and 7 deletions

View File

@@ -121,7 +121,7 @@ impl MatrixClient {
.map_err(MatrixClientError::ReadDbPassphrase)?; .map_err(MatrixClientError::ReadDbPassphrase)?;
let client = Client::builder() let client = Client::builder()
.server_name_or_homeserver_url(&AppConfig::get().matrix_homeserver) .homeserver_url(&AppConfig::get().matrix_homeserver)
// Automatically refresh tokens if needed // Automatically refresh tokens if needed
.handle_refresh_tokens() .handle_refresh_tokens()
.sqlite_store(&db_path, Some(&passphrase)) .sqlite_store(&db_path, Some(&passphrase))

View File

@@ -2,7 +2,7 @@ import { APIClient } from "./ApiClient";
export class MatrixSyncApi { export class MatrixSyncApi {
/** /**
* Force sync thread startup * Start sync thread
*/ */
static async Start(): Promise<void> { static async Start(): Promise<void> {
await APIClient.exec({ await APIClient.exec({
@@ -10,4 +10,25 @@ export class MatrixSyncApi {
uri: "/matrix_sync/start", uri: "/matrix_sync/start",
}); });
} }
/**
* Stop sync thread
*/
static async Stop(): Promise<void> {
await APIClient.exec({
method: "POST",
uri: "/matrix_sync/stop",
});
}
/**
* Get sync thread status
*/
static async Status(): Promise<boolean> {
const res = await APIClient.exec({
method: "GET",
uri: "/matrix_sync/status",
});
return res.data.started;
}
} }

View File

@@ -1,4 +1,3 @@
import { APIClient } from "../api/ApiClient";
import { MatrixSyncApi } from "../api/MatrixSyncApi"; import { MatrixSyncApi } from "../api/MatrixSyncApi";
import { AsyncWidget } from "../widgets/AsyncWidget"; import { AsyncWidget } from "../widgets/AsyncWidget";
import { useUserInfo } from "../widgets/dashboard/BaseAuthenticatedPage"; import { useUserInfo } from "../widgets/dashboard/BaseAuthenticatedPage";

View File

@@ -3,15 +3,21 @@ import CloseIcon from "@mui/icons-material/Close";
import KeyIcon from "@mui/icons-material/Key"; import KeyIcon from "@mui/icons-material/Key";
import LinkIcon from "@mui/icons-material/Link"; import LinkIcon from "@mui/icons-material/Link";
import LinkOffIcon from "@mui/icons-material/LinkOff"; import LinkOffIcon from "@mui/icons-material/LinkOff";
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew";
import StopIcon from "@mui/icons-material/Stop";
import { import {
Button, Button,
Card, Card,
CardActions, CardActions,
CardContent, CardContent,
CircularProgress,
Grid,
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import React from "react"; import React from "react";
import { MatrixLinkApi } from "../api/MatrixLinkApi"; import { MatrixLinkApi } from "../api/MatrixLinkApi";
import { MatrixSyncApi } from "../api/MatrixSyncApi";
import { SetRecoveryKeyDialog } from "../dialogs/SetRecoveryKeyDialog"; import { SetRecoveryKeyDialog } from "../dialogs/SetRecoveryKeyDialog";
import { useAlert } from "../hooks/contexts_provider/AlertDialogProvider"; import { useAlert } from "../hooks/contexts_provider/AlertDialogProvider";
import { useConfirm } from "../hooks/contexts_provider/ConfirmDialogProvider"; import { useConfirm } from "../hooks/contexts_provider/ConfirmDialogProvider";
@@ -27,10 +33,17 @@ export function MatrixLinkRoute(): React.ReactElement {
{user.info.matrix_user_id === null ? ( {user.info.matrix_user_id === null ? (
<ConnectCard /> <ConnectCard />
) : ( ) : (
<> <Grid container spacing={2}>
<ConnectedCard /> <Grid size={{ sm: 12, md: 6 }}>
<EncryptionKeyStatus /> <ConnectedCard />
</> </Grid>
<Grid size={{ sm: 12, md: 6 }}>
<EncryptionKeyStatus />
</Grid>
<Grid size={{ sm: 12, md: 6 }}>
<SyncThreadStatus />
</Grid>
</Grid>
)} )}
</MatrixGWRouteContainer> </MatrixGWRouteContainer>
); );
@@ -202,3 +215,115 @@ function EncryptionKeyStatus(): React.ReactElement {
</> </>
); );
} }
function SyncThreadStatus(): React.ReactElement {
const alert = useAlert();
const snackbar = useSnackbar();
const [started, setStarted] = React.useState<undefined | boolean>();
const loadStatus = async () => {
try {
setStarted(await MatrixSyncApi.Status());
} catch (e) {
console.error(`Failed to refresh sync thread status! ${e}`);
snackbar(`Failed to refresh sync thread status! ${e}`);
}
};
const handleStartThread = async () => {
try {
setStarted(undefined);
await MatrixSyncApi.Start();
snackbar("Sync thread started");
} catch (e) {
console.error(`Failed to start sync thread! ${e}`);
alert(`Failed to start sync thread! ${e}`);
}
};
const handleStopThread = async () => {
try {
setStarted(undefined);
await MatrixSyncApi.Stop();
snackbar("Sync thread stopped");
} catch (e) {
console.error(`Failed to stop sync thread! ${e}`);
alert(`Failed to stop sync thread! ${e}`);
}
};
React.useEffect(() => {
const interval = setInterval(loadStatus, 1000);
() => clearInterval(interval);
}, []);
return (
<>
<Card>
<CardContent>
<Typography variant="h5" component="div" gutterBottom>
Sync thread status
</Typography>
<Typography variant="body1" gutterBottom>
<p>
A thread is spawned on the server to watch for events on the
Matrix server. You can restart this thread from here in case of
issue.
</p>
<p>
Current thread status:{" "}
{started === undefined ? (
<>
<CircularProgress
size={"1rem"}
style={{ verticalAlign: "middle" }}
/>
</>
) : started === true ? (
<>
<CheckIcon
style={{ display: "inline", verticalAlign: "middle" }}
/>{" "}
Started
</>
) : (
<>
<PowerSettingsNewIcon
style={{ display: "inline", verticalAlign: "middle" }}
/>
Stopped
</>
)}
</p>
</Typography>
</CardContent>
<CardActions>
{started === false && (
<Button
size="small"
variant="outlined"
startIcon={<PlayArrowIcon />}
onClick={handleStartThread}
>
Start thread
</Button>
)}
{started === true && (
<Button
size="small"
variant="outlined"
startIcon={<StopIcon />}
onClick={handleStopThread}
>
Stop thread
</Button>
)}
</CardActions>
</Card>
</>
);
}