From 658dd397f56da4684678c93738064f5c4d21e16a Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 24 Aug 2023 15:28:13 -0500 Subject: [PATCH] relay: respect "local: true" filter --- src/filter.ts | 27 +++++++++++++++++++++++++++ src/pipeline.ts | 4 ++-- src/subs.ts | 14 +++++++++----- src/utils.ts | 8 ++++++++ 4 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/filter.ts diff --git a/src/filter.ts b/src/filter.ts new file mode 100644 index 0000000..d813c62 --- /dev/null +++ b/src/filter.ts @@ -0,0 +1,27 @@ +import { type Event, matchFilters } from '@/deps.ts'; + +import type { DittoFilter } from '@/types.ts'; + +interface EventData { + isLocal: boolean; +} + +function matchDittoFilter(filter: DittoFilter, event: Event, data: EventData): boolean { + if (filter.local && !data.isLocal) { + return false; + } + + return matchFilters([filter], event); +} + +function matchDittoFilters(filters: DittoFilter[], event: Event, data: EventData): boolean { + for (const filter of filters) { + if (matchDittoFilter(filter, event, data)) { + return true; + } + } + + return false; +} + +export { matchDittoFilters }; diff --git a/src/pipeline.ts b/src/pipeline.ts index 7632464..0507e75 100644 --- a/src/pipeline.ts +++ b/src/pipeline.ts @@ -66,8 +66,8 @@ function trackRelays(event: Event) { } /** Distribute the event through active subscriptions. */ -function streamOut(event: Event) { - for (const sub of Sub.matches(event)) { +async function streamOut(event: Event) { + for await (const sub of Sub.matches(event)) { sub.socket.send(JSON.stringify(['EVENT', event])); } } diff --git a/src/subs.ts b/src/subs.ts index 2a63214..afe265a 100644 --- a/src/subs.ts +++ b/src/subs.ts @@ -1,4 +1,6 @@ -import { type Event, matchFilters } from '@/deps.ts'; +import { type Event } from '@/deps.ts'; +import { matchDittoFilters } from './filter.ts'; +import { isEventLocal } from '@/utils.ts'; import type { DittoFilter } from '@/types.ts'; @@ -18,7 +20,7 @@ interface Subscription { * Subscriptions can be added, removed, and matched against events. * * ```ts - * for (const sub of Sub.matches(event)) { + * for await (const sub of Sub.matches(event)) { * // Send event to sub.socket * sub.socket.send(JSON.stringify(event)); * } @@ -53,16 +55,18 @@ class SubscriptionStore { * Loop through matching subscriptions to stream out. * * ```ts - * for (const sub of Sub.matches(event)) { + * for await (const sub of Sub.matches(event)) { * // Send event to sub.socket * sub.socket.send(JSON.stringify(event)); * } * ``` */ - *matches(event: Event): Iterable { + async *matches(event: Event) { + const isLocal = await isEventLocal(event); + for (const subs of this.#store.values()) { for (const sub of subs.values()) { - if (matchFilters(sub.filters, event)) { + if (matchDittoFilters(sub.filters, event, { isLocal })) { yield sub; } } diff --git a/src/utils.ts b/src/utils.ts index 653c824..6cd6dd4 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,4 @@ +import { findUser } from '@/db/users.ts'; import { type Event, nip19, z } from '@/deps.ts'; import { lookupNip05Cached } from '@/nip05.ts'; import { getAuthor } from '@/queries.ts'; @@ -101,11 +102,18 @@ function isFollowing(source: Event<3>, targetPubkey: string): boolean { ); } +/** Check whether the event belongs to a local user. */ +async function isEventLocal(event: Event) { + const user = await findUser({ pubkey: event.pubkey }); + return !!user; +} + export { bech32ToPubkey, eventAge, eventDateComparator, findTag, + isEventLocal, isFollowing, isRelay, lookupAccount,