From af884d9710dd42c462437c02a53948b09d5d396f Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 23 Jan 2025 12:22:42 -0800 Subject: follows --- lib/nostr.ts | 19 +++++--- lib/strfry.ts | 5 ++- routes/nostr.ts | 136 +++++++++++++++++++++++++++----------------------------- 3 files changed, 84 insertions(+), 76 deletions(-) diff --git a/lib/nostr.ts b/lib/nostr.ts index 21c254e3..9f31f6ad 100644 --- a/lib/nostr.ts +++ b/lib/nostr.ts @@ -151,12 +151,21 @@ export const getProfile = async (pubkey) => { export const getCount = async (pubkey) => { try { - const result = await scan({ authors: [pubkey], kinds: [3] }); - const follows = result.length - ? result[0].tags.filter((t) => t[0] === "p").length - : 0; + let follows = await g(`${pubkey}:follows:n`); + + if (!follows) { + const result = await get({ authors: [pubkey], kinds: [3] }); + follows = result ? result.tags.filter((t) => t[0] === "p").length : 0; + await db.set(`${pubkey}:follows:n`, follows, { EX: 300 }); + } + + let followers = await g(`${pubkey}:followers:n`); + + if (!followers) { + [followers] = await count({ "#p": [pubkey], kinds: [3] }); + await db.set(`${pubkey}:followers:n`, followers, { EX: 300 }); + } - const [followers] = await count({ "#p": [pubkey], kinds: [3] }); return { follows, followers }; } catch (e) { console.log(e); diff --git a/lib/strfry.ts b/lib/strfry.ts index 926ca429..65b77709 100644 --- a/lib/strfry.ts +++ b/lib/strfry.ts @@ -72,7 +72,10 @@ const exec = async (cmd: string, data = ""): Promise => // return r; // }; -export const load = (data) => exec(`echo '${data}' | /app/strfry import --no-verify\n`); +export const load = (data) => + exec( + `echo '${data.replace(/'/g, "'\\''")}' | /app/strfry import --no-verify\n`, + ); export const count = (f) => exec(`/app/strfry scan --count '${JSON.stringify(f)}'\n`); export const scan = (f) => exec(`/app/strfry scan '${JSON.stringify(f)}'\n`); diff --git a/routes/nostr.ts b/routes/nostr.ts index 0bfe9970..24cb3ed6 100644 --- a/routes/nostr.ts +++ b/routes/nostr.ts @@ -1,5 +1,5 @@ import config from "$config"; -import { db } from "$lib/db"; +import { db, g, s } from "$lib/db"; import ln from "$lib/ln"; import { anon, @@ -133,56 +133,14 @@ export default { // if (!relays.includes(config.nostr)) relays.push(config.nostr); if (!verifyEvent(event)) fail("Invalid event"); await load(JSON.stringify(event)); - if (event.kind === 3) db.del(`${pubkey}:follows`); - res.send({}); - } catch (e) { - bail(res, e.message); - } - }, - - async follows(req, res) { - const { - params: { pubkey }, - query: { limit = 20, offset = 0, pubkeysOnly }, - } = req; - try { - const events = await scan({ authors: [pubkey], kinds: [3] }); - if (!events.length) return res.send([]); - - const event = events[0]; - let pubkeys = event.tags - .filter((tag) => tag[0] === "p") - .map((tag) => tag[1]); - - let follows = []; - if (pubkeysOnly) follows = pubkeys; - else { - pubkeys = pubkeys.slice(limit, offset); - const profiles = await scan({ authors: pubkeys, kinds: [0] }); - for (const p of profiles) { - const { content, pubkey } = p; - let user = await getUser(pubkey, fields); - user = { ...user, ...JSON.parse(content) }; - user.pubkey = pubkey; - follows.push(user); - } - - const keys = follows.map((f) => f.pubkey); - const missing = await Promise.all( - pubkeys - .filter((p) => !keys.includes(p)) - .map( - async (pubkey) => (await getUser(pubkey, fields)) || anon(pubkey), - ), - ); - - follows.push(...missing); + if (event.kind === 3) { + db.del(`${pubkey}:follows`); + db.del(`${pubkey}:follows:n`); } - res.send(follows); + res.send({}); } catch (e) { - console.log("follows fail", e); bail(res, e.message); } }, @@ -214,38 +172,76 @@ export default { } }, - async followers(req, res) { + async follows(req, res) { const { params: { pubkey }, - query: { limit = 20, offset = 0 }, + query: { limit = 20, offset = 0, pubkeysOnly }, } = req; try { - const filter = { kinds: [3], "#p": [pubkey] }; - const events = await scan({ ...filter, limit }); - if (!events.length) return res.send([]); + let follows = await g(`${pubkey}:follows`); + if (follows?.length) return res.send(follows); + + const event = await get({ authors: [pubkey], kinds: [3] }); + if (!event) return res.send([]); - const pubkeys = events.map((e) => e.pubkey).slice(offset, limit); + let pubkeys = event.tags + .filter((tag) => tag[0] === "p") + .map((tag) => tag[1]); - const followers = []; - const profiles = await scan({ authors: pubkeys, kinds: [0] }); - for (const p of profiles) { - const { content, pubkey } = p; - let user = await getUser(pubkey, fields); - user = { ...user, ...JSON.parse(content) }; - user.pubkey = pubkey; - followers.push(user); + follows = []; + if (pubkeysOnly) follows = pubkeys; + else { + pubkeys = pubkeys.slice(offset, offset + limit); + follows = ( + await Promise.allSettled( + pubkeys.map(async (pubkey) => ({ + ...(await getProfile(pubkey)), + pubkey, + })), + ) + ) + .filter((r) => r.status === "fulfilled") + .map((r) => r.value); } - const keys = followers.map((f) => f.pubkey); - const missing = await Promise.all( - pubkeys - .filter((p) => !keys.includes(p)) - .map( - async (pubkey) => (await getUser(pubkey, fields)) || anon(pubkey), - ), - ); + await db.set(`${pubkey}:follows`, JSON.stringify(follows), { + EX: 300, + }); - followers.push(...missing); + res.send(follows); + } catch (e) { + console.log("follows fail", e); + bail(res, e.message); + } + }, + + async followers(req, res) { + const { + params: { pubkey }, + query: { limit = 20, offset = 0 }, + } = req; + try { + let followers = await g(`${pubkey}:followers`); + if (followers?.length) return res.send(followers); + + const events = await q({ kinds: [3], "#p": [pubkey], limit }); + if (!events.length) return res.send([]); + + const pubkeys = events.map((e) => e.pubkey).slice(offset, offset + limit); + followers = ( + await Promise.allSettled( + pubkeys.map(async (pubkey) => ({ + ...(await getProfile(pubkey)), + pubkey, + })), + ) + ) + .filter((r) => r.status === "fulfilled") + .map((r) => r.value); + + await db.set(`${pubkey}:followers`, JSON.stringify(followers), { + EX: 300, + }); res.send(followers); } catch (e) { -- cgit v1.2.3