refactor: extract connection pool

wip: setup system-worker
This commit is contained in:
2023-12-28 17:40:26 +00:00
parent e7e7fdc14d
commit c2e1215667
7 changed files with 455 additions and 169 deletions

View File

@ -0,0 +1,14 @@
export const enum NostrSystemCommand {
OkResponse,
ErrorResponse,
Init,
ConnectRelay,
DisconnectRelay
}
export interface NostrSystemMessage<T> {
id: string;
type: NostrSystemCommand;
data: T;
}

View File

@ -0,0 +1,59 @@
/// <reference lib="webworker" />
import { NostrSystem, NostrsystemProps } from "../nostr-system";
import { NostrSystemMessage, NostrSystemCommand } from ".";
let system: NostrSystem | undefined;
function reply<T>(id: string, type: NostrSystemCommand, data: T) {
globalThis.postMessage({
id,
type,
data,
} as NostrSystemMessage<T>);
}
function okReply(id: string, message?: string) {
reply<string | undefined>(id, NostrSystemCommand.OkResponse, message);
}
function errorReply(id: string, message: string) {
reply<string>(id, NostrSystemCommand.ErrorResponse, message);
}
function checkInitialized() {
if (system === undefined) {
throw new Error("System not initialized");
}
}
globalThis.onmessage = async ev => {
const data = ev.data as { id: string; type: NostrSystemCommand };
try {
switch (data.type) {
case NostrSystemCommand.Init: {
const cmd = ev.data as NostrSystemMessage<NostrsystemProps>;
if (system === undefined) {
system = new NostrSystem(cmd.data);
await system.Init();
okReply(data.id);
} else {
errorReply(data.id, "System is already initialized");
}
break;
}
case NostrSystemCommand.ConnectRelay: {
checkInitialized();
const cmd = ev.data as NostrSystemMessage<[string, {read: boolean, write: boolean}]>;
await system?.ConnectToRelay(cmd.data[0], cmd.data[1]);
okReply(data.id, "Connected");
break;
}
default: {
errorReply(data.id, "Unknown command");
break;
}
}
} catch (e) {
if (e instanceof Error) {
errorReply(data.id, e.message);
}
}
};

View File

@ -0,0 +1,109 @@
import { v4 as uuid } from "uuid";
import EventEmitter from "eventemitter3";
import {
ConnectionStateSnapshot,
NostrEvent,
NoteStore,
OkResponse,
ProfileLoaderService,
QueryOptimizer,
RelayCache,
RelaySettings,
RequestBuilder,
SystemInterface,
TaggedNostrEvent,
} from "..";
import { NostrSystemEvents, NostrsystemProps } from "../nostr-system";
import { Query } from "../query";
import { NostrSystemCommand, NostrSystemMessage } from ".";
export class SystemWorker extends EventEmitter<NostrSystemEvents> implements SystemInterface {
#worker: Worker;
#commandQueue: Map<string, (v: unknown) => void> = new Map();
checkSigs: boolean;
constructor(scriptPath: string, props: NostrsystemProps) {
super();
this.checkSigs = props.checkSigs ?? false;
this.#worker = new Worker(scriptPath, {
name: "SystemWorker",
});
}
get Sockets(): ConnectionStateSnapshot[] {
throw new Error("Method not implemented.");
}
async Init() {
await this.#workerRpc<void, string>(NostrSystemCommand.Init, undefined);
}
GetQuery(id: string): Query | undefined {
return undefined;
}
Query<T extends NoteStore>(type: new () => T, req: RequestBuilder): Query {
throw new Error("Method not implemented.");
}
Fetch(req: RequestBuilder, cb?: ((evs: TaggedNostrEvent[]) => void) | undefined): Promise<TaggedNostrEvent[]> {
throw new Error("Method not implemented.");
}
ConnectToRelay(address: string, options: RelaySettings): Promise<void> {
throw new Error("Method not implemented.");
}
DisconnectRelay(address: string): void {
throw new Error("Method not implemented.");
}
HandleEvent(ev: TaggedNostrEvent): void {
throw new Error("Method not implemented.");
}
BroadcastEvent(ev: NostrEvent, cb?: ((rsp: OkResponse) => void) | undefined): Promise<OkResponse[]> {
throw new Error("Method not implemented.");
}
WriteOnceToRelay(relay: string, ev: NostrEvent): Promise<OkResponse> {
throw new Error("Method not implemented.");
}
get ProfileLoader(): ProfileLoaderService {
throw new Error("Method not implemented.");
}
get RelayCache(): RelayCache {
throw new Error("Method not implemented.");
}
get QueryOptimizer(): QueryOptimizer {
throw new Error("Method not implemented.");
}
#workerRpc<T, R>(type: NostrSystemCommand, data: T, timeout = 5_000) {
const id = uuid();
this.#worker.postMessage({
id,
type,
data,
} as NostrSystemMessage<T>);
return new Promise<R>((resolve, reject) => {
let t: ReturnType<typeof setTimeout>;
this.#commandQueue.set(id, v => {
clearTimeout(t);
const cmdReply = v as NostrSystemMessage<R>;
if (cmdReply.type === NostrSystemCommand.OkResponse) {
resolve(cmdReply.data);
} else {
reject(cmdReply.data);
}
});
t = setTimeout(() => {
reject("timeout");
}, timeout);
});
}
}