diff --git a/src/context/index.tsx b/src/context/index.tsx index 045e733e..51b0564f 100644 --- a/src/context/index.tsx +++ b/src/context/index.tsx @@ -6,7 +6,7 @@ import { useEffect, useState } from "preact/hooks"; import { Preloader, UIProvider } from "@revoltchat/ui"; -import { hydrateState } from "../mobx/State"; +import { state } from "../mobx/State"; import Binder from "../controllers/client/jsx/Binder"; import ModalRenderer from "../controllers/modals/ModalRenderer"; @@ -14,7 +14,6 @@ import Locale from "./Locale"; import Theme from "./Theme"; import { history } from "./history"; import Intermediate from "./intermediate/Intermediate"; -import SyncManager from "./revoltjs/SyncManager"; const uiContext = { Link, @@ -31,7 +30,7 @@ export default function Context({ children }: { children: Children }) { const [ready, setReady] = useState(false); useEffect(() => { - hydrateState().then(() => setReady(true)); + state.hydrate().then(() => setReady(true)); }, []); if (!ready) return ; @@ -42,7 +41,6 @@ export default function Context({ children }: { children: Children }) { {children} - diff --git a/src/context/revoltjs/SyncManager.tsx b/src/context/revoltjs/SyncManager.tsx deleted file mode 100644 index 5022a373..00000000 --- a/src/context/revoltjs/SyncManager.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/** - * This file monitors changes to settings and syncs them to the server. - */ -import { ClientboundNotification } from "revolt.js"; - -import { useEffect } from "preact/hooks"; - -import { reportError } from "../../lib/ErrorBoundary"; - -import { useApplicationState } from "../../mobx/State"; - -import { - useClient, - useSession, -} from "../../controllers/client/ClientController"; - -export default function SyncManager() { - const client = useClient(); - const session = useSession(); - const state = useApplicationState(); - - // Sync settings from Revolt. - useEffect(() => { - if (session?.ready) { - state.sync - .pull(session.client!) - .catch(console.error) - .finally(() => state.changelog.checkForUpdates()); - } - }, [session?.ready]); - - // Take data updates from Revolt. - useEffect(() => { - if (!client) return; - function onPacket(packet: ClientboundNotification) { - if (packet.type === "UserSettingsUpdate") { - try { - state.sync.apply(packet.update); - } catch (err) { - reportError(err as any, "failed_sync_apply"); - } - } - } - - client.addListener("packet", onPacket); - return () => client.removeListener("packet", onPacket); - }, [client]); - - return <>; -} diff --git a/src/lib/window.ts b/src/lib/window.ts index f1290106..7ee0ce3f 100644 --- a/src/lib/window.ts +++ b/src/lib/window.ts @@ -1,3 +1,17 @@ +/** + * Inject a key into the window's globals. + * @param key Key + * @param value Value + */ +export function injectWindow(key: string, value: any) { + (window as any)[key] = value; +} + +/** + * Inject a controller into the global controllers object. + * @param key Key + * @param value Value + */ export function injectController(key: string, value: any) { (window as any).controllers = { ...((window as any).controllers ?? {}), diff --git a/src/mobx/State.ts b/src/mobx/State.ts index bdc22d4f..b48d9162 100644 --- a/src/mobx/State.ts +++ b/src/mobx/State.ts @@ -1,8 +1,11 @@ // @ts-expect-error No typings. import stringify from "json-stringify-deterministic"; import localforage from "localforage"; -import { makeAutoObservable, reaction, runInAction } from "mobx"; -import { Client } from "revolt.js"; +import { action, makeAutoObservable, reaction, runInAction } from "mobx"; +import { Client, ClientboundNotification } from "revolt.js"; + +import { reportError } from "../lib/ErrorBoundary"; +import { injectWindow } from "../lib/window"; import { clientController } from "../controllers/client/ClientController"; import Persistent from "./interfaces/Persistent"; @@ -69,6 +72,10 @@ export default class State { this.register(); this.setDisabled = this.setDisabled.bind(this); + this.onPacket = this.onPacket.bind(this); + + // Inject into window + injectWindow("state", this); } /** @@ -125,6 +132,20 @@ export default class State { } } + /** + * Consume packets from the client. + * @param packet Inbound Packet + */ + @action onPacket(packet: ClientboundNotification) { + if (packet.type === "UserSettingsUpdate") { + try { + this.sync.apply(packet.update); + } catch (err) { + reportError(err as any, "failed_sync_apply"); + } + } + } + /** * Register reaction listeners for persistent data stores. * @returns Function to dispose of listeners @@ -132,11 +153,17 @@ export default class State { registerListeners(client?: Client) { // If a client is present currently, expose it and provide it to plugins. if (client) { - // this.client = client; - this.plugins.onClient(client); - // Register message listener for clearing queue. - // this.client.addListener("message", this.queue.onMessage); + client.addListener("message", this.queue.onMessage); + + // Register listener for incoming packets. + client.addListener("packet", this.onPacket); + + // Sync settings from remote server. + state.sync + .pull(client) + .catch(console.error) + .finally(() => state.changelog.checkForUpdates()); } // Register all the listeners required for saving and syncing state. @@ -222,14 +249,12 @@ export default class State { }); return () => { - /*// Remove any listeners attached to client. + // Remove any listeners attached to client. if (client) { client.removeListener("message", this.queue.onMessage); + client.removeListener("packet", this.onPacket); } - // Stop exposing the client. - this.client = undefined;*/ - // Wipe all listeners. listeners.forEach((x) => x()); }; @@ -282,13 +307,7 @@ export default class State { } } -export let state: State; - -export async function hydrateState() { - state = new State(); - (window as any).state = state; - await state.hydrate(); -} +export const state = new State(); /** * Get the application state diff --git a/src/mobx/stores/Plugins.ts b/src/mobx/stores/Plugins.ts index 711349e8..e6b3bbb3 100644 --- a/src/mobx/stores/Plugins.ts +++ b/src/mobx/stores/Plugins.ts @@ -41,7 +41,6 @@ type Plugin = { * ```typescript * function (state: State) { * return { - * onClient: (client: Client) => {}, * onUnload: () => {} * } * } @@ -59,7 +58,6 @@ type Plugin = { type Instance = { format: 1; - onClient?: (client: Client) => void; onUnload?: () => void; }; @@ -231,13 +229,4 @@ export default class Plugins implements Store, Persistent { localforage.removeItem("revite:plugins"); window.location.reload(); } - - /** - * Push client through to plugins - */ - onClient(client: Client) { - for (const instance of this.instances.values()) { - instance.onClient?.(client); - } - } }