Merge branch 'rm-relays' into 'main'
Remove `relays` table from the database, track them with a NIP-65 admin event See merge request soapbox-pub/ditto!207
This commit is contained in:
commit
79177cd6c3
|
@ -7,7 +7,6 @@
|
|||
"debug": "deno run -A --inspect src/server.ts",
|
||||
"test": "DATABASE_URL=\"sqlite://:memory:\" deno test -A",
|
||||
"check": "deno check src/server.ts",
|
||||
"relays:sync": "deno run -A scripts/relays.ts sync",
|
||||
"nsec": "deno run scripts/nsec.ts",
|
||||
"admin:event": "deno run -A scripts/admin-event.ts",
|
||||
"admin:role": "deno run -A scripts/admin-role.ts"
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
import { addRelays } from '@/db/relays.ts';
|
||||
import { filteredArray } from '@/schema.ts';
|
||||
import { relaySchema } from '@/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 <url>');
|
||||
}
|
||||
|
||||
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, { active: true });
|
||||
console.log(`Done: added ${values.length} relays.`);
|
||||
}
|
|
@ -2,7 +2,6 @@ export interface DittoTables {
|
|||
events: EventRow;
|
||||
events_fts: EventFTSRow;
|
||||
tags: TagRow;
|
||||
relays: RelayRow;
|
||||
unattached_media: UnattachedMediaRow;
|
||||
author_stats: AuthorStatsRow;
|
||||
event_stats: EventStatsRow;
|
||||
|
@ -45,12 +44,6 @@ interface TagRow {
|
|||
event_id: string;
|
||||
}
|
||||
|
||||
interface RelayRow {
|
||||
url: string;
|
||||
domain: string;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
interface UnattachedMediaRow {
|
||||
id: string;
|
||||
pubkey: string;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(_db: Kysely<any>): Promise<void> {
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(_db: Kysely<any>): Promise<void> {
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(_db: Kysely<any>): Promise<void> {
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(_db: Kysely<any>): Promise<void> {
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema.dropTable('users').ifExists().execute();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema.dropIndex('idx_tags_tag').execute();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema.alterTable('events').addColumn('deleted_at', 'integer').execute();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema.createIndex('idx_author_stats_pubkey').on('author_stats').column('pubkey').execute();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Kysely } from '@/deps.ts';
|
||||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { Kysely } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema.dropTable('relays').execute();
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
.createTable('relays')
|
||||
.addColumn('url', 'text', (col) => col.primaryKey())
|
||||
.addColumn('domain', 'text', (col) => col.notNull())
|
||||
.addColumn('active', 'boolean', (col) => col.notNull())
|
||||
.execute();
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
import tldts from 'tldts';
|
||||
|
||||
import { db } from '@/db.ts';
|
||||
|
||||
interface AddRelaysOpts {
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
/** Inserts relays into the database, skipping duplicates. */
|
||||
function addRelays(relays: `wss://${string}`[], opts: AddRelaysOpts = {}) {
|
||||
if (!relays.length) return Promise.resolve();
|
||||
const { active = false } = opts;
|
||||
|
||||
const values = relays.map((url) => ({
|
||||
url: new URL(url).toString(),
|
||||
domain: tldts.getDomain(url)!,
|
||||
active,
|
||||
}));
|
||||
|
||||
return db.insertInto('relays')
|
||||
.values(values)
|
||||
.onConflict((oc) => oc.column('url').doNothing())
|
||||
.execute();
|
||||
}
|
||||
|
||||
/** Get a list of all known active relay URLs. */
|
||||
async function getActiveRelays(): Promise<string[]> {
|
||||
const rows = await db
|
||||
.selectFrom('relays')
|
||||
.select('relays.url')
|
||||
.where('relays.active', '=', true)
|
||||
.execute();
|
||||
|
||||
return rows.map((row) => row.url);
|
||||
}
|
||||
|
||||
export { addRelays, getActiveRelays };
|
|
@ -5,7 +5,6 @@ import { sql } from 'kysely';
|
|||
|
||||
import { Conf } from '@/config.ts';
|
||||
import { db } from '@/db.ts';
|
||||
import { addRelays } from '@/db/relays.ts';
|
||||
import { deleteAttachedMedia } from '@/db/unattached-media.ts';
|
||||
import { DittoEvent } from '@/interfaces/DittoEvent.ts';
|
||||
import { isEphemeralKind } from '@/kinds.ts';
|
||||
|
@ -14,7 +13,7 @@ import { updateStats } from '@/stats.ts';
|
|||
import { hydrateEvents, purifyEvent } from '@/storages/hydrate.ts';
|
||||
import { Storages } from '@/storages.ts';
|
||||
import { getTagSet } from '@/tags.ts';
|
||||
import { eventAge, isRelay, nostrDate, nostrNow, parseNip05, Time } from '@/utils.ts';
|
||||
import { eventAge, nostrDate, nostrNow, parseNip05, Time } from '@/utils.ts';
|
||||
import { fetchWorker } from '@/workers/fetch.ts';
|
||||
import { TrendsWorker } from '@/workers/trends.ts';
|
||||
import { verifyEventWorker } from '@/workers/verify.ts';
|
||||
|
@ -59,7 +58,6 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise<void
|
|||
parseMetadata(event, signal),
|
||||
processDeletions(event, signal),
|
||||
DVM.event(event),
|
||||
trackRelays(event),
|
||||
trackHashtags(event),
|
||||
fetchRelatedEvents(event, signal),
|
||||
processMedia(event),
|
||||
|
@ -183,22 +181,6 @@ async function trackHashtags(event: NostrEvent): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
/** Tracks known relays in the database. */
|
||||
function trackRelays(event: NostrEvent) {
|
||||
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]);
|
||||
}
|
||||
|
||||
/** Queue related events to fetch. */
|
||||
async function fetchRelatedEvents(event: DittoEvent, signal: AbortSignal) {
|
||||
if (!event.user) {
|
||||
|
|
16
src/pool.ts
16
src/pool.ts
|
@ -1,8 +1,20 @@
|
|||
import { RelayPoolWorker } from 'nostr-relaypool';
|
||||
|
||||
import { getActiveRelays } from '@/db/relays.ts';
|
||||
import { Storages } from '@/storages.ts';
|
||||
import { Conf } from '@/config.ts';
|
||||
|
||||
const activeRelays = await getActiveRelays();
|
||||
const [relayList] = await Storages.db.query([
|
||||
{ kinds: [10002], authors: [Conf.pubkey], limit: 1 },
|
||||
]);
|
||||
|
||||
const tags = relayList?.tags ?? [];
|
||||
|
||||
const activeRelays = tags.reduce((acc, [name, url, marker]) => {
|
||||
if (name === 'r' && !marker) {
|
||||
acc.push(url);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
console.log(`pool: connecting to ${activeRelays.length} relays.`);
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { NostrEvent } from '@nostrify/nostrify';
|
||||
import { EventTemplate, getEventHash, nip19 } from 'nostr-tools';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { nostrIdSchema } from '@/schemas/nostr.ts';
|
||||
|
||||
|
@ -82,12 +81,6 @@ async function sha256(message: string): Promise<string> {
|
|||
return hashHex;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
|
||||
/** Deduplicate events by ID. */
|
||||
function dedupeEvents(events: NostrEvent[]): NostrEvent[] {
|
||||
return [...new Map(events.map((event) => [event.id, event])).values()];
|
||||
|
@ -143,13 +136,11 @@ export {
|
|||
eventMatchesTemplate,
|
||||
findTag,
|
||||
isNostrId,
|
||||
isRelay,
|
||||
isURL,
|
||||
type Nip05,
|
||||
nostrDate,
|
||||
nostrNow,
|
||||
parseNip05,
|
||||
relaySchema,
|
||||
sha256,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue