From 00fa334d42f20c210d00a2b8287c1a4f691c287c Mon Sep 17 00:00:00 2001 From: thislight Date: Mon, 15 Jul 2024 13:59:10 +0800 Subject: [PATCH] rewrite client providing & fix sign in redirect --- src/App.tsx | 53 +++++++++++++++++++++++++----- src/accounts/stores.ts | 15 --------- src/masto/acct.ts | 6 ++-- src/masto/clients.ts | 73 +++++++++++++++++++++++++++++++----------- src/timelines/Home.tsx | 12 +++---- 5 files changed, 106 insertions(+), 53 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index c5fa9fd..4a36e23 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,27 @@ import { Route, Router } from "@solidjs/router"; import { ThemeProvider } from "@suid/material"; -import { Component, lazy } from "solid-js"; +import { + Component, + createRenderEffect, + createSignal, + ErrorBoundary, + lazy, +} from "solid-js"; import { useRootTheme } from "./material/mui.js"; -import "./App.css" +import { + Provider as ClientProvider, + createMastoClientFor, + type Session, +} from "./masto/clients.js"; +import "./App.css"; +import { $accounts } from "./accounts/stores.js"; +import { useStore } from "@nanostores/solid"; const AccountSignIn = lazy(() => import("./accounts/SignIn.js")); -const AccountMastodonOAuth2Callback = lazy(() => import("./accounts/MastodonOAuth2Callback.js")) -const TimelineHome = lazy(() => import("./timelines/Home.js")) +const AccountMastodonOAuth2Callback = lazy( + () => import("./accounts/MastodonOAuth2Callback.js"), +); +const TimelineHome = lazy(() => import("./timelines/Home.js")); const Routing: Component = () => { return ( @@ -14,7 +29,10 @@ const Routing: Component = () => { - + ); @@ -22,10 +40,29 @@ const Routing: Component = () => { const App: Component = () => { const theme = useRootTheme(); + const accts = useStore($accounts); + const clientStore = createSignal([]); + + createRenderEffect(() => { + const [, setClients] = clientStore; + setClients( + accts().map((x) => ({ account: x, client: createMastoClientFor(x) })), + ); + }); + return ( - - - + { + console.error(err); + return <>; + }} + > + + + + + + ); }; diff --git a/src/accounts/stores.ts b/src/accounts/stores.ts index 96c6499..fe408f9 100644 --- a/src/accounts/stores.ts +++ b/src/accounts/stores.ts @@ -1,9 +1,6 @@ import { persistentAtom } from "@nanostores/persistent"; -import { useStore } from "@nanostores/solid"; -import { useNavigate } from "@solidjs/router"; import { createOAuthAPIClient, createRestAPIClient } from "masto"; import { action } from "nanostores"; -import { createRenderEffect } from "solid-js"; export type Account = { site: string; @@ -175,15 +172,3 @@ export const getOrRegisterApp = action( return all[site]; }, ); - -export function useAccts() { - const accts = useStore($accounts); - const naviagte = useNavigate(); - - createRenderEffect(() => { - if (accts().length > 0) return; - naviagte("/accounts/sign-in"); - }); - - return accts; -} diff --git a/src/masto/acct.ts b/src/masto/acct.ts index 51c8ea2..eafd297 100644 --- a/src/masto/acct.ts +++ b/src/masto/acct.ts @@ -1,9 +1,7 @@ import { Accessor, createResource } from "solid-js"; -import { Account } from "../accounts/stores"; -import { useMastoClientFor } from "./clients"; +import type { mastodon } from "masto"; -export function useAcctProfile(account: Accessor) { - const client = useMastoClientFor(account) +export function useAcctProfile(client: Accessor) { return createResource(client, (client) => { return client.v1.accounts.verifyCredentials() }, { diff --git a/src/masto/clients.ts b/src/masto/clients.ts index 3ff1be6..9e71b8c 100644 --- a/src/masto/clients.ts +++ b/src/masto/clients.ts @@ -1,41 +1,78 @@ -import { Accessor, createMemo, createResource } from "solid-js"; +import { + Accessor, + createContext, + createRenderEffect, + createResource, + Signal, + useContext, +} from "solid-js"; import { Account } from "../accounts/stores"; import { createRestAPIClient, mastodon } from "masto"; +import { useLocation, useNavigate } from "@solidjs/router"; -const restfulCache: Record = {} +const restfulCache: Record = {}; export function createMastoClientFor(account: Account) { - const cacheKey = [account.site, account.accessToken].join('') - const cache = restfulCache[cacheKey] + const cacheKey = [account.site, account.accessToken].join(""); + const cache = restfulCache[cacheKey]; if (cache) return cache; const client = createRestAPIClient({ url: account.site, accessToken: account.accessToken, - }) - restfulCache[cacheKey] = client + }); + restfulCache[cacheKey] = client; - return client -} - -export function useMastoClientFor(account: Accessor) { - return createMemo(() => createMastoClientFor(account())) + return client; } export function createUnauthorizedClient(site: string) { - const cache = restfulCache[site] + const cache = restfulCache[site]; if (cache) return cache; const client = createRestAPIClient({ - url: site - }) - restfulCache[site] = client + url: site, + }); + restfulCache[site] = client; - return client + return client; } export function useInstance(client: Accessor) { return createResource(client, async (client) => { - return await client.v2.instance.fetch() - }) + return await client.v2.instance.fetch(); + }); +} + +export type Session = { + account: Account; + client: mastodon.rest.Client; +}; + +const Context = /* @__PURE__ */ createContext>(); + +export const Provider = Context.Provider; + +export function useSessions() { + const [sessions] = useSessionsRw(); + const navigate = useNavigate(); + const location = useLocation(); + + createRenderEffect(() => { + if (sessions().length > 0) return; + navigate( + "/accounts/sign-in?back=" + encodeURIComponent(location.pathname), + { replace: true }, + ); + }); + + return sessions; +} + +export function useSessionsRw() { + const store = useContext(Context); + if (!store) { + throw new TypeError("sessions are not provided"); + } + return store; } diff --git a/src/timelines/Home.tsx b/src/timelines/Home.tsx index 696c0a2..16fa2e1 100644 --- a/src/timelines/Home.tsx +++ b/src/timelines/Home.tsx @@ -3,15 +3,12 @@ import { For, onCleanup, createSignal, - createEffect, Show, untrack, onMount, } from "solid-js"; -import { $accounts, useAccts } from "../accounts/stores"; import { useDocumentTitle } from "../utils"; -import { useStore } from "@nanostores/solid"; -import { useMastoClientFor } from "../masto/clients"; +import { useSessions } from "../masto/clients"; import { type mastodon } from "masto"; import Scaffold from "../material/Scaffold"; import { @@ -24,7 +21,6 @@ import { MenuItem, Switch, Toolbar, - Typography, } from "@suid/material"; import { css } from "solid-styled"; import { TimeSourceProvider, createTimeSource } from "../platform/timesrc"; @@ -152,11 +148,11 @@ const TimelinePanel: Component<{ const Home: Component = () => { let panelList: HTMLDivElement; useDocumentTitle("Timelines"); - const accounts = useAccts(); const now = createTimeSource(); - const client = useMastoClientFor(() => accounts()[0]); - const [profile] = useAcctProfile(() => accounts()[0]); + const sessions = useSessions(); + const client = () => sessions()[0].client; + const [profile] = useAcctProfile(client); const [panelOffset, setPanelOffset] = createSignal(0); const [prefetching, setPrefetching] = createSignal(true);