From 5ea2eb711fb93a8399a8bd69f470acc060805726 Mon Sep 17 00:00:00 2001 From: Martti Malmi Date: Thu, 4 Jan 2024 15:15:46 +0200 Subject: [PATCH] move wasm and system out of index.tsx --- .../src/Element/Event/Create/NoteCreator.tsx | 2 +- .../src/Element/IrisAccount/IrisAccount.tsx | 2 +- packages/app/src/Element/PinPrompt.tsx | 3 +- .../src/Element/Trending/TrendingPosts.tsx | 2 +- packages/app/src/Pages/ZapPool.tsx | 2 +- packages/app/src/chat/nip24.ts | 3 +- packages/app/src/index.tsx | 140 +----------------- packages/app/src/system.ts | 90 +++++++++++ packages/app/src/wasm.ts | 44 ++++++ 9 files changed, 146 insertions(+), 142 deletions(-) create mode 100644 packages/app/src/system.ts create mode 100644 packages/app/src/wasm.ts diff --git a/packages/app/src/Element/Event/Create/NoteCreator.tsx b/packages/app/src/Element/Event/Create/NoteCreator.tsx index eb610206..42667362 100644 --- a/packages/app/src/Element/Event/Create/NoteCreator.tsx +++ b/packages/app/src/Element/Event/Create/NoteCreator.tsx @@ -15,7 +15,6 @@ import Note from "@/Element/Event/Note"; import { ClipboardEventHandler, DragEvent, useEffect } from "react"; import useLogin from "@/Hooks/useLogin"; -import { GetPowWorker } from "@/index"; import AsyncButton from "@/Element/Button/AsyncButton"; import { AsyncIcon } from "@/Element/Button/AsyncIcon"; import { fetchNip05Pubkey, unixNow } from "@snort/shared"; @@ -28,6 +27,7 @@ import { TrendingHashTagsLine } from "@/Element/Event/Create/TrendingHashTagsLin import { Toastore } from "@/Toaster"; import { OkResponseRow } from "./OkResponseRow"; import CloseButton from "@/Element/Button/CloseButton"; +import { GetPowWorker } from "@/wasm"; export function NoteCreator() { const { formatMessage } = useIntl(); diff --git a/packages/app/src/Element/IrisAccount/IrisAccount.tsx b/packages/app/src/Element/IrisAccount/IrisAccount.tsx index b2c95e43..e4018ea6 100644 --- a/packages/app/src/Element/IrisAccount/IrisAccount.tsx +++ b/packages/app/src/Element/IrisAccount/IrisAccount.tsx @@ -5,10 +5,10 @@ import { LoginStore } from "@/Login"; import AccountName from "./AccountName"; import ActiveAccount from "./ActiveAccount"; import ReservedAccount from "./ReservedAccount"; -import { ProfileLoader } from "@/index"; import { FormattedMessage } from "react-intl"; import { injectIntl } from "react-intl"; import messages from "@/Element/messages"; +import { ProfileLoader } from "@/system"; declare global { interface Window { diff --git a/packages/app/src/Element/PinPrompt.tsx b/packages/app/src/Element/PinPrompt.tsx index 5703a215..76205166 100644 --- a/packages/app/src/Element/PinPrompt.tsx +++ b/packages/app/src/Element/PinPrompt.tsx @@ -9,7 +9,8 @@ import useEventPublisher from "@/Hooks/useEventPublisher"; import { LoginStore, createPublisher, sessionNeedsPin } from "@/Login"; import Modal from "./Modal"; import AsyncButton from "./Button/AsyncButton"; -import { GetPowWorker } from "@/index"; + +import { GetPowWorker } from "@/wasm"; export function PinPrompt({ onResult, diff --git a/packages/app/src/Element/Trending/TrendingPosts.tsx b/packages/app/src/Element/Trending/TrendingPosts.tsx index 86d256de..9141695e 100644 --- a/packages/app/src/Element/Trending/TrendingPosts.tsx +++ b/packages/app/src/Element/Trending/TrendingPosts.tsx @@ -15,8 +15,8 @@ import ImageGridItem from "@/Element/Feed/ImageGridItem"; import { SpotlightThreadModal } from "@/Element/Spotlight/SpotlightThreadModal"; import useLogin from "@/Hooks/useLogin"; import useCachedFetch from "@/Hooks/useCachedFetch"; -import { System } from "@/index"; import { removeUndefined } from "@snort/shared"; +import { System } from "@/system"; export default function TrendingNotes({ count = Infinity, small = false }: { count: number; small: boolean }) { const api = new NostrBandApi(); diff --git a/packages/app/src/Pages/ZapPool.tsx b/packages/app/src/Pages/ZapPool.tsx index b3777561..4616e270 100644 --- a/packages/app/src/Pages/ZapPool.tsx +++ b/packages/app/src/Pages/ZapPool.tsx @@ -237,4 +237,4 @@ export default function ZapPoolPage() { return null; } return ; -} \ No newline at end of file +} diff --git a/packages/app/src/chat/nip24.ts b/packages/app/src/chat/nip24.ts index 08aed041..9af579bd 100644 --- a/packages/app/src/chat/nip24.ts +++ b/packages/app/src/chat/nip24.ts @@ -3,7 +3,8 @@ import { EventKind, NostrPrefix, encodeTLVEntries, TLVEntryType, TLVEntry, decod import { GiftWrapCache } from "@/Cache/GiftWrapCache"; import { UnwrappedGift } from "@/Db"; import { Chat, ChatSystem, ChatType, lastReadInChat } from "@/chat"; -import { GetPowWorker } from "@/index"; + +import { GetPowWorker } from "@/wasm"; export class Nip24ChatSystem extends ExternalStore> implements ChatSystem { #cache: GiftWrapCache; diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index f95ade24..5c1539ad 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -2,37 +2,11 @@ import "./index.css"; import "@szhsin/react-menu/dist/index.css"; import "./fonts/inter.css"; -import { - compress, - expand_filter, - flat_merge, - get_diff, - pow, - schnorr_verify_event, - default as wasmInit, -} from "@snort/system-wasm"; -import WasmPath from "@snort/system-wasm/pkg/system_wasm_bg.wasm"; - import { StrictMode } from "react"; import * as ReactDOM from "react-dom/client"; import { createBrowserRouter, RouteObject, RouterProvider } from "react-router-dom"; -import { - NostrSystem, - ProfileLoaderService, - Optimizer, - FlatReqFilter, - ReqFilter, - PowMiner, - NostrEvent, - mapEventToProfile, - PowWorker, - encodeTLVEntries, - socialGraphInstance, - TaggedNostrEvent, -} from "@snort/system"; -import PowWorkerURL from "@snort/system/src/pow-worker.ts?worker&url"; +import { encodeTLVEntries } from "@snort/system"; import { SnortContext } from "@snort/system-react"; -import { removeUndefined, throwIfOffline } from "@snort/shared"; import * as serviceWorkerRegistration from "@/serviceWorkerRegistration"; import { IntlProvider } from "@/IntlProvider"; @@ -53,7 +27,7 @@ import { ThreadRoute } from "@/Element/Event/Thread"; import { SubscribeRoutes } from "@/Pages/subscribe"; import ZapPoolPage from "@/Pages/ZapPool"; import { db } from "@/Db"; -import { preload, RelayMetrics, SystemDb, UserCache, UserRelays } from "@/Cache"; +import { preload } from "@/Cache"; import { LoginStore } from "@/Login"; import { SnortDeckLayout } from "@/Pages/DeckLayout"; import FreeNostrAddressPage from "@/Pages/FreeNostrAddressPage"; @@ -65,10 +39,8 @@ import { setupWebLNWalletConfig } from "@/Wallet/WebLN"; import { Wallets } from "@/Wallet"; import NetworkGraph from "@/Pages/NetworkGraph"; import WalletPage from "./Pages/WalletPage"; - -import IndexedDBWorker from "./Cache/IndexedDB?worker"; -import * as Comlink from "comlink"; -import { addEventToFuzzySearch } from "@/FuzzySearch"; +import { hasWasm, wasmInit, WasmPath } from "@/wasm"; +import { System } from "@/system"; declare global { interface Window { @@ -76,110 +48,6 @@ declare global { } } -const WasmOptimizer = { - expandFilter: (f: ReqFilter) => { - return expand_filter(f) as Array; - }, - getDiff: (prev: Array, next: Array) => { - return get_diff(prev, next) as Array; - }, - flatMerge: (all: Array) => { - return flat_merge(all) as Array; - }, - compress: (all: Array) => { - return compress(all) as Array; - }, - schnorrVerify: ev => { - return schnorr_verify_event(ev); - }, -} as Optimizer; - -export class WasmPowWorker implements PowMiner { - minePow(ev: NostrEvent, target: number): Promise { - const res = pow(ev, target); - return Promise.resolve(res); - } -} - -const hasWasm = "WebAssembly" in globalThis; -const DefaultPowWorker = hasWasm ? undefined : new PowWorker(PowWorkerURL); -export const GetPowWorker = () => (hasWasm ? new WasmPowWorker() : unwrap(DefaultPowWorker)); - -const indexedDB = Comlink.wrap(new IndexedDBWorker()); - -/** - * Singleton nostr system - */ -export const System = new NostrSystem({ - relayCache: UserRelays, - profileCache: UserCache, - relayMetrics: RelayMetrics, - optimizer: hasWasm ? WasmOptimizer : undefined, - db: SystemDb, -}); - -System.on("auth", async (c, r, cb) => { - const { id } = LoginStore.snapshot(); - const pub = LoginStore.getPublisher(id); - if (pub) { - cb(await pub.nip42Auth(c, r)); - } -}); - -System.on("event", (_, ev) => { - addEventToFuzzySearch(ev); - socialGraphInstance.handleEvent(ev); - if (CONFIG.useIndexedDBEvents && socialGraphInstance.getFollowDistance(ev.pubkey) <= 2) { - indexedDB.handleEvent(ev); - } -}); - -if (CONFIG.useIndexedDBEvents) { - // load all profiles - indexedDB.find( - { kinds: [0] }, - Comlink.proxy((e: TaggedNostrEvent) => System.HandleEvent(e)), - ); - - System.on("request", (filter: ReqFilter) => { - indexedDB.find( - filter, - Comlink.proxy((e: TaggedNostrEvent) => { - System.HandleEvent(e); - }), - ); - }); -} - -async function fetchProfile(key: string) { - try { - throwIfOffline(); - const rsp = await fetch(`${CONFIG.httpCache}/profile/${key}`); - if (rsp.ok) { - const data = (await rsp.json()) as NostrEvent; - if (data) { - return mapEventToProfile(data); - } - } - } catch (e) { - console.error(e); - } -} - -/** - * Add profile loader fn - */ -if (CONFIG.httpCache) { - System.ProfileLoader.loaderFn = async (keys: Array) => { - return removeUndefined(await Promise.all(keys.map(a => fetchProfile(a)))); - }; -} - -/** - * Singleton user profile loader - */ -export const ProfileLoader = new ProfileLoaderService(System, UserCache); - serviceWorkerRegistration.register(); async function initSite() { diff --git a/packages/app/src/system.ts b/packages/app/src/system.ts new file mode 100644 index 00000000..08770357 --- /dev/null +++ b/packages/app/src/system.ts @@ -0,0 +1,90 @@ +import { + mapEventToProfile, + NostrEvent, + NostrSystem, + ProfileLoaderService, + ReqFilter, + socialGraphInstance, + TaggedNostrEvent, +} from "@snort/system"; +import { RelayMetrics, SystemDb, UserCache, UserRelays } from "@/Cache"; +import { hasWasm, WasmOptimizer } from "@/wasm"; +import * as Comlink from "comlink"; +import IndexedDBWorker from "@/Cache/IndexedDB?worker"; +import { removeUndefined, throwIfOffline } from "@snort/shared"; +import { LoginStore } from "@/Login"; +import { addEventToFuzzySearch } from "@/FuzzySearch"; + +export const indexedDB = Comlink.wrap(new IndexedDBWorker()); +/** + * Singleton nostr system + */ +export const System = new NostrSystem({ + relayCache: UserRelays, + profileCache: UserCache, + relayMetrics: RelayMetrics, + optimizer: hasWasm ? WasmOptimizer : undefined, + db: SystemDb, +}); + +System.on("auth", async (c, r, cb) => { + const { id } = LoginStore.snapshot(); + const pub = LoginStore.getPublisher(id); + if (pub) { + cb(await pub.nip42Auth(c, r)); + } +}); + +System.on("event", (_, ev) => { + addEventToFuzzySearch(ev); + socialGraphInstance.handleEvent(ev); + if (CONFIG.useIndexedDBEvents && socialGraphInstance.getFollowDistance(ev.pubkey) <= 2) { + indexedDB.handleEvent(ev); + } +}); + +if (CONFIG.useIndexedDBEvents) { + // load all profiles + indexedDB.find( + { kinds: [0] }, + Comlink.proxy((e: TaggedNostrEvent) => System.HandleEvent(e)), + ); + + System.on("request", (filter: ReqFilter) => { + indexedDB.find( + filter, + Comlink.proxy((e: TaggedNostrEvent) => { + System.HandleEvent(e); + }), + ); + }); +} + +/** + * Add profile loader fn + */ +if (CONFIG.httpCache) { + System.ProfileLoader.loaderFn = async (keys: Array) => { + return removeUndefined(await Promise.all(keys.map(a => fetchProfile(a)))); + }; +} + +export async function fetchProfile(key: string) { + try { + throwIfOffline(); + const rsp = await fetch(`${CONFIG.httpCache}/profile/${key}`); + if (rsp.ok) { + const data = (await rsp.json()) as NostrEvent; + if (data) { + return mapEventToProfile(data); + } + } + } catch (e) { + console.error(e); + } +} + +/** + * Singleton user profile loader + */ +export const ProfileLoader = new ProfileLoaderService(System, UserCache); diff --git a/packages/app/src/wasm.ts b/packages/app/src/wasm.ts new file mode 100644 index 00000000..d1e612d2 --- /dev/null +++ b/packages/app/src/wasm.ts @@ -0,0 +1,44 @@ +import { + compress, + expand_filter, + flat_merge, + get_diff, + pow, + schnorr_verify_event, + default as wasmInit, +} from "@snort/system-wasm"; +import WasmPath from "@snort/system-wasm/pkg/system_wasm_bg.wasm"; + +import { FlatReqFilter, NostrEvent, Optimizer, PowMiner, PowWorker, ReqFilter } from "@snort/system"; +import PowWorkerURL from "@snort/system/src/pow-worker.ts?worker&url"; +import { unwrap } from "@/SnortUtils"; + +export const WasmOptimizer = { + expandFilter: (f: ReqFilter) => { + return expand_filter(f) as Array; + }, + getDiff: (prev: Array, next: Array) => { + return get_diff(prev, next) as Array; + }, + flatMerge: (all: Array) => { + return flat_merge(all) as Array; + }, + compress: (all: Array) => { + return compress(all) as Array; + }, + schnorrVerify: ev => { + return schnorr_verify_event(ev); + }, +} as Optimizer; + +export class WasmPowWorker implements PowMiner { + minePow(ev: NostrEvent, target: number): Promise { + const res = pow(ev, target); + return Promise.resolve(res); + } +} + +export { wasmInit, WasmPath }; +export const hasWasm = "WebAssembly" in globalThis; +const DefaultPowWorker = hasWasm ? undefined : new PowWorker(PowWorkerURL); +export const GetPowWorker = () => (hasWasm ? new WasmPowWorker() : unwrap(DefaultPowWorker));