diff --git a/main.tsx b/main.tsx index 1228c4d..80758ee 100644 --- a/main.tsx +++ b/main.tsx @@ -8,13 +8,13 @@ import * as gql from "https://esm.sh/graphql@16.8.1"; import { Policy } from "./resolvers/policy.ts"; import { func_ResolvePolicyByKind } from "./resolvers/policy.ts"; import { func_GetEventsByKinds, func_WriteEvent } from "./resolvers/event.ts"; -import { WriteEvent } from "./resolvers/event.ts"; -import { func_GetEventsByIDs } from "./resolvers/event.ts"; +import { EventStore, func_GetEventsByIDs } from "./resolvers/event.ts"; import { GetEventsByIDs } from "./resolvers/event.ts"; import { GetEventsByKinds } from "./resolvers/event.ts"; import { NostrEvent, NostrKind, parseJSON, PublicKey, verifyEvent } from "./_libs.ts"; import { PolicyStore } from "./resolvers/policy.ts"; import { Policies } from "./resolvers/policy.ts"; +import { interface_GetEventsByAuthors } from "./resolvers/event.ts"; const schema = gql.buildSchema(gql.print(typeDefs)); @@ -63,6 +63,9 @@ export async function run(args: { const get_all_policies = Policies(args.kv); const policyStore = new PolicyStore(default_policy, args.kv, await get_all_policies()); + + const eventStore = await EventStore.New(args.kv); + const server = Deno.serve( { port, @@ -77,9 +80,10 @@ export async function run(args: { password, connections, resolvePolicyByKind: policyStore.resolvePolicyByKind, - write_event: WriteEvent(args.kv), + write_event: eventStore.write_event.bind(eventStore), get_events_by_IDs: GetEventsByIDs(args.kv), get_events_by_kinds: GetEventsByKinds(args.kv), + get_events_by_authors: eventStore.get_events_by_authors.bind(eventStore), policyStore, kv: args.kv, }), @@ -102,7 +106,7 @@ export type EventReadWriter = { write_event: func_WriteEvent; get_events_by_IDs: func_GetEventsByIDs; get_events_by_kinds: func_GetEventsByKinds; -}; +} & interface_GetEventsByAuthors; const root_handler = ( args: { diff --git a/resolvers/event.ts b/resolvers/event.ts index e44fe48..befca91 100644 --- a/resolvers/event.ts +++ b/resolvers/event.ts @@ -1,5 +1,4 @@ -import { NostrEvent, NostrKind, PublicKey } from "../_libs.ts"; -import { pubkey_resolver } from "./pubkey.ts"; +import { NostrEvent, NostrKind } from "../_libs.ts"; export type Actor = { type: "admin"; @@ -43,13 +42,52 @@ function fromEntries(entries: Deno.KvEntryMaybe[]) { return events; } +export type func_GetEventsByAuthors = (authors: Set) => AsyncIterable; +export type interface_GetEventsByAuthors = { + get_events_by_authors: func_GetEventsByAuthors; +}; + export type func_WriteEvent = (event: NostrEvent) => Promise; -export const WriteEvent = (kv: Deno.Kv): func_WriteEvent => async (event: NostrEvent) => { - const result = await kv.atomic() - .set(["event", event.id], event) - .set(["event", event.kind, event.id], event) - .set(["event", event.pubkey, event.id], event) - .commit(); - - return result.ok; +export type interface_WriteEvent = { + write_event: func_WriteEvent; }; + +export class EventStore implements interface_GetEventsByAuthors, interface_WriteEvent { + private constructor( + private events: Map, + private kv: Deno.Kv, + ) {} + + static async New(kv: Deno.Kv) { + const entries = kv.list({ prefix: ["event"] }); + const events = new Map(); + for await (const entry of entries) { + const event = entry.value; + events.set(event.id, event); + } + return new EventStore(events, kv); + } + + async *get_events_by_authors(authors: Set): AsyncIterable { + for (const event of this.events.values()) { + if (authors.has(event.pubkey)) { + yield event; + } + } + } + + async write_event(event: NostrEvent) { + console.log("write_event", event); + const result = await this.kv.atomic() + .set(["event", event.id], event) + .set(["event", event.kind, event.id], event) + .set(["event", event.pubkey, event.id], event) + .commit(); + + if (result.ok) { + this.events.set(event.id, event); + } + + return result.ok; + } +} diff --git a/resolvers/policy.ts b/resolvers/policy.ts index bca2357..981db87 100644 --- a/resolvers/policy.ts +++ b/resolvers/policy.ts @@ -27,7 +27,7 @@ export class PolicyStore { constructor( private default_policy: DefaultPolicy, private kv: Deno.Kv, - private initial_policies: Policy[], + initial_policies: Policy[], ) { for (const policy of initial_policies) { this.policies.set(policy.kind, policy); diff --git a/test.ts b/test.ts index 0fdaba7..aab43a6 100644 --- a/test.ts +++ b/test.ts @@ -8,6 +8,7 @@ import { NostrKind, prepareNormalNostrEvent, RelayRejectedEvent, + RelayResponse_Event, SingleRelayConnection, SubscriptionStream, } from "./_libs.ts"; @@ -96,6 +97,19 @@ Deno.test("main", async () => { assertEquals(events.length, 3); // todo: assert content } + { + const ctx1 = InMemoryAccountContext.Generate(); + const event_1 = await randomEvent(ctx1, NostrKind.TEXT_NOTE, "1"); + + await client.sendEvent(event_1); + + const stream = await client.newSub("get author", { + authors: [ctx1.publicKey.hex], + }) as SubscriptionStream; + + const msg = await stream.chan.pop() as RelayResponse_Event; + assertEquals(msg.event, event_1); + } await client.close(); await relay.shutdown(); diff --git a/ws.ts b/ws.ts index 7a71c05..d46fcb4 100644 --- a/ws.ts +++ b/ws.ts @@ -1,7 +1,12 @@ // deno-lint-ignore-file import { func_ResolvePolicyByKind } from "./resolvers/policy.ts"; import { DefaultPolicy, EventReadWriter } from "./main.tsx"; -import { func_GetEventsByIDs, func_GetEventsByKinds, func_WriteEvent } from "./resolvers/event.ts"; +import { + func_GetEventsByAuthors, + func_GetEventsByIDs, + func_GetEventsByKinds, + func_WriteEvent, +} from "./resolvers/event.ts"; import { _RelayResponse_EOSE, _RelayResponse_Event, @@ -184,6 +189,7 @@ async function handle_filter(args: { filter: NostrFilter; get_events_by_IDs: func_GetEventsByIDs; get_events_by_kinds: func_GetEventsByKinds; + get_events_by_authors: func_GetEventsByAuthors; resolvePolicyByKind: func_ResolvePolicyByKind; }) { const event_candidates = new Map(); @@ -209,7 +215,18 @@ async function handle_filter(args: { event_candidates.delete(key); } } else { - const events = args.get_events_by_kinds(filter.kinds); + const events = get_events_by_kinds(filter.kinds); + for await (const event of events) { + console.log(event); + event_candidates.set(event.id, event); + } + } + } + if (filter.authors) { + if (event_candidates.size > 0) { + console.log("event_candidates", event_candidates); + } else { + const events = args.get_events_by_authors(new Set(filter.authors)); for await (const event of events) { console.log(event); event_candidates.set(event.id, event);