refactor: extract connection pool
wip: setup system-worker
This commit is contained in:
14
packages/system/src/worker/index.ts
Normal file
14
packages/system/src/worker/index.ts
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
export const enum NostrSystemCommand {
|
||||
OkResponse,
|
||||
ErrorResponse,
|
||||
Init,
|
||||
ConnectRelay,
|
||||
DisconnectRelay
|
||||
}
|
||||
|
||||
export interface NostrSystemMessage<T> {
|
||||
id: string;
|
||||
type: NostrSystemCommand;
|
||||
data: T;
|
||||
}
|
59
packages/system/src/worker/system-worker-script.ts
Normal file
59
packages/system/src/worker/system-worker-script.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
};
|
109
packages/system/src/worker/system-worker.ts
Normal file
109
packages/system/src/worker/system-worker.ts
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user