diff --git a/matrixgw_backend/src/controllers/ws_controller.rs b/matrixgw_backend/src/controllers/ws_controller.rs index 9ac0092..c9ae359 100644 --- a/matrixgw_backend/src/controllers/ws_controller.rs +++ b/matrixgw_backend/src/controllers/ws_controller.rs @@ -6,7 +6,7 @@ use crate::extractors::matrix_client_extractor::MatrixClientExtractor; use crate::matrix_connection::matrix_client::MatrixClient; use crate::matrix_connection::matrix_manager::MatrixManagerMsg; use actix_web::dev::Payload; -use actix_web::{FromRequest, HttpRequest, web}; +use actix_web::{FromRequest, HttpRequest, HttpResponse, web}; use actix_ws::Message; use futures_util::StreamExt; use matrix_sdk::ruma::OwnedRoomId; @@ -38,6 +38,11 @@ pub async fn ws( // Forcefully ignore request payload by manually extracting authentication information let client = MatrixClientExtractor::from_request(&req, &mut Payload::None).await?; + // Check if Matrix link has been established first + if !client.client.is_client_connected() { + return Ok(HttpResponse::ExpectationFailed().json("Matrix link not established yet!")); + } + // Ensure sync thread is started ractor::cast!( manager, diff --git a/matrixgw_backend/src/extractors/matrix_client_extractor.rs b/matrixgw_backend/src/extractors/matrix_client_extractor.rs index 0a80c3e..8ba5688 100644 --- a/matrixgw_backend/src/extractors/matrix_client_extractor.rs +++ b/matrixgw_backend/src/extractors/matrix_client_extractor.rs @@ -15,6 +15,7 @@ impl MatrixClientExtractor { pub async fn to_extended_user_info(&self) -> anyhow::Result { Ok(ExtendedUserInfo { user: self.auth.user.clone(), + matrix_account_connected: self.client.is_client_connected(), matrix_user_id: self.client.user_id().map(|id| id.to_string()), matrix_device_id: self.client.device_id().map(|id| id.to_string()), matrix_recovery_state: self.client.recovery_state(), diff --git a/matrixgw_backend/src/users.rs b/matrixgw_backend/src/users.rs index 26f1f17..6727e0b 100644 --- a/matrixgw_backend/src/users.rs +++ b/matrixgw_backend/src/users.rs @@ -281,6 +281,7 @@ impl APIToken { pub struct ExtendedUserInfo { #[serde(flatten)] pub user: User, + pub matrix_account_connected: bool, pub matrix_user_id: Option, pub matrix_device_id: Option, pub matrix_recovery_state: EncryptionRecoveryState, diff --git a/matrixgw_frontend/src/api/AuthApi.ts b/matrixgw_frontend/src/api/AuthApi.ts index c9d0fa8..bcf6f3d 100644 --- a/matrixgw_frontend/src/api/AuthApi.ts +++ b/matrixgw_frontend/src/api/AuthApi.ts @@ -6,6 +6,7 @@ export interface UserInfo { time_update: number; name: string; email: string; + matrix_account_connected: boolean; matrix_user_id?: string; matrix_device_id?: string; matrix_recovery_state?: "Enabled" | "Disabled" | "Unknown" | "Incomplete"; diff --git a/matrixgw_frontend/src/routes/HomeRoute.tsx b/matrixgw_frontend/src/routes/HomeRoute.tsx index e404074..829833c 100644 --- a/matrixgw_frontend/src/routes/HomeRoute.tsx +++ b/matrixgw_frontend/src/routes/HomeRoute.tsx @@ -6,7 +6,7 @@ import { NotLinkedAccountMessage } from "../widgets/NotLinkedAccountMessage"; export function HomeRoute(): React.ReactElement { const user = useUserInfo(); - if (!user.info.matrix_user_id) return ; + if (!user.info.matrix_account_connected) return ; return (

diff --git a/matrixgw_frontend/src/routes/WSDebugRoute.tsx b/matrixgw_frontend/src/routes/WSDebugRoute.tsx index a4e3bfd..fa6fb67 100644 --- a/matrixgw_frontend/src/routes/WSDebugRoute.tsx +++ b/matrixgw_frontend/src/routes/WSDebugRoute.tsx @@ -4,7 +4,9 @@ import "react-json-view-lite/dist/index.css"; import { WsApi, type WsMessage } from "../api/WsApi"; import { useSnackbar } from "../hooks/contexts_provider/SnackbarProvider"; import { time } from "../utils/DateUtils"; +import { useUserInfo } from "../widgets/dashboard/BaseAuthenticatedPage"; import { MatrixGWRouteContainer } from "../widgets/MatrixGWRouteContainer"; +import { NotLinkedAccountMessage } from "../widgets/NotLinkedAccountMessage"; const State = { Closed: "Closed", @@ -15,6 +17,9 @@ const State = { type TimestampedMessages = WsMessage & { time: number }; export function WSDebugRoute(): React.ReactElement { + const user = useUserInfo(); + if (!user.info.matrix_account_connected) return ; + const snackbar = useSnackbar(); const [state, setState] = React.useState(State.Closed); @@ -28,7 +33,7 @@ export function WSDebugRoute(): React.ReactElement { ws.onopen = () => setState(State.Connected); ws.onerror = (e) => { - console.error(`WS Debug error! ${e}`); + console.error(`WS Debug error!`, e); snackbar(`WebSocket error! ${e}`); setState(State.Error); }; diff --git a/matrixgw_frontend/src/widgets/dashboard/DashboardSidebar.tsx b/matrixgw_frontend/src/widgets/dashboard/DashboardSidebar.tsx index a2c7f3d..7a9974f 100644 --- a/matrixgw_frontend/src/widgets/dashboard/DashboardSidebar.tsx +++ b/matrixgw_frontend/src/widgets/dashboard/DashboardSidebar.tsx @@ -8,6 +8,7 @@ import { useTheme } from "@mui/material/styles"; import type {} from "@mui/material/themeCssVarsAugmentation"; import useMediaQuery from "@mui/material/useMediaQuery"; import * as React from "react"; +import { useUserInfo } from "./BaseAuthenticatedPage"; import DashboardSidebarContext from "./DashboardSidebarContext"; import DashboardSidebarDividerItem from "./DashboardSidebarDividerItem"; import DashboardSidebarPageItem from "./DashboardSidebarPageItem"; @@ -31,6 +32,7 @@ export default function DashboardSidebar({ container, }: DashboardSidebarProps) { const theme = useTheme(); + const user = useUserInfo(); const isOverSmViewport = useMediaQuery(theme.breakpoints.up("sm")); const isOverMdViewport = useMediaQuery(theme.breakpoints.up("md")); @@ -99,6 +101,7 @@ export default function DashboardSidebar({ }} > } href="/" @@ -115,6 +118,7 @@ export default function DashboardSidebar({ href="/tokens" /> } href="/wsdebug" @@ -123,7 +127,12 @@ export default function DashboardSidebar({ ), - [mini, hasDrawerTransitions, isFullyExpanded] + [ + mini, + hasDrawerTransitions, + isFullyExpanded, + user.info.matrix_account_connected, + ] ); const getDrawerSharedSx = React.useCallback(