From bababe56f30f72b7a57e5c52d2b1108955f721d0 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 10 Dec 2023 11:10:11 -0600 Subject: [PATCH] stats: update note count --- src/db.ts | 20 ++++++++++++++++++-- src/pipeline.ts | 6 +++++- src/stats.ts | 47 +++++++++++++++++++++++++++++++---------------- 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/db.ts b/src/db.ts index a722d4e..6f0397f 100644 --- a/src/db.ts +++ b/src/db.ts @@ -13,6 +13,22 @@ interface DittoDB { users: UserRow; relays: RelayRow; unattached_media: UnattachedMediaRow; + pubkey_stats: PubkeyStatsRow; + event_stats: EventStatsRow; +} + +interface PubkeyStatsRow { + pubkey: string; + followers_count: number; + following_count: number; + notes_count: number; +} + +interface EventStatsRow { + event_id: string; + replies_count: number; + reposts_count: number; + reactions_count: number; } interface EventRow { @@ -101,7 +117,7 @@ async function migrate() { console.log('Everything up-to-date.'); } else { console.log('Migrations finished!'); - for (const { migrationName, status } of results.results) { + for (const { migrationName, status } of results.results!) { console.log(` - ${migrationName}: ${status}`); } } @@ -110,4 +126,4 @@ async function migrate() { await migrate(); -export { db, type DittoDB, type EventRow, type TagRow, type UserRow }; +export { db, type DittoDB, type EventRow, type EventStatsRow, type PubkeyStatsRow, type TagRow, type UserRow }; diff --git a/src/pipeline.ts b/src/pipeline.ts index 9749a9c..d4811e4 100644 --- a/src/pipeline.ts +++ b/src/pipeline.ts @@ -8,6 +8,7 @@ import { isEphemeralKind } from '@/kinds.ts'; import * as mixer from '@/mixer.ts'; import { publish } from '@/pool.ts'; import { isLocallyFollowed } from '@/queries.ts'; +import { updateStats } from '@/stats.ts'; import { Sub } from '@/subs.ts'; import { getTagSet } from '@/tags.ts'; import { eventAge, isRelay, nostrDate, Time } from '@/utils.ts'; @@ -68,7 +69,10 @@ async function storeEvent(event: Event, data: EventData): Promise { if (deletion) { return Promise.reject(new RelayError('blocked', 'event was deleted')); } else { - await eventsDB.insertEvent(event, data).catch(console.warn); + await Promise.all([ + eventsDB.insertEvent(event, data).catch(console.warn), + updateStats(event), + ]); } } else { return Promise.reject(new RelayError('blocked', 'only registered users can post')); diff --git a/src/stats.ts b/src/stats.ts index 741c418..d0d14c0 100644 --- a/src/stats.ts +++ b/src/stats.ts @@ -1,11 +1,17 @@ -import { open as lmdb } from 'npm:lmdb'; +import { db, type PubkeyStatsRow } from '@/db.ts'; import { Event } from '@/deps.ts'; -const db = lmdb({ path: 'data/ditto.lmdb' }); +type PubkeyStat = keyof Omit; /** Store stats for the event in LMDB. */ -async function saveStats(event: Event): Promise { +function updateStats(event: Event) { + return updateStatsQuery(event).execute(); +} + +async function updateStatsQuery(event: Event) { switch (event.kind) { + case 1: + return incrementPubkeyStatQuery(event.pubkey, 'notes_count', 1); case 6: return await incrementMentionedEvent(event, 'reposts'); case 7: @@ -13,20 +19,29 @@ async function saveStats(event: Event): Promise { } } -/** Increment the subkey for the first mentioned event. */ -async function incrementMentionedEvent(event: Event, subkey: string): Promise { - const eventId = event.tags.find(([name]) => name === 'e')?.[1]; - if (eventId) { - return await incrementKey([eventId, subkey]); - } +function incrementPubkeyStatQuery(pubkey: string, stat: PubkeyStat, diff: number) { + const row: PubkeyStatsRow = { + pubkey, + followers_count: 0, + following_count: 0, + notes_count: 0, + }; + + row[stat] = diff; + + return db.insertInto('pubkey_stats') + .values(row) + .onConflict((oc) => + oc + .column('pubkey') + .doUpdateSet((eb) => ({ + [stat]: eb(stat, '+', diff), + })) + ); } -/** Increase the counter by 1, or set the key if it doesn't exist. */ -function incrementKey(key: string[]): Promise { - return db.transaction(() => { - const value = db.get(key) || 0; - db.put(key, value + 1); - }); +function findFirstTag({ tags }: Event, name: string): string | undefined { + return tags.find(([n]) => n === name)?.[1]; } -export { saveStats }; +export { updateStats };