mirror of
https://github.com/revoltchat/revite.git
synced 2025-02-22 00:00:56 -05:00
chore: deprecate RevoltClient
context
This commit is contained in:
parent
0e86f19da2
commit
0261fec676
13 changed files with 118 additions and 108 deletions
|
@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { Channel, Server, User, API } from "revolt.js";
|
import { Channel, Server, User, API } from "revolt.js";
|
||||||
|
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useLayoutEffect, useState } from "preact/hooks";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useSession,
|
useSession,
|
||||||
|
|
|
@ -8,12 +8,12 @@ import { Preloader, UIProvider } from "@revoltchat/ui";
|
||||||
|
|
||||||
import { hydrateState } from "../mobx/State";
|
import { hydrateState } from "../mobx/State";
|
||||||
|
|
||||||
|
import Binder from "../controllers/client/jsx/Binder";
|
||||||
import ModalRenderer from "../controllers/modals/ModalRenderer";
|
import ModalRenderer from "../controllers/modals/ModalRenderer";
|
||||||
import Locale from "./Locale";
|
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 Client from "./revoltjs/RevoltClient";
|
|
||||||
import SyncManager from "./revoltjs/SyncManager";
|
import SyncManager from "./revoltjs/SyncManager";
|
||||||
|
|
||||||
const uiContext = {
|
const uiContext = {
|
||||||
|
@ -41,10 +41,10 @@ export default function Context({ children }: { children: Children }) {
|
||||||
<UIProvider value={uiContext}>
|
<UIProvider value={uiContext}>
|
||||||
<Locale>
|
<Locale>
|
||||||
<Intermediate>
|
<Intermediate>
|
||||||
<Client>
|
<Binder>
|
||||||
{children}
|
{children}
|
||||||
<SyncManager />
|
{<SyncManager />}
|
||||||
</Client>
|
</Binder>
|
||||||
</Intermediate>
|
</Intermediate>
|
||||||
<ModalRenderer />
|
<ModalRenderer />
|
||||||
</Locale>
|
</Locale>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
import { Redirect } from "react-router-dom";
|
import { Redirect } from "react-router-dom";
|
||||||
|
|
||||||
import { useSession } from "../../controllers/client/ClientController";
|
import { clientController } from "../../controllers/client/ClientController";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
auth?: boolean;
|
auth?: boolean;
|
||||||
|
@ -9,16 +10,17 @@ interface Props {
|
||||||
children: Children;
|
children: Children;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CheckAuth = (props: Props) => {
|
export const CheckAuth = observer((props: Props) => {
|
||||||
const session = useSession();
|
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;
|
if (props.blockRender) return null;
|
||||||
return <Redirect to="/login" />;
|
return <Redirect to="/login" />;
|
||||||
} else if (!props.auth && session?.ready) {
|
} else if (!props.auth && loggedIn) {
|
||||||
if (props.blockRender) return null;
|
if (props.blockRender) return null;
|
||||||
return <Redirect to="/" />;
|
return <Redirect to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>{props.children}</>;
|
return <>{props.children}</>;
|
||||||
};
|
});
|
||||||
|
|
|
@ -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}</>;
|
|
||||||
});
|
|
|
@ -58,8 +58,9 @@ class ClientController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@action pickNextSession() {
|
@action pickNextSession() {
|
||||||
this.current =
|
this.switchAccount(
|
||||||
this.current ?? this.sessions.keys().next().value ?? null;
|
this.current ?? this.sessions.keys().next().value ?? null,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,6 +83,15 @@ class ClientController {
|
||||||
return this.sessions.get(this.current!);
|
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
|
* Get an unauthenticated instance of the Revolt.js Client
|
||||||
* @returns API Client
|
* @returns API Client
|
||||||
|
@ -111,7 +121,15 @@ class ClientController {
|
||||||
* @returns Whether we are logged in
|
* @returns Whether we are logged in
|
||||||
*/
|
*/
|
||||||
@computed isLoggedIn() {
|
@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();
|
const session = new Session();
|
||||||
this.sessions.set(user_id, session);
|
this.sessions.set(user_id, session);
|
||||||
|
this.pickNextSession();
|
||||||
|
|
||||||
session
|
session
|
||||||
.emit({
|
.emit({
|
||||||
|
@ -144,8 +163,6 @@ class ClientController {
|
||||||
session.destroy();
|
session.destroy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.pickNextSession();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -270,6 +270,6 @@ export default class Session {
|
||||||
* @returns Boolean
|
* @returns Boolean
|
||||||
*/
|
*/
|
||||||
@computed get ready() {
|
@computed get ready() {
|
||||||
return this.client?.user;
|
return !!this.client?.user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
src/controllers/client/jsx/Binder.tsx
Normal file
27
src/controllers/client/jsx/Binder.tsx
Normal 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);
|
|
@ -1,8 +1,6 @@
|
||||||
/* eslint-disable react-hooks/rules-of-hooks */
|
/* eslint-disable react-hooks/rules-of-hooks */
|
||||||
import { action, makeAutoObservable } from "mobx";
|
import { action, makeAutoObservable } from "mobx";
|
||||||
import { Channel } from "revolt.js";
|
import { Channel, Message, Nullable } from "revolt.js";
|
||||||
import { Message } from "revolt.js";
|
|
||||||
import { Nullable } from "revolt.js";
|
|
||||||
|
|
||||||
import { SimpleRenderer } from "./simple/SimpleRenderer";
|
import { SimpleRenderer } from "./simple/SimpleRenderer";
|
||||||
import { RendererRoutines, ScrollState } from "./types";
|
import { RendererRoutines, ScrollState } from "./types";
|
||||||
|
|
|
@ -47,8 +47,6 @@ export default class State {
|
||||||
private persistent: [string, Persistent<unknown>][] = [];
|
private persistent: [string, Persistent<unknown>][] = [];
|
||||||
private disabled: Set<string> = new Set();
|
private disabled: Set<string> = new Set();
|
||||||
|
|
||||||
client?: Client;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct new State.
|
* Construct new State.
|
||||||
*/
|
*/
|
||||||
|
@ -67,14 +65,10 @@ export default class State {
|
||||||
this.plugins = new Plugins(this);
|
this.plugins = new Plugins(this);
|
||||||
this.ordering = new Ordering(this);
|
this.ordering = new Ordering(this);
|
||||||
|
|
||||||
makeAutoObservable(this, {
|
makeAutoObservable(this);
|
||||||
client: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.register();
|
this.register();
|
||||||
this.setDisabled = this.setDisabled.bind(this);
|
this.setDisabled = this.setDisabled.bind(this);
|
||||||
|
|
||||||
this.client = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,11 +132,11 @@ 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.client = client;
|
||||||
this.plugins.onClient(client);
|
this.plugins.onClient(client);
|
||||||
|
|
||||||
// Register message listener for clearing queue.
|
// 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.
|
// Register all the listeners required for saving and syncing state.
|
||||||
|
@ -228,13 +222,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop exposing the client.
|
// Stop exposing the client.
|
||||||
this.client = undefined;
|
this.client = undefined;*/
|
||||||
|
|
||||||
// Wipe all listeners.
|
// Wipe all listeners.
|
||||||
listeners.forEach((x) => x());
|
listeners.forEach((x) => x());
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { action, computed, makeAutoObservable } from "mobx";
|
||||||
|
|
||||||
import { reorder } from "@revoltchat/ui";
|
import { reorder } from "@revoltchat/ui";
|
||||||
|
|
||||||
|
import { clientController } from "../../controllers/client/ClientController";
|
||||||
import State from "../State";
|
import State from "../State";
|
||||||
import Persistent from "../interfaces/Persistent";
|
import Persistent from "../interfaces/Persistent";
|
||||||
import Store from "../interfaces/Store";
|
import Store from "../interfaces/Store";
|
||||||
|
@ -63,18 +64,19 @@ export default class Ordering implements Store, Persistent<Data>, Syncable {
|
||||||
* All known servers with ordering applied
|
* All known servers with ordering applied
|
||||||
*/
|
*/
|
||||||
@computed get orderedServers() {
|
@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 ordered = [...this.servers];
|
||||||
|
|
||||||
const out = [];
|
const out = [];
|
||||||
for (const id of ordered) {
|
for (const id of ordered) {
|
||||||
if (known.delete(id)) {
|
if (known.delete(id)) {
|
||||||
out.push(this.state.client!.servers.get(id)!);
|
out.push(client!.servers.get(id)!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const id of known) {
|
for (const id of known) {
|
||||||
out.push(this.state.client!.servers.get(id)!);
|
out.push(client!.servers.get(id)!);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
|
@ -59,7 +59,7 @@ type Plugin = {
|
||||||
|
|
||||||
type Instance = {
|
type Instance = {
|
||||||
format: 1;
|
format: 1;
|
||||||
onClient?: (client: Client) => {};
|
onClient?: (client: Client) => void;
|
||||||
onUnload?: () => void;
|
onUnload?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ export default class Plugins implements Store, Persistent<Data> {
|
||||||
* @param id Plugin Id
|
* @param id Plugin Id
|
||||||
*/
|
*/
|
||||||
@computed get(namespace: string, id: string) {
|
@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
|
* @returns Plugin Instance
|
||||||
*/
|
*/
|
||||||
private getInstance(plugin: Pick<Plugin, "namespace" | "id">) {
|
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.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) {
|
if (typeof plugin.enabled === "undefined" || plugin) {
|
||||||
this.load(plugin.namespace, plugin.id);
|
this.load(plugin.namespace, plugin.id);
|
||||||
|
@ -173,7 +173,7 @@ export default class Plugins implements Store, Persistent<Data> {
|
||||||
*/
|
*/
|
||||||
remove(namespace: string, id: string) {
|
remove(namespace: string, id: string) {
|
||||||
this.unload(namespace, id);
|
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!";
|
if (!plugin) throw "Unknown plugin!";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ns = `${plugin.namespace }/${ plugin.id}`;
|
const ns = `${plugin.namespace}/${plugin.id}`;
|
||||||
|
|
||||||
const instance: Instance = eval(plugin.entrypoint)();
|
const instance: Instance = eval(plugin.entrypoint)();
|
||||||
this.instances.set(ns, {
|
this.instances.set(ns, {
|
||||||
|
@ -198,10 +198,6 @@ export default class Plugins implements Store, Persistent<Data> {
|
||||||
...plugin,
|
...plugin,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.state.client) {
|
|
||||||
instance.onClient?.(this.state.client);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to load ${namespace}/${id}!`);
|
console.error(`Failed to load ${namespace}/${id}!`);
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
@ -217,7 +213,7 @@ export default class Plugins implements Store, Persistent<Data> {
|
||||||
const plugin = this.get(namespace, id);
|
const plugin = this.get(namespace, id);
|
||||||
if (!plugin) throw "Unknown plugin!";
|
if (!plugin) throw "Unknown plugin!";
|
||||||
|
|
||||||
const ns = `${plugin.namespace }/${ plugin.id}`;
|
const ns = `${plugin.namespace}/${plugin.id}`;
|
||||||
const loaded = this.getInstance(plugin);
|
const loaded = this.getInstance(plugin);
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
loaded.onUnload?.();
|
loaded.onUnload?.();
|
||||||
|
|
|
@ -76,12 +76,6 @@ const Routes = styled.div.attrs({ "data-component": "routes" })<{
|
||||||
|
|
||||||
background: var(--primary-background);
|
background: var(--primary-background);
|
||||||
|
|
||||||
/*background-color: rgba(
|
|
||||||
var(--primary-background-rgb),
|
|
||||||
max(var(--min-opacity), 0.75)
|
|
||||||
);*/
|
|
||||||
//backdrop-filter: blur(10px);
|
|
||||||
|
|
||||||
${() =>
|
${() =>
|
||||||
isTouchscreenDevice &&
|
isTouchscreenDevice &&
|
||||||
css`
|
css`
|
||||||
|
|
|
@ -15,44 +15,51 @@ const Login = lazy(() => import("./login/Login"));
|
||||||
const ConfirmDelete = lazy(() => import("./login/ConfirmDelete"));
|
const ConfirmDelete = lazy(() => import("./login/ConfirmDelete"));
|
||||||
const RevoltApp = lazy(() => import("./RevoltApp"));
|
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() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary section="client">
|
<ErrorBoundary section="client">
|
||||||
<Context>
|
<Context>
|
||||||
<Masks />
|
<Masks />
|
||||||
{/*
|
<Switch>
|
||||||
// @ts-expect-error typings mis-match between preact... and preact? */}
|
<Route path="/login/verify/:token">
|
||||||
<Suspense fallback={<Preloader type="spinner" />}>
|
<Login />
|
||||||
<Switch>
|
</Route>
|
||||||
<Route path="/login/verify/:token">
|
<Route path="/login/reset/:token">
|
||||||
|
<LoadSuspense>
|
||||||
<Login />
|
<Login />
|
||||||
</Route>
|
</LoadSuspense>
|
||||||
<Route path="/login/reset/:token">
|
</Route>
|
||||||
<Login />
|
<Route path="/delete/:token">
|
||||||
</Route>
|
<LoadSuspense>
|
||||||
<Route path="/delete/:token">
|
|
||||||
<ConfirmDelete />
|
<ConfirmDelete />
|
||||||
</Route>
|
</LoadSuspense>
|
||||||
<Route path="/invite/:code">
|
</Route>
|
||||||
<CheckAuth blockRender>
|
<Route path="/invite/:code">
|
||||||
<Invite />
|
<CheckAuth blockRender>
|
||||||
</CheckAuth>
|
<Invite />
|
||||||
<CheckAuth auth blockRender>
|
</CheckAuth>
|
||||||
<Invite />
|
<CheckAuth auth blockRender>
|
||||||
</CheckAuth>
|
<Invite />
|
||||||
</Route>
|
</CheckAuth>
|
||||||
<Route path="/login">
|
</Route>
|
||||||
<CheckAuth>
|
<Route path="/login">
|
||||||
<Login />
|
<CheckAuth>
|
||||||
</CheckAuth>
|
<Login />
|
||||||
</Route>
|
</CheckAuth>
|
||||||
<Route path="/">
|
</Route>
|
||||||
<CheckAuth auth>
|
<Route path="/">
|
||||||
|
<CheckAuth auth>
|
||||||
|
<LoadSuspense>
|
||||||
<RevoltApp />
|
<RevoltApp />
|
||||||
</CheckAuth>
|
</LoadSuspense>
|
||||||
</Route>
|
</CheckAuth>
|
||||||
</Switch>
|
</Route>
|
||||||
</Suspense>
|
</Switch>
|
||||||
</Context>
|
</Context>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue