From 1d67181e5299537fff3706e134510821eaf3db7b Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 25 Jul 2023 17:07:09 -0500 Subject: [PATCH] Add trends controller... and it kind of works! --- deno.json | 2 +- src/app.ts | 4 ++++ src/controllers/api/trends.ts | 23 +++++++++++++++++++++++ src/loopback.ts | 12 +++++------- src/trends.test.ts | 8 +++++++- src/trends.ts | 15 +++++++++++---- 6 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 src/controllers/api/trends.ts diff --git a/deno.json b/deno.json index bf7bc4f..f0c10e6 100644 --- a/deno.json +++ b/deno.json @@ -2,7 +2,7 @@ "$schema": "https://deno.land/x/deno@v1.32.3/cli/schemas/config-file.v1.json", "lock": false, "tasks": { - "dev": "deno run --allow-read --allow-env --allow-net --allow-ffi --unstable --watch src/server.ts", + "dev": "deno run --allow-read --allow-write --allow-env --allow-net --allow-ffi --unstable --watch src/server.ts", "test": "deno test -A --unstable src" }, "imports": { diff --git a/src/app.ts b/src/app.ts index a2f43c3..af95656 100644 --- a/src/app.ts +++ b/src/app.ts @@ -27,6 +27,7 @@ import { statusController, } from './controllers/api/statuses.ts'; import { streamingController } from './controllers/api/streaming.ts'; +import { trendingTagsController } from './controllers/api/trends.ts'; import { indexController } from './controllers/site.ts'; import { hostMetaController } from './controllers/well-known/host-meta.ts'; import { nodeInfoController, nodeInfoSchemaController } from './controllers/well-known/nodeinfo.ts'; @@ -101,6 +102,9 @@ app.get('/api/v2/search', searchController); app.get('/api/pleroma/frontend_configurations', frontendConfigController); +app.get('/api/v1/trends/tags', trendingTagsController); +app.get('/api/v1/trends', trendingTagsController); + // Not (yet) implemented. app.get('/api/v1/notifications', emptyArrayController); app.get('/api/v1/bookmarks', emptyArrayController); diff --git a/src/controllers/api/trends.ts b/src/controllers/api/trends.ts new file mode 100644 index 0000000..f88b486 --- /dev/null +++ b/src/controllers/api/trends.ts @@ -0,0 +1,23 @@ +import { type AppController } from '@/app.ts'; +import { Conf } from '@/config.ts'; +import { trends } from '@/trends.ts'; +import { Time } from '@/utils.ts'; + +const trendingTagsController: AppController = (c) => { + const yesterday = new Date(new Date().getTime() - Time.days(1)); + const now = new Date(); + + const tags = trends.getTrendingTags(yesterday, now); + + return c.json(tags.map(({ name, accounts }) => ({ + name, + url: Conf.local(`/tags/${name}`), + history: [{ + day: String(Math.floor(yesterday.getTime() / 1000)), + uses: String(accounts), // Not actually true - we don't collect this + accounts: String(accounts), + }], + }))); +}; + +export { trendingTagsController }; diff --git a/src/loopback.ts b/src/loopback.ts index 30256de..b971501 100644 --- a/src/loopback.ts +++ b/src/loopback.ts @@ -1,17 +1,15 @@ import { Conf } from '@/config.ts'; -import { relayInit, Sqlite } from '@/deps.ts'; -import { TrendsDB } from '@/trends.ts'; - -const db = new Sqlite('data/trends.sqlite3'); -const trends = new TrendsDB(db); +import { relayInit } from '@/deps.ts'; +import { trends } from '@/trends.ts'; +import { nostrNow } from '@/utils.ts'; const relay = relayInit(Conf.relay); await relay.connect(); -const sub = relay.sub([{ kinds: [1] }]); +const sub = relay.sub([{ kinds: [1], since: nostrNow() }]); -sub.on('eose', sub.unsub); sub.on('event', (event) => { + console.info('loopback event:', event.id); const tags = event.tags .filter((tag) => tag[0] === 't') .map((tag) => tag[1]); diff --git a/src/trends.test.ts b/src/trends.test.ts index 76de876..3f7eaeb 100644 --- a/src/trends.test.ts +++ b/src/trends.test.ts @@ -18,7 +18,13 @@ Deno.test('getTrendingTags', () => { new Date('2999-01-01T00:00:00'), ); - assertEquals(result, ['ditto', 'hello', 'yolo']); + const expected = [ + { name: 'ditto', accounts: 3 }, + { name: 'hello', accounts: 2 }, + { name: 'yolo', accounts: 1 }, + ]; + + assertEquals(result, expected); trends.cleanupTagUsages(new Date('2999-01-01T00:00:00')); }); diff --git a/src/trends.ts b/src/trends.ts index 2575851..4831168 100644 --- a/src/trends.ts +++ b/src/trends.ts @@ -18,7 +18,7 @@ class TrendsDB { `); } - getTrendingTags(since: Date, until: Date): string[] { + getTrendingTags(since: Date, until: Date) { return this.#db.query( ` SELECT tag, COUNT(DISTINCT pubkey8) @@ -29,12 +29,15 @@ class TrendsDB { DESC LIMIT 10; `, [since, until], - ).map((row) => row[0]); + ).map((row) => ({ + name: row[0], + accounts: Number(row[1]), + })); } addTagUsages(pubkey: string, hashtags: string[]): void { const pubkey8 = hexIdSchema.parse(pubkey).substring(0, 8); - const tags = hashtagSchema.array().parse(hashtags); + const tags = hashtagSchema.array().min(1).parse(hashtags); const now = new Date(); this.#db.query( @@ -51,4 +54,8 @@ class TrendsDB { } } -export { TrendsDB }; +const trends = new TrendsDB( + new Sqlite('data/trends.sqlite3'), +); + +export { trends, TrendsDB };