From 1b8bb7871794d93fcda116b043fbaa24969470c8 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 11:02:09 -0500 Subject: [PATCH 01/15] Rename loopback to firehose --- src/app.ts | 2 +- src/{loopback.ts => firehose.ts} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/{loopback.ts => firehose.ts} (93%) diff --git a/src/app.ts b/src/app.ts index 00a14601..6968b0d8 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,6 @@ import { type Context, cors, type Handler, Hono, type HonoEnv, logger, type MiddlewareHandler } from '@/deps.ts'; import { type Event } from '@/event.ts'; -import '@/loopback.ts'; +import '@/firehose.ts'; import { actorController } from './controllers/activitypub/actor.ts'; import { diff --git a/src/loopback.ts b/src/firehose.ts similarity index 93% rename from src/loopback.ts rename to src/firehose.ts index e07c73ea..17a5155d 100644 --- a/src/loopback.ts +++ b/src/firehose.ts @@ -20,9 +20,9 @@ relay.subscribe( undefined, ); -/** Handle events through the loopback pipeline. */ +/** Handle events through the firehose pipeline. */ async function handleEvent(event: SignedEvent): Promise { - console.info('loopback event:', event.id); + console.info('firehose event:', event.id); trackHashtags(event); From 4a47c25f1eb7ef49a5e32b275e88a12e81701fd8 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 12:29:54 -0500 Subject: [PATCH 02/15] Add NIP-11 schema --- src/schema.ts | 17 ++++++++++++++++- src/schemas/nostr.ts | 20 +++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/schema.ts b/src/schema.ts index 361a310a..09d46a0f 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -54,4 +54,19 @@ const decode64Schema = z.string().transform((value, ctx) => { const hashtagSchema = z.string().regex(/^\w{1,30}$/); -export { decode64Schema, emojiTagSchema, filteredArray, hashtagSchema, jsonSchema, parseRelay, relaySchema }; +/** + * Limits the length before trying to parse the URL. + * https://stackoverflow.com/a/417184/8811886 + */ +const safeUrlSchema = z.string().max(2048).url(); + +export { + decode64Schema, + emojiTagSchema, + filteredArray, + hashtagSchema, + jsonSchema, + parseRelay, + relaySchema, + safeUrlSchema, +}; diff --git a/src/schemas/nostr.ts b/src/schemas/nostr.ts index e5bdb813..cbc68164 100644 --- a/src/schemas/nostr.ts +++ b/src/schemas/nostr.ts @@ -1,14 +1,16 @@ import { verifySignature, z } from '@/deps.ts'; -import { jsonSchema } from '../schema.ts'; +import { jsonSchema, safeUrlSchema } from '../schema.ts'; /** Schema to validate Nostr hex IDs such as event IDs and pubkeys. */ const nostrIdSchema = z.string().regex(/^[0-9a-f]{64}$/); +/** Nostr kinds are positive integers. */ +const kindSchema = z.number().int().positive(); /** Nostr event schema. */ const eventSchema = z.object({ id: nostrIdSchema, - kind: z.number(), + kind: kindSchema, tags: z.array(z.array(z.string())), content: z.string(), created_at: z.number(), @@ -21,7 +23,7 @@ const signedEventSchema = eventSchema.refine(verifySignature); /** Nostr relay filter schema. */ const filterSchema = z.object({ - kinds: z.number().int().positive().array().optional(), + kinds: kindSchema.array().optional(), ids: nostrIdSchema.array().optional(), authors: nostrIdSchema.array().optional(), since: z.number().int().positive().optional(), @@ -67,6 +69,17 @@ const metaContentSchema = z.object({ /** Parses kind 0 content from a JSON string. */ const jsonMetaContentSchema = jsonSchema.pipe(metaContentSchema).catch({}); +/** NIP-11 Relay Information Document. */ +const relayInfoDocSchema = z.object({ + name: z.string().transform((val) => val.slice(0, 30)).optional().catch(undefined), + description: z.string().transform((val) => val.slice(0, 3000)).optional().catch(undefined), + pubkey: nostrIdSchema.optional().catch(undefined), + contact: safeUrlSchema.optional().catch(undefined), + supported_nips: z.number().int().positive().array().optional().catch(undefined), + software: safeUrlSchema.optional().catch(undefined), + icon: safeUrlSchema.optional().catch(undefined), +}); + export { type ClientCLOSE, type ClientEVENT, @@ -77,5 +90,6 @@ export { jsonMetaContentSchema, metaContentSchema, nostrIdSchema, + relayInfoDocSchema, signedEventSchema, }; From 78f638e6331dd8f154f82111b5d074160ed08e1c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 14:11:28 -0500 Subject: [PATCH 03/15] Add relays to database and start tracking them --- src/db.ts | 5 +++++ src/db/migrations/001_add_relays.ts | 12 ++++++++++++ src/db/relays.ts | 19 +++++++++++++++++++ src/firehose.ts | 28 +++++++++++++++++++++++----- src/schema.ts | 29 +---------------------------- src/utils.ts | 7 +++++++ 6 files changed, 67 insertions(+), 33 deletions(-) create mode 100644 src/db/migrations/001_add_relays.ts create mode 100644 src/db/relays.ts diff --git a/src/db.ts b/src/db.ts index d03bf2f1..7da67ed0 100644 --- a/src/db.ts +++ b/src/db.ts @@ -8,6 +8,7 @@ interface DittoDB { events: EventRow; tags: TagRow; users: UserRow; + relays: RelayRow; } interface EventRow { @@ -34,6 +35,10 @@ interface UserRow { inserted_at: Date; } +interface RelayRow { + url: string; +} + const db = new Kysely({ dialect: new DenoSqliteDialect({ database: new Sqlite(Conf.dbPath), diff --git a/src/db/migrations/001_add_relays.ts b/src/db/migrations/001_add_relays.ts new file mode 100644 index 00000000..a603c2ed --- /dev/null +++ b/src/db/migrations/001_add_relays.ts @@ -0,0 +1,12 @@ +import { Kysely } from '@/deps.ts'; + +export async function up(db: Kysely): Promise { + await db.schema + .createTable('relays') + .addColumn('url', 'text', (col) => col.primaryKey()) + .execute(); +} + +export async function down(db: Kysely): Promise { + await db.schema.dropTable('relays').execute(); +} diff --git a/src/db/relays.ts b/src/db/relays.ts new file mode 100644 index 00000000..d550162f --- /dev/null +++ b/src/db/relays.ts @@ -0,0 +1,19 @@ +import { db } from '@/db.ts'; + +/** Inserts relays into the database, skipping duplicates. */ +function addRelays(relays: `wss://${string}`[]) { + const values = relays.map((url) => ({ url })); + + return db.insertInto('relays') + .values(values) + .onConflict((oc) => oc.column('url').doNothing()) + .execute(); +} + +/** Get a list of all known good relays. */ +async function getAllRelays(): Promise { + const rows = await db.selectFrom('relays').select('relays.url').execute(); + return rows.map((row) => row.url); +} + +export { addRelays, getAllRelays }; diff --git a/src/firehose.ts b/src/firehose.ts index 17a5155d..d1b5f7e9 100644 --- a/src/firehose.ts +++ b/src/firehose.ts @@ -1,20 +1,21 @@ -import { Conf } from '@/config.ts'; import { insertEvent, isLocallyFollowed } from '@/db/events.ts'; +import { addRelays, getAllRelays } from '@/db/relays.ts'; import { findUser } from '@/db/users.ts'; import { RelayPool } from '@/deps.ts'; import { trends } from '@/trends.ts'; -import { nostrDate, nostrNow } from '@/utils.ts'; +import { isRelay, nostrDate, nostrNow } from '@/utils.ts'; import type { SignedEvent } from '@/event.ts'; -const relay = new RelayPool([Conf.relay]); +const relays = await getAllRelays(); +const pool = new RelayPool(relays); // This file watches all events on your Ditto relay and triggers // side-effects based on them. This can be used for things like // notifications, trending hashtag tracking, etc. -relay.subscribe( +pool.subscribe( [{ kinds: [1], since: nostrNow() }], - [Conf.relay], + relays, handleEvent, undefined, undefined, @@ -25,6 +26,7 @@ async function handleEvent(event: SignedEvent): Promise { console.info('firehose event:', event.id); trackHashtags(event); + trackRelays(event); if (await findUser({ pubkey: event.pubkey }) || await isLocallyFollowed(event.pubkey)) { insertEvent(event).catch(console.warn); @@ -49,3 +51,19 @@ function trackHashtags(event: SignedEvent): void { // do nothing } } + +/** Tracks nown relays in the database. */ +function trackRelays(event: SignedEvent) { + const relays = new Set<`wss://${string}`>(); + + event.tags.forEach((tag) => { + if (['p', 'e', 'a'].includes(tag[0]) && isRelay(tag[2])) { + relays.add(tag[2]); + } + if (event.kind === 10002 && tag[0] === 'r' && isRelay(tag[1])) { + relays.add(tag[1]); + } + }); + + return addRelays([...relays]); +} diff --git a/src/schema.ts b/src/schema.ts index 09d46a0f..e56c1aeb 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -20,24 +20,6 @@ const jsonSchema = z.string().transform((value, ctx) => { } }); -/** Alias for `safeParse`, but instead of returning a success object it returns the value (or undefined on fail). */ -function parseValue(schema: z.ZodType, value: unknown): T | undefined { - const result = schema.safeParse(value); - return result.success ? result.data : undefined; -} - -const parseRelay = (relay: string | URL) => parseValue(relaySchema, relay); - -const relaySchema = z.custom((relay) => { - if (typeof relay !== 'string') return false; - try { - const { protocol } = new URL(relay); - return protocol === 'wss:' || protocol === 'ws:'; - } catch (_e) { - return false; - } -}); - const emojiTagSchema = z.tuple([z.literal('emoji'), z.string(), z.string().url()]); /** https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem */ @@ -60,13 +42,4 @@ const hashtagSchema = z.string().regex(/^\w{1,30}$/); */ const safeUrlSchema = z.string().max(2048).url(); -export { - decode64Schema, - emojiTagSchema, - filteredArray, - hashtagSchema, - jsonSchema, - parseRelay, - relaySchema, - safeUrlSchema, -}; +export { decode64Schema, emojiTagSchema, filteredArray, hashtagSchema, jsonSchema, safeUrlSchema }; diff --git a/src/utils.ts b/src/utils.ts index ed0a640f..a2c25047 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -142,6 +142,12 @@ function activityJson(c: Context, object: T) { return response; } +/** Schema to parse a relay URL. */ +const relaySchema = z.string().max(255).startsWith('wss://').url(); + +/** Check whether the value is a valid relay URL. */ +const isRelay = (relay: string): relay is `wss://${string}` => relaySchema.safeParse(relay).success; + export { activityJson, bech32ToPubkey, @@ -149,6 +155,7 @@ export { eventAge, eventDateComparator, findTag, + isRelay, lookupAccount, type Nip05, nostrDate, From 16ba2241248bc49caa49adf98a1397f9cfb8cba3 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 14:40:30 -0500 Subject: [PATCH 04/15] Get rid of DITTO_RELAY, derive from LOCAL_DOMAIN --- src/config.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/config.ts b/src/config.ts index 461d986b..f13a4079 100644 --- a/src/config.ts +++ b/src/config.ts @@ -35,12 +35,9 @@ const Conf = { ['sign', 'verify'], ); }, - get relay() { - const value = Deno.env.get('DITTO_RELAY'); - if (!value) { - throw new Error('Missing DITTO_RELAY'); - } - return value; + get relay(): `wss://${string}` | `ws://${string}` { + const { protocol, host } = Conf.url; + return `${protocol === 'https:' ? 'wss:' : 'ws:'}//${host}/relay`; }, get localDomain() { return Deno.env.get('LOCAL_DOMAIN') || 'http://localhost:8000'; From cd5cf96886c4fc303bae8d7d10345d686b3c71d2 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 15:39:21 -0500 Subject: [PATCH 05/15] firehose: update comment --- src/firehose.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/firehose.ts b/src/firehose.ts index d1b5f7e9..b3d22967 100644 --- a/src/firehose.ts +++ b/src/firehose.ts @@ -10,9 +10,9 @@ import type { SignedEvent } from '@/event.ts'; const relays = await getAllRelays(); const pool = new RelayPool(relays); -// This file watches all events on your Ditto relay and triggers -// side-effects based on them. This can be used for things like -// notifications, trending hashtag tracking, etc. +// This file watches events on all known relays and performs +// side-effects based on them, such as trending hashtag tracking +// and storing events for notifications and the home feed. pool.subscribe( [{ kinds: [1], since: nostrNow() }], relays, From f13616a7403fb5d521fe0bbe5af2f8c6cf4effcc Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 18:27:30 -0500 Subject: [PATCH 06/15] Bump kysely-deno-sqlite to v1.0.0 (no changes) --- src/deps.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deps.ts b/src/deps.ts index 5d075796..d4431c7a 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -59,4 +59,4 @@ export { type NullableInsertKeys, sql, } from 'npm:kysely@^0.25.0'; -export { DenoSqliteDialect } from 'https://gitlab.com/soapbox-pub/kysely-deno-sqlite/-/raw/76748303a45fac64a889cd2b9265c6c9b8ef2e8b/mod.ts'; +export { DenoSqliteDialect } from 'https://gitlab.com/soapbox-pub/kysely-deno-sqlite/-/raw/v1.0.0/mod.ts'; From e3ade42f58b662d2e5c922682be362c5b0c2dd95 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 18:46:35 -0500 Subject: [PATCH 07/15] Added script to populate relays from external source --- deno.json | 7 ++++--- scripts/relays.ts | 23 +++++++++++++++++++++++ src/utils.ts | 1 + 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 scripts/relays.ts diff --git a/deno.json b/deno.json index 5233fa9e..66b12132 100644 --- a/deno.json +++ b/deno.json @@ -6,21 +6,22 @@ "dev": "deno run --allow-read --allow-write=data --allow-env --allow-net --unstable --watch src/server.ts", "debug": "deno run --allow-read --allow-write=data --allow-env --allow-net --unstable --inspect src/server.ts", "test": "DB_PATH=\":memory:\" deno test --allow-read --allow-write=data --allow-env --unstable src", - "check": "deno check --unstable src/server.ts" + "check": "deno check --unstable src/server.ts", + "relays:sync": "deno run -A --unstable scripts/relays.ts sync", }, "imports": { "@/": "./src/", "~/": "./" }, "lint": { - "include": ["src/"], + "include": ["src/", "scripts/"], "rules": { "tags": ["recommended"], "exclude": ["no-explicit-any"] } }, "fmt": { - "include": ["src/"], + "include": ["src/", "scripts/"], "useTabs": false, "lineWidth": 120, "indentWidth": 2, diff --git a/scripts/relays.ts b/scripts/relays.ts new file mode 100644 index 00000000..ab4e7aba --- /dev/null +++ b/scripts/relays.ts @@ -0,0 +1,23 @@ +import { addRelays } from '@/db/relays.ts'; +import { filteredArray } from '@/schema.ts'; +import { relaySchema } from '~/src/utils.ts'; + +switch (Deno.args[0]) { + case 'sync': + await sync(Deno.args.slice(1)); + break; + default: + console.log('Usage: deno run -A scripts/relays.ts sync '); +} + +async function sync([url]: string[]) { + if (!url) { + console.error('Error: please provide a URL'); + Deno.exit(1); + } + const response = await fetch(url); + const data = await response.json(); + const values = filteredArray(relaySchema).parse(data) as `wss://${string}`[]; + await addRelays(values); + console.log(`Done: added ${values.length} relays.`); +} diff --git a/src/utils.ts b/src/utils.ts index a2c25047..8716d634 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -164,6 +164,7 @@ export { paginationSchema, parseBody, parseNip05, + relaySchema, sha256, }; From b11677573bf4b540a68b61a5253670592b0c74bb Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 19:00:54 -0500 Subject: [PATCH 08/15] db/relays: skip if values are empty --- src/db/relays.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/db/relays.ts b/src/db/relays.ts index d550162f..b650c837 100644 --- a/src/db/relays.ts +++ b/src/db/relays.ts @@ -2,6 +2,7 @@ import { db } from '@/db.ts'; /** Inserts relays into the database, skipping duplicates. */ function addRelays(relays: `wss://${string}`[]) { + if (!relays.length) return Promise.resolve(); const values = relays.map((url) => ({ url })); return db.insertInto('relays') From 45a3e2974e8078740d05ba4606d90e3ce99453cd Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 19:01:28 -0500 Subject: [PATCH 09/15] firehose: expand criteria, improve logging --- src/firehose.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/firehose.ts b/src/firehose.ts index b3d22967..5e8610e1 100644 --- a/src/firehose.ts +++ b/src/firehose.ts @@ -14,7 +14,7 @@ const pool = new RelayPool(relays); // side-effects based on them, such as trending hashtag tracking // and storing events for notifications and the home feed. pool.subscribe( - [{ kinds: [1], since: nostrNow() }], + [{ kinds: [0, 1, 3, 5, 6, 7], since: nostrNow() }], relays, handleEvent, undefined, @@ -23,7 +23,7 @@ pool.subscribe( /** Handle events through the firehose pipeline. */ async function handleEvent(event: SignedEvent): Promise { - console.info('firehose event:', event.id); + console.info(`firehose: Event<${event.kind}> ${event.id}`); trackHashtags(event); trackRelays(event); From 875fcfb09d27833fab8c3d82c7f6f7757fe99ef1 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 19:01:56 -0500 Subject: [PATCH 10/15] firehose: nown --> known --- src/firehose.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/firehose.ts b/src/firehose.ts index 5e8610e1..6c605326 100644 --- a/src/firehose.ts +++ b/src/firehose.ts @@ -52,7 +52,7 @@ function trackHashtags(event: SignedEvent): void { } } -/** Tracks nown relays in the database. */ +/** Tracks known relays in the database. */ function trackRelays(event: SignedEvent) { const relays = new Set<`wss://${string}`>(); From 3da30553cba61b4445a992ae4bd0d90a2dd6098d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 19:16:49 -0500 Subject: [PATCH 11/15] firehose: accept kind 10002 events --- src/firehose.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/firehose.ts b/src/firehose.ts index 6c605326..4e5e3dc0 100644 --- a/src/firehose.ts +++ b/src/firehose.ts @@ -14,7 +14,7 @@ const pool = new RelayPool(relays); // side-effects based on them, such as trending hashtag tracking // and storing events for notifications and the home feed. pool.subscribe( - [{ kinds: [0, 1, 3, 5, 6, 7], since: nostrNow() }], + [{ kinds: [0, 1, 3, 5, 6, 7, 10002], since: nostrNow() }], relays, handleEvent, undefined, From 2e983154bbb5c91e23b4b1414d132d0842b87680 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Aug 2023 20:41:20 -0500 Subject: [PATCH 12/15] db/relays: reformat --- src/db/relays.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/db/relays.ts b/src/db/relays.ts index b650c837..5b91c682 100644 --- a/src/db/relays.ts +++ b/src/db/relays.ts @@ -13,7 +13,11 @@ function addRelays(relays: `wss://${string}`[]) { /** Get a list of all known good relays. */ async function getAllRelays(): Promise { - const rows = await db.selectFrom('relays').select('relays.url').execute(); + const rows = await db + .selectFrom('relays') + .select('relays.url') + .execute(); + return rows.map((row) => row.url); } From 92f5bea891bdd6f1a2bf512b4092ade4e35e1325 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 15 Aug 2023 18:59:49 -0500 Subject: [PATCH 13/15] db/relays: add "domain" column --- src/db/migrations/001_add_relays.ts | 1 + src/db/relays.ts | 7 ++++++- src/deps.ts | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/db/migrations/001_add_relays.ts b/src/db/migrations/001_add_relays.ts index a603c2ed..41f73a96 100644 --- a/src/db/migrations/001_add_relays.ts +++ b/src/db/migrations/001_add_relays.ts @@ -4,6 +4,7 @@ export async function up(db: Kysely): Promise { await db.schema .createTable('relays') .addColumn('url', 'text', (col) => col.primaryKey()) + .addColumn('domain', 'text', (col) => col.notNull()) .execute(); } diff --git a/src/db/relays.ts b/src/db/relays.ts index 5b91c682..65b009d7 100644 --- a/src/db/relays.ts +++ b/src/db/relays.ts @@ -1,9 +1,14 @@ +import { tldts } from '@/deps.ts'; import { db } from '@/db.ts'; /** Inserts relays into the database, skipping duplicates. */ function addRelays(relays: `wss://${string}`[]) { if (!relays.length) return Promise.resolve(); - const values = relays.map((url) => ({ url })); + + const values = relays.map((url) => ({ + url, + domain: tldts.getDomain(url), + })); return db.insertInto('relays') .values(values) diff --git a/src/deps.ts b/src/deps.ts index d4431c7a..2c7d67d5 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -60,3 +60,4 @@ export { sql, } from 'npm:kysely@^0.25.0'; export { DenoSqliteDialect } from 'https://gitlab.com/soapbox-pub/kysely-deno-sqlite/-/raw/v1.0.0/mod.ts'; +export { default as tldts } from 'npm:tldts@^6.0.14'; From a0769d7c92372ea56a59c570efe0f2fd60c4acb3 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 15 Aug 2023 19:07:26 -0500 Subject: [PATCH 14/15] db/relays: add `active` column --- src/db.ts | 2 ++ src/db/migrations/001_add_relays.ts | 1 + src/db/relays.ts | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/db.ts b/src/db.ts index 7da67ed0..474652c4 100644 --- a/src/db.ts +++ b/src/db.ts @@ -37,6 +37,8 @@ interface UserRow { interface RelayRow { url: string; + domain: string; + active: boolean; } const db = new Kysely({ diff --git a/src/db/migrations/001_add_relays.ts b/src/db/migrations/001_add_relays.ts index 41f73a96..1415f5f7 100644 --- a/src/db/migrations/001_add_relays.ts +++ b/src/db/migrations/001_add_relays.ts @@ -5,6 +5,7 @@ export async function up(db: Kysely): Promise { .createTable('relays') .addColumn('url', 'text', (col) => col.primaryKey()) .addColumn('domain', 'text', (col) => col.notNull()) + .addColumn('active', 'boolean', (col) => col.notNull()) .execute(); } diff --git a/src/db/relays.ts b/src/db/relays.ts index 65b009d7..89c9fcb0 100644 --- a/src/db/relays.ts +++ b/src/db/relays.ts @@ -7,7 +7,8 @@ function addRelays(relays: `wss://${string}`[]) { const values = relays.map((url) => ({ url, - domain: tldts.getDomain(url), + domain: tldts.getDomain(url)!, + active: true, })); return db.insertInto('relays') From 882a3fe203d9d7b8af282bc4dfe923f873cd2836 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 16 Aug 2023 08:28:52 -0500 Subject: [PATCH 15/15] Use only "active" relays in the pool --- src/db/relays.ts | 7 ++++--- src/firehose.ts | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/db/relays.ts b/src/db/relays.ts index 89c9fcb0..d6f99c38 100644 --- a/src/db/relays.ts +++ b/src/db/relays.ts @@ -17,14 +17,15 @@ function addRelays(relays: `wss://${string}`[]) { .execute(); } -/** Get a list of all known good relays. */ -async function getAllRelays(): Promise { +/** Get a list of all known active relay URLs. */ +async function getActiveRelays(): Promise { const rows = await db .selectFrom('relays') .select('relays.url') + .where('relays.active', '=', true) .execute(); return rows.map((row) => row.url); } -export { addRelays, getAllRelays }; +export { addRelays, getActiveRelays }; diff --git a/src/firehose.ts b/src/firehose.ts index 4e5e3dc0..689ebc3f 100644 --- a/src/firehose.ts +++ b/src/firehose.ts @@ -1,5 +1,5 @@ import { insertEvent, isLocallyFollowed } from '@/db/events.ts'; -import { addRelays, getAllRelays } from '@/db/relays.ts'; +import { addRelays, getActiveRelays } from '@/db/relays.ts'; import { findUser } from '@/db/users.ts'; import { RelayPool } from '@/deps.ts'; import { trends } from '@/trends.ts'; @@ -7,7 +7,7 @@ import { isRelay, nostrDate, nostrNow } from '@/utils.ts'; import type { SignedEvent } from '@/event.ts'; -const relays = await getAllRelays(); +const relays = await getActiveRelays(); const pool = new RelayPool(relays); // This file watches events on all known relays and performs