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);
- }
- }
}