chore(refactor): remove SyncManager

This commit is contained in:
Paul Makles 2022-06-29 16:41:26 +01:00
parent 1fcb3cedc1
commit 45692999bf
5 changed files with 52 additions and 82 deletions

View file

@ -6,7 +6,7 @@ import { useEffect, useState } from "preact/hooks";
import { Preloader, UIProvider } from "@revoltchat/ui"; import { Preloader, UIProvider } from "@revoltchat/ui";
import { hydrateState } from "../mobx/State"; import { state } from "../mobx/State";
import Binder from "../controllers/client/jsx/Binder"; import Binder from "../controllers/client/jsx/Binder";
import ModalRenderer from "../controllers/modals/ModalRenderer"; import ModalRenderer from "../controllers/modals/ModalRenderer";
@ -14,7 +14,6 @@ import Locale from "./Locale";
import Theme from "./Theme"; import Theme from "./Theme";
import { history } from "./history"; import { history } from "./history";
import Intermediate from "./intermediate/Intermediate"; import Intermediate from "./intermediate/Intermediate";
import SyncManager from "./revoltjs/SyncManager";
const uiContext = { const uiContext = {
Link, Link,
@ -31,7 +30,7 @@ export default function Context({ children }: { children: Children }) {
const [ready, setReady] = useState(false); const [ready, setReady] = useState(false);
useEffect(() => { useEffect(() => {
hydrateState().then(() => setReady(true)); state.hydrate().then(() => setReady(true));
}, []); }, []);
if (!ready) return <Preloader type="spinner" />; if (!ready) return <Preloader type="spinner" />;
@ -42,7 +41,6 @@ export default function Context({ children }: { children: Children }) {
<Locale> <Locale>
<Intermediate> <Intermediate>
{children} {children}
<SyncManager />
<Binder /> <Binder />
</Intermediate> </Intermediate>
<ModalRenderer /> <ModalRenderer />

View file

@ -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 <></>;
}

View file

@ -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) { export function injectController(key: string, value: any) {
(window as any).controllers = { (window as any).controllers = {
...((window as any).controllers ?? {}), ...((window as any).controllers ?? {}),

View file

@ -1,8 +1,11 @@
// @ts-expect-error No typings. // @ts-expect-error No typings.
import stringify from "json-stringify-deterministic"; import stringify from "json-stringify-deterministic";
import localforage from "localforage"; import localforage from "localforage";
import { makeAutoObservable, reaction, runInAction } from "mobx"; import { action, makeAutoObservable, reaction, runInAction } from "mobx";
import { Client } from "revolt.js"; import { Client, ClientboundNotification } from "revolt.js";
import { reportError } from "../lib/ErrorBoundary";
import { injectWindow } from "../lib/window";
import { clientController } from "../controllers/client/ClientController"; import { clientController } from "../controllers/client/ClientController";
import Persistent from "./interfaces/Persistent"; import Persistent from "./interfaces/Persistent";
@ -69,6 +72,10 @@ export default class State {
this.register(); this.register();
this.setDisabled = this.setDisabled.bind(this); 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. * Register reaction listeners for persistent data stores.
* @returns Function to dispose of listeners * @returns Function to dispose of listeners
@ -132,11 +153,17 @@ export default class State {
registerListeners(client?: Client) { registerListeners(client?: Client) {
// If a client is present currently, expose it and provide it to plugins. // If a client is present currently, expose it and provide it to plugins.
if (client) { if (client) {
// this.client = client;
this.plugins.onClient(client);
// Register message listener for clearing queue. // 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. // Register all the listeners required for saving and syncing state.
@ -222,14 +249,12 @@ export default class State {
}); });
return () => { return () => {
/*// Remove any listeners attached to client. // Remove any listeners attached to client.
if (client) { if (client) {
client.removeListener("message", this.queue.onMessage); client.removeListener("message", this.queue.onMessage);
client.removeListener("packet", this.onPacket);
} }
// Stop exposing the client.
this.client = undefined;*/
// Wipe all listeners. // Wipe all listeners.
listeners.forEach((x) => x()); listeners.forEach((x) => x());
}; };
@ -282,13 +307,7 @@ export default class State {
} }
} }
export let state: State; export const state = new State();
export async function hydrateState() {
state = new State();
(window as any).state = state;
await state.hydrate();
}
/** /**
* Get the application state * Get the application state

View file

@ -41,7 +41,6 @@ type Plugin = {
* ```typescript * ```typescript
* function (state: State) { * function (state: State) {
* return { * return {
* onClient: (client: Client) => {},
* onUnload: () => {} * onUnload: () => {}
* } * }
* } * }
@ -59,7 +58,6 @@ type Plugin = {
type Instance = { type Instance = {
format: 1; format: 1;
onClient?: (client: Client) => void;
onUnload?: () => void; onUnload?: () => void;
}; };
@ -231,13 +229,4 @@ export default class Plugins implements Store, Persistent<Data> {
localforage.removeItem("revite:plugins"); localforage.removeItem("revite:plugins");
window.location.reload(); window.location.reload();
} }
/**
* Push client through to plugins
*/
onClient(client: Client) {
for (const instance of this.instances.values()) {
instance.onClient?.(client);
}
}
} }