From 24efca5ea0ad6b265463c51b70b6e3e483587ce1 Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Fri, 12 Apr 2024 21:51:57 -0300 Subject: [PATCH] perf: hydrate repost event in home timeline --- src/controllers/api/statuses.ts | 2 +- src/controllers/api/streaming.ts | 2 +- src/controllers/api/timelines.ts | 9 +++++++-- src/storages/hydrate.ts | 22 ++++++++++++++++++++++ src/views/mastodon/statuses.ts | 12 ++++++++++-- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/controllers/api/statuses.ts b/src/controllers/api/statuses.ts index afd3673..66018ac 100644 --- a/src/controllers/api/statuses.ts +++ b/src/controllers/api/statuses.ts @@ -226,7 +226,7 @@ const reblogStatusController: AppController = async (c) => { tags: [['e', event.id], ['p', event.pubkey]], }, c); - const status = await renderReblog(reblogEvent); + const status = await renderReblog(reblogEvent, { loadOriginalPostEvent: true }); return c.json(status); }; diff --git a/src/controllers/api/streaming.ts b/src/controllers/api/streaming.ts index ed6ccdd..becf46a 100644 --- a/src/controllers/api/streaming.ts +++ b/src/controllers/api/streaming.ts @@ -64,7 +64,7 @@ const streamingController: AppController = (c) => { if (filter) { for await (const event of Sub.sub(socket, '1', [filter])) { if (event.kind === 6) { - const status = await renderReblog(event); + const status = await renderReblog(event, { loadOriginalPostEvent: true }); if (status) { send('update', status); } diff --git a/src/controllers/api/timelines.ts b/src/controllers/api/timelines.ts index 677bc60..0809835 100644 --- a/src/controllers/api/timelines.ts +++ b/src/controllers/api/timelines.ts @@ -49,7 +49,12 @@ async function renderStatuses(c: AppContext, filters: NostrFilter[]) { const events = await eventsDB .query(filters, { signal }) .then((events) => - hydrateEvents({ events, relations: ['author', 'author_stats', 'event_stats'], storage: eventsDB, signal }) + hydrateEvents({ + events, + relations: ['author', 'author_stats', 'event_stats', 'repost'], + storage: eventsDB, + signal, + }) ); if (!events.length) { @@ -58,7 +63,7 @@ async function renderStatuses(c: AppContext, filters: NostrFilter[]) { const statuses = (await Promise.all(events.map((event) => { if (event.kind === 6) { - return renderReblog(event); + return renderReblog(event, {}); } return renderStatus(event, c.get('pubkey')); }))).filter((boolean) => boolean); diff --git a/src/storages/hydrate.ts b/src/storages/hydrate.ts index e56ebe6..06cd37c 100644 --- a/src/storages/hydrate.ts +++ b/src/storages/hydrate.ts @@ -3,6 +3,7 @@ import { db } from '@/db.ts'; import { type NostrEvent, type NStore } from '@/deps.ts'; import { type DittoEvent } from '@/interfaces/DittoEvent.ts'; import { type DittoRelation } from '@/interfaces/DittoFilter.ts'; +import { eventsDB } from '@/storages.ts'; interface HydrateEventOpts { events: DittoEvent[]; @@ -33,6 +34,9 @@ async function hydrateEvents(opts: HydrateEventOpts): Promise { case 'user': await hydrateUsers({ events, storage, signal }); break; + case 'repost': + await hydrateRepostEvents(events); + break; } } @@ -111,6 +115,24 @@ async function hydrateEventStats(events: DittoEvent[]): Promise { return events; } +async function hydrateRepostEvents(events: DittoEvent[]): Promise { + const results = await eventsDB.query([{ kinds: [1], ids: events.map((event) => event.id) }]); + + for (const event of events) { + if (event.kind === 6) { + const originalPostId = event.tags.find(([name]) => name === 'e')?.[1]; + if (!originalPostId) continue; + + const originalPostEvent = results.find((event) => event.id === originalPostId); + if (!originalPostEvent) continue; + + event.repost = originalPostEvent; + } + } + + return events; +} + /** Return a normalized event without any non-standard keys. */ function purifyEvent(event: NostrEvent): NostrEvent { return { diff --git a/src/views/mastodon/statuses.ts b/src/views/mastodon/statuses.ts index 6762e82..b9ea949 100644 --- a/src/views/mastodon/statuses.ts +++ b/src/views/mastodon/statuses.ts @@ -100,13 +100,21 @@ async function renderStatus(event: DittoEvent, viewerPubkey?: string) { }; } -async function renderReblog(event: DittoEvent) { +type reblogOpts = { + loadOriginalPostEvent?: boolean; +}; + +async function renderReblog(event: DittoEvent, opts: reblogOpts) { + const { loadOriginalPostEvent } = opts; + if (!event.author) return; const repostId = event.tags.find(([name]) => name === 'e')?.[1]; if (!repostId) return; - event.repost = await getEvent(repostId, { kind: 1 }); + if (loadOriginalPostEvent) { + event.repost = await getEvent(repostId, { kind: 1 }); + } if (!event.repost) return; const reblog = await renderStatus(event.repost);