UNPKG

matrix-react-sdk

Version:
127 lines (115 loc) 4.88 kB
/* Copyright 2024 New Vector Ltd. Copyright 2017-2021 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ import { SyncState } from "matrix-js-sdk/src/matrix"; import { MINIMUM_MATRIX_VERSION, SUPPORTED_MATRIX_VERSIONS } from "matrix-js-sdk/src/version-support"; import { logger } from "matrix-js-sdk/src/logger"; import { Action } from "../dispatcher/actions"; import dis from "../dispatcher/dispatcher"; import { ActionPayload } from "../dispatcher/payloads"; import { DoAfterSyncPreparedPayload } from "../dispatcher/payloads/DoAfterSyncPreparedPayload"; import { AsyncStore } from "./AsyncStore"; import { MatrixClientPeg } from "../MatrixClientPeg"; import ToastStore from "./ToastStore"; import { _t } from "../languageHandler"; import SdkConfig from "../SdkConfig"; import GenericToast from "../components/views/toasts/GenericToast"; interface IState { deferredAction: ActionPayload | null; } const INITIAL_STATE: IState = { deferredAction: null, }; /** * A class for storing application state to do with authentication. This is a simple * store that listens for actions and updates its state accordingly, informing any * listeners (views) of state changes. */ class LifecycleStore extends AsyncStore<IState> { public constructor() { super(dis, INITIAL_STATE); } protected onDispatch(payload: ActionPayload | DoAfterSyncPreparedPayload<ActionPayload>): void { switch (payload.action) { case Action.DoAfterSyncPrepared: this.updateState({ deferredAction: payload.deferred_action, }); break; case "cancel_after_sync_prepared": this.updateState({ deferredAction: null, }); break; case "MatrixActions.sync": { if (payload.state === SyncState.Syncing && payload.prevState !== SyncState.Syncing) { // We've reconnected to the server: update server version support // This is async but we don't care about the result, so just fire & forget. checkServerVersions(); } if (payload.state !== "PREPARED") { break; } if (!this.state.deferredAction) break; const deferredAction = Object.assign({}, this.state.deferredAction); this.updateState({ deferredAction: null, }); dis.dispatch(deferredAction); break; } case "on_client_not_viable": case Action.OnLoggedOut: this.reset(); break; } } } async function checkServerVersions(): Promise<void> { try { const client = MatrixClientPeg.get(); if (!client) return; for (const version of SUPPORTED_MATRIX_VERSIONS) { // Check if the server supports this spec version. (`isVersionSupported` caches the response, so this loop will // only make a single HTTP request). // Note that although we do this on a reconnect, we cache the server's versions in memory // indefinitely, so it will only ever trigger the toast on the first connection after a fresh // restart of the client. if (await client.isVersionSupported(version)) { // we found a compatible spec version return; } } // This is retrospective doc having debated about the exactly what this toast is for, but // our guess is that it's a nudge to update, or ask your HS admin to update your Homeserver // after a new version of Element has come out, in a way that doesn't lock you out of all // your messages. const toastKey = "LEGACY_SERVER"; ToastStore.sharedInstance().addOrReplaceToast({ key: toastKey, title: _t("unsupported_server_title"), props: { description: _t("unsupported_server_description", { version: MINIMUM_MATRIX_VERSION, brand: SdkConfig.get().brand, }), primaryLabel: _t("action|ok"), onPrimaryClick: () => { ToastStore.sharedInstance().dismissToast(toastKey); }, }, component: GenericToast, priority: 98, }); } catch (e) { logger.warn("Failed to check server versions", e); } } let singletonLifecycleStore: LifecycleStore | null = null; if (!singletonLifecycleStore) { singletonLifecycleStore = new LifecycleStore(); } export default singletonLifecycleStore!;