feat: implement useClient from client controller

This commit is contained in:
Paul Makles
2022-06-28 19:59:58 +01:00
parent ce88fab714
commit 5f2311b09c
72 changed files with 330 additions and 457 deletions

View File

@@ -1,11 +1,17 @@
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
import type { Nullable } from "revolt.js";
import { Client, Nullable } from "revolt.js";
import Auth from "../../mobx/stores/Auth";
import { modalController } from "../modals/ModalController";
import Session from "./Session";
class ClientController {
/**
* API client
*/
private apiClient: Client;
/**
* Map of user IDs to sessions
*/
@@ -17,10 +23,19 @@ class ClientController {
private current: Nullable<string>;
constructor() {
this.apiClient = new Client({
apiURL: import.meta.env.VITE_API_URL,
});
this.sessions = new ObservableMap();
this.current = null;
makeAutoObservable(this);
this.logoutCurrent = this.logoutCurrent.bind(this);
// Inject globally
(window as any).clientController = this;
}
/**
@@ -29,12 +44,23 @@ class ClientController {
*/
@action hydrate(auth: Auth) {
for (const entry of auth.getAccounts()) {
const user_id = entry.session.user_id!;
const session = new Session();
this.sessions.set(entry.session._id!, session);
session.emit({
action: "LOGIN",
session: entry.session,
});
this.sessions.set(user_id, session);
session
.emit({
action: "LOGIN",
session: entry.session,
})
.catch((error) => {
if (error === "Forbidden" || error === "Unauthorized") {
this.sessions.delete(user_id);
auth.removeSession(user_id);
modalController.push({ type: "signed_out" });
}
});
}
this.current = this.sessions.keys().next().value ?? null;
@@ -44,6 +70,14 @@ class ClientController {
return this.sessions.get(this.current!);
}
@computed getAnonymousClient() {
return this.apiClient;
}
@computed getAvailableClient() {
return this.getActiveSession()?.client ?? this.apiClient;
}
@computed isLoggedIn() {
return this.current === null;
}
@@ -59,6 +93,41 @@ class ClientController {
session.destroy();
}
}
@action logoutCurrent() {
if (this.current) {
this.logout(this.current);
}
}
@action switchAccount(user_id: string) {
this.current = user_id;
}
}
export const clientController = new ClientController();
/**
* Get the currently active session.
* @returns Session
*/
export function useSession() {
return clientController.getActiveSession();
}
/**
* Get the currently active client or an unauthorised
* client for API requests, whichever is available.
* @returns Revolt.js Client
*/
export function useClient() {
return clientController.getAvailableClient();
}
/**
* Get unauthorised client for API requests.
* @returns Revolt.js Client
*/
export function useApi() {
return clientController.getAnonymousClient().api;
}

View File

@@ -20,6 +20,7 @@ type Transition =
export default class Session {
state: State = window.navigator.onLine ? "Ready" : "Offline";
user_id: string | null = null;
client: Client | null = null;
constructor() {
@@ -83,6 +84,7 @@ export default class Session {
private destroyClient() {
this.client!.removeAllListeners();
this.user_id = null;
this.client = null;
}
@@ -101,7 +103,7 @@ export default class Session {
}
@action async emit(data: Transition) {
console.info("Handle event:", data);
console.info(`[FSM ${this.user_id ?? "Anonymous"}]`, data);
switch (data.action) {
// Login with session
@@ -112,6 +114,7 @@ export default class Session {
try {
await this.client!.useExistingSession(data.session);
this.user_id = this.client!.user!._id;
} catch (err) {
this.state = "Ready";
throw err;

View File

@@ -1,18 +1,16 @@
import { SubmitHandler, useForm } from "react-hook-form";
import { Text } from "preact-i18n";
import { useContext, useState } from "preact/hooks";
import { useState } from "preact/hooks";
import { Category, Error, Modal } from "@revoltchat/ui";
import { noopTrue } from "../../../lib/js";
import { useApplicationState } from "../../../mobx/State";
import { AppContext } from "../../../context/revoltjs/RevoltClient";
import { takeError } from "../../../context/revoltjs/util";
import FormField from "../../../pages/login/FormField";
import { useClient } from "../../client/ClientController";
import { ModalProps } from "../types";
interface FormInputs {
@@ -30,7 +28,7 @@ export default function ModifyAccount({
field,
...props
}: ModalProps<"modify_account">) {
const client = useApplicationState().client!;
const client = useClient();
const [processing, setProcessing] = useState(false);
const { handleSubmit, register, errors } = useForm<FormInputs>();
const [error, setError] = useState<string | undefined>(undefined);