chore: deprecate RevoltClient context

This commit is contained in:
Paul Makles 2022-06-29 16:02:35 +01:00
parent 0e86f19da2
commit 0261fec676
13 changed files with 118 additions and 108 deletions

View file

@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
import { useParams } from "react-router-dom";
import { Channel, Server, User, API } from "revolt.js";
import { useEffect, useState } from "preact/hooks";
import { useEffect, useLayoutEffect, useState } from "preact/hooks";
import {
useSession,

View file

@ -8,12 +8,12 @@ import { Preloader, UIProvider } from "@revoltchat/ui";
import { hydrateState } from "../mobx/State";
import Binder from "../controllers/client/jsx/Binder";
import ModalRenderer from "../controllers/modals/ModalRenderer";
import Locale from "./Locale";
import Theme from "./Theme";
import { history } from "./history";
import Intermediate from "./intermediate/Intermediate";
import Client from "./revoltjs/RevoltClient";
import SyncManager from "./revoltjs/SyncManager";
const uiContext = {
@ -41,10 +41,10 @@ export default function Context({ children }: { children: Children }) {
<UIProvider value={uiContext}>
<Locale>
<Intermediate>
<Client>
<Binder>
{children}
<SyncManager />
</Client>
{<SyncManager />}
</Binder>
</Intermediate>
<ModalRenderer />
</Locale>

View file

@ -1,6 +1,7 @@
import { observer } from "mobx-react-lite";
import { Redirect } from "react-router-dom";
import { useSession } from "../../controllers/client/ClientController";
import { clientController } from "../../controllers/client/ClientController";
interface Props {
auth?: boolean;
@ -9,16 +10,17 @@ interface Props {
children: Children;
}
export const CheckAuth = (props: Props) => {
const session = useSession();
export const CheckAuth = observer((props: Props) => {
const loggedIn = clientController.isLoggedIn();
if (props.auth && !session?.ready) {
// Redirect if logged out on authenticated page or vice-versa.
if (props.auth && !loggedIn) {
if (props.blockRender) return null;
return <Redirect to="/login" />;
} else if (!props.auth && session?.ready) {
} else if (!props.auth && loggedIn) {
if (props.blockRender) return null;
return <Redirect to="/" />;
}
return <>{props.children}</>;
};
});

View file

@ -1,27 +0,0 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { observer } from "mobx-react-lite";
import { useEffect } from "preact/hooks";
import { Preloader } from "@revoltchat/ui";
import { useApplicationState } from "../../mobx/State";
import { clientController } from "../../controllers/client/ClientController";
type Props = {
children: Children;
};
export default observer(({ children }: Props) => {
const session = clientController.getActiveSession();
if (session) {
if (!session.ready) return <Preloader type="spinner" />;
const client = session.client!;
const state = useApplicationState();
useEffect(() => state.registerListeners(client), [state, client]);
}
return <>{children}</>;
});

View file

@ -58,8 +58,9 @@ class ClientController {
}
@action pickNextSession() {
this.current =
this.current ?? this.sessions.keys().next().value ?? null;
this.switchAccount(
this.current ?? this.sessions.keys().next().value ?? null,
);
}
/**
@ -82,6 +83,15 @@ class ClientController {
return this.sessions.get(this.current!);
}
/**
* Get the currently ready client
* @returns Ready Client
*/
@computed getReadyClient() {
const session = this.getActiveSession();
return session && session.ready ? session.client! : undefined;
}
/**
* Get an unauthenticated instance of the Revolt.js Client
* @returns API Client
@ -111,7 +121,15 @@ class ClientController {
* @returns Whether we are logged in
*/
@computed isLoggedIn() {
return this.current === null;
return this.current !== null;
}
/**
* Check whether we are currently ready
* @returns Whether we are ready to render
*/
@computed isReady() {
return this.getActiveSession()?.ready;
}
/**
@ -127,6 +145,7 @@ class ClientController {
const session = new Session();
this.sessions.set(user_id, session);
this.pickNextSession();
session
.emit({
@ -144,8 +163,6 @@ class ClientController {
session.destroy();
}
});
this.pickNextSession();
}
/**

View file

@ -270,6 +270,6 @@ export default class Session {
* @returns Boolean
*/
@computed get ready() {
return this.client?.user;
return !!this.client?.user;
}
}

View file

@ -0,0 +1,27 @@
import { observer } from "mobx-react-lite";
import { useEffect } from "preact/hooks";
import { Preloader } from "@revoltchat/ui";
import { state } from "../../../mobx/State";
import { clientController } from "../ClientController";
/**
* Prevent render until the client is ready to display.
* Also binds listeners from state to the current client.
*/
const Binder: React.FC = ({ children }) => {
const client = clientController.getReadyClient();
useEffect(() => state.registerListeners(client!), [client]);
// Block render if client is getting ready to work.
if (clientController.isLoggedIn() && !clientController.isReady()) {
return <Preloader type="spinner" />;
}
return <>{children}</>;
};
export default observer(Binder);

View file

@ -1,8 +1,6 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { action, makeAutoObservable } from "mobx";
import { Channel } from "revolt.js";
import { Message } from "revolt.js";
import { Nullable } from "revolt.js";
import { Channel, Message, Nullable } from "revolt.js";
import { SimpleRenderer } from "./simple/SimpleRenderer";
import { RendererRoutines, ScrollState } from "./types";

View file

@ -47,8 +47,6 @@ export default class State {
private persistent: [string, Persistent<unknown>][] = [];
private disabled: Set<string> = new Set();
client?: Client;
/**
* Construct new State.
*/
@ -67,14 +65,10 @@ export default class State {
this.plugins = new Plugins(this);
this.ordering = new Ordering(this);
makeAutoObservable(this, {
client: false,
});
makeAutoObservable(this);
this.register();
this.setDisabled = this.setDisabled.bind(this);
this.client = undefined;
}
/**
@ -138,11 +132,11 @@ 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.client = client;
this.plugins.onClient(client);
// Register message listener for clearing queue.
this.client.addListener("message", this.queue.onMessage);
// this.client.addListener("message", this.queue.onMessage);
}
// Register all the listeners required for saving and syncing state.
@ -228,13 +222,13 @@ 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);
}
// Stop exposing the client.
this.client = undefined;
this.client = undefined;*/
// Wipe all listeners.
listeners.forEach((x) => x());

View file

@ -2,6 +2,7 @@ import { action, computed, makeAutoObservable } from "mobx";
import { reorder } from "@revoltchat/ui";
import { clientController } from "../../controllers/client/ClientController";
import State from "../State";
import Persistent from "../interfaces/Persistent";
import Store from "../interfaces/Store";
@ -63,18 +64,19 @@ export default class Ordering implements Store, Persistent<Data>, Syncable {
* All known servers with ordering applied
*/
@computed get orderedServers() {
const known = new Set(this.state.client?.servers.keys() ?? []);
const client = clientController.getReadyClient();
const known = new Set(client?.servers.keys() ?? []);
const ordered = [...this.servers];
const out = [];
for (const id of ordered) {
if (known.delete(id)) {
out.push(this.state.client!.servers.get(id)!);
out.push(client!.servers.get(id)!);
}
}
for (const id of known) {
out.push(this.state.client!.servers.get(id)!);
out.push(client!.servers.get(id)!);
}
return out;

View file

@ -59,7 +59,7 @@ type Plugin = {
type Instance = {
format: 1;
onClient?: (client: Client) => {};
onClient?: (client: Client) => void;
onUnload?: () => void;
};
@ -124,7 +124,7 @@ export default class Plugins implements Store, Persistent<Data> {
* @param id Plugin Id
*/
@computed get(namespace: string, id: string) {
return this.plugins.get(`${namespace }/${ id}`);
return this.plugins.get(`${namespace}/${id}`);
}
/**
@ -133,7 +133,7 @@ export default class Plugins implements Store, Persistent<Data> {
* @returns Plugin Instance
*/
private getInstance(plugin: Pick<Plugin, "namespace" | "id">) {
return this.instances.get(`${plugin.namespace }/${ plugin.id}`);
return this.instances.get(`${plugin.namespace}/${plugin.id}`);
}
/**
@ -159,7 +159,7 @@ export default class Plugins implements Store, Persistent<Data> {
this.unload(plugin.namespace, plugin.id);
}
this.plugins.set(`${plugin.namespace }/${ plugin.id}`, plugin);
this.plugins.set(`${plugin.namespace}/${plugin.id}`, plugin);
if (typeof plugin.enabled === "undefined" || plugin) {
this.load(plugin.namespace, plugin.id);
@ -173,7 +173,7 @@ export default class Plugins implements Store, Persistent<Data> {
*/
remove(namespace: string, id: string) {
this.unload(namespace, id);
this.plugins.delete(`${namespace }/${ id}`);
this.plugins.delete(`${namespace}/${id}`);
}
/**
@ -186,7 +186,7 @@ export default class Plugins implements Store, Persistent<Data> {
if (!plugin) throw "Unknown plugin!";
try {
const ns = `${plugin.namespace }/${ plugin.id}`;
const ns = `${plugin.namespace}/${plugin.id}`;
const instance: Instance = eval(plugin.entrypoint)();
this.instances.set(ns, {
@ -198,10 +198,6 @@ export default class Plugins implements Store, Persistent<Data> {
...plugin,
enabled: true,
});
if (this.state.client) {
instance.onClient?.(this.state.client);
}
} catch (error) {
console.error(`Failed to load ${namespace}/${id}!`);
console.error(error);
@ -217,7 +213,7 @@ export default class Plugins implements Store, Persistent<Data> {
const plugin = this.get(namespace, id);
if (!plugin) throw "Unknown plugin!";
const ns = `${plugin.namespace }/${ plugin.id}`;
const ns = `${plugin.namespace}/${plugin.id}`;
const loaded = this.getInstance(plugin);
if (loaded) {
loaded.onUnload?.();

View file

@ -76,12 +76,6 @@ const Routes = styled.div.attrs({ "data-component": "routes" })<{
background: var(--primary-background);
/*background-color: rgba(
var(--primary-background-rgb),
max(var(--min-opacity), 0.75)
);*/
//backdrop-filter: blur(10px);
${() =>
isTouchscreenDevice &&
css`

View file

@ -15,44 +15,51 @@ const Login = lazy(() => import("./login/Login"));
const ConfirmDelete = lazy(() => import("./login/ConfirmDelete"));
const RevoltApp = lazy(() => import("./RevoltApp"));
const LoadSuspense: React.FC = ({ children }) => (
// @ts-expect-error Typing issue between Preact and Preact.
<Suspense fallback={<Preloader type="ring" />}>{children}</Suspense>
);
export function App() {
return (
<ErrorBoundary section="client">
<Context>
<Masks />
{/*
// @ts-expect-error typings mis-match between preact... and preact? */}
<Suspense fallback={<Preloader type="spinner" />}>
<Switch>
<Route path="/login/verify/:token">
<Switch>
<Route path="/login/verify/:token">
<Login />
</Route>
<Route path="/login/reset/:token">
<LoadSuspense>
<Login />
</Route>
<Route path="/login/reset/:token">
<Login />
</Route>
<Route path="/delete/:token">
</LoadSuspense>
</Route>
<Route path="/delete/:token">
<LoadSuspense>
<ConfirmDelete />
</Route>
<Route path="/invite/:code">
<CheckAuth blockRender>
<Invite />
</CheckAuth>
<CheckAuth auth blockRender>
<Invite />
</CheckAuth>
</Route>
<Route path="/login">
<CheckAuth>
<Login />
</CheckAuth>
</Route>
<Route path="/">
<CheckAuth auth>
</LoadSuspense>
</Route>
<Route path="/invite/:code">
<CheckAuth blockRender>
<Invite />
</CheckAuth>
<CheckAuth auth blockRender>
<Invite />
</CheckAuth>
</Route>
<Route path="/login">
<CheckAuth>
<Login />
</CheckAuth>
</Route>
<Route path="/">
<CheckAuth auth>
<LoadSuspense>
<RevoltApp />
</CheckAuth>
</Route>
</Switch>
</Suspense>
</LoadSuspense>
</CheckAuth>
</Route>
</Switch>
</Context>
</ErrorBoundary>
);