From 33d8a7d5235281d705bc1ac27113e150b2b9c617 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 28 Dec 2022 15:05:56 -0800 Subject: fix follows and followers endpoints --- lib/nostr.js | 46 +++++++++++++++++++++++++++++++--------------- lib/utils.js | 3 +++ routes/events.js | 5 ++++- routes/users.js | 54 ++++++++++++++++++++++++++++++++++++++---------------- 4 files changed, 76 insertions(+), 32 deletions(-) diff --git a/lib/nostr.js b/lib/nostr.js index 257bca9e..034a4aaa 100644 --- a/lib/nostr.js +++ b/lib/nostr.js @@ -41,32 +41,35 @@ pool.on("event", async (relay, sub, ev) => { let newuser = { username: pubkey.substr(0, 6), pubkey, - anon: true + anon: true, + follows: [], + followers: [] }; ev.user = JSON.parse(await redis.get(`user:${pubkey}`)) || newuser; - if (!ev.user.initialized) { - relay.subscribe("zero", { - limit: 1, - kinds: [0], - authors: [pubkey] - }); - } - - if (ev.kind === 1) { - broadcast("event", ev); - } + relay.subscribe("zero", { + limit: 1, + kinds: [0], + authors: [pubkey] + }); + + broadcast("event", ev); } } else if (sub === "zero") { let { pubkey } = ev; let newuser = { username: pubkey.substr(0, 6), pubkey, - anon: true + anon: true, + follows: [], + followers: [] }; let user = JSON.parse(await redis.get(`user:${pubkey}`)) || newuser; + + if (user.profileUpdated > ev.created_at) return; + if (parsed.name && user.username === pubkey.substr(0, 6)) user.username = parsed.name; @@ -75,17 +78,30 @@ pool.on("event", async (relay, sub, ev) => { user = { ...user, ...parsed, - initialized: true + initialized: true, + profileUpdated: ev.created_at }; await redis.set(`user:${pubkey}`, JSON.stringify(user)); + await redis.set(`user:${user.username}`, JSON.stringify(user)); } else if (sub.includes("follows")) { let pubkey = sub.split(":")[0]; await redis.set(`${pubkey}:follows`, JSON.stringify(ev.tags)); for (let f of ev.tags) { - await redis.sAdd(`${f[1]}:followers`, pubkey); + let [_, followPubkey] = f; + pool.subscribe("zero", { + limit: 1, + kinds: [0], + authors: [followPubkey] + }); + await redis.sAdd(`${followPubkey}:followers`, pubkey); } store.fetching[pubkey] = false; + } else if (sub.includes("followers")) { + let followed = sub.split(":")[0]; + let { pubkey } = ev; + await redis.sAdd(`${followed}:followers`, pubkey); + store.fetching[pubkey] = false; } else { if (!relay.url.includes("coinos")) return; diff --git a/lib/utils.js b/lib/utils.js index 17283836..5355cc2c 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -10,6 +10,7 @@ import lnd from "$lib/lnd"; import ln from "$lib/ln"; import { coinos } from "$lib/nostr"; + const { Op } = sequelize; export const sleep = n => new Promise(r => setTimeout(r, n)); @@ -204,3 +205,5 @@ export const derivePayRequest = async ({ amount, memo, tip }) => { await ln.invoice(value ? `${value}sat` : "any", new Date(), memo, 360) ).bolt11; }; + +export const uniq = (a, k) => [...new Map(a.map(x => [k(x), x])).values()]; diff --git a/routes/events.js b/routes/events.js index 63189f70..3f42fead 100644 --- a/routes/events.js +++ b/routes/events.js @@ -23,7 +23,7 @@ app.get("/nostr/:pubkey", async (req, res) => { }); } - if (!user) user = { username: pubkey.substr(0, 6), pubkey, anon: true }; + if (!user) user = { username: pubkey.substr(0, 6), pubkey, anon: true, follows: [], followers: [] }; let { since } = user; @@ -33,6 +33,9 @@ app.get("/nostr/:pubkey", async (req, res) => { authors: [pubkey] }); + coinos.subscribe(`${pubkey}:followers`, { since, kinds: [3], "#p": [pubkey] }); + + user.since = Math.round(Date.now() / 1000); await redis.set(`user:${pubkey}`, JSON.stringify(user)); diff --git a/routes/users.js b/routes/users.js index 7a01f25e..d19e42ea 100644 --- a/routes/users.js +++ b/routes/users.js @@ -3,7 +3,7 @@ import redis from "$lib/redis"; import config from "$config"; import store from "$lib/store"; import { auth, optionalAuth } from "$lib/passport"; -import { getUser, wait } from "$lib/utils"; +import { getUser, uniq, wait } from "$lib/utils"; import axios from "axios"; import bcrypt from "bcrypt"; import jwt from "jsonwebtoken"; @@ -99,9 +99,23 @@ app.get("/users/:username", async (req, res) => { ) }); + if (user) user = user.get({ plain: true }); + else user = JSON.parse(await redis.get(`user:${username}`)); + + if (!user && username.length === 64) { + let newuser = { + username: username.substr(0, 6), + pubkey: username, + anon: true, + follows: [], + followers: [] + }; + + user = JSON.parse(await redis.get(`user:${newuser.pubkey}`)) || newuser; + } + if (!user) return res.code(500).send("User not found"); - user = user.get({ plain: true }); let { pubkey } = user; if (pubkey) { @@ -125,6 +139,7 @@ app.get("/users/:username", async (req, res) => { res.send(user); } catch (e) { + console.log(e); res.code(500).send(e.message); } }); @@ -668,15 +683,19 @@ app.post("/checkPassword", auth, async function(req, res) { app.get("/:pubkey/follows", async (req, res) => { try { let { pubkey } = req.params; - let follows = JSON.parse(await redis.get(`${pubkey}:follows`)) || []; + let tags = JSON.parse(await redis.get(`${pubkey}:follows`)) || []; - if (follows.length) { - follows = await db.User.findAll({ - where: { pubkey: follows.map(t => t[1]) } - }); - - res.send(follows); + let follows = []; + for (let f of tags) { + let [_, pubkey] = f; + let user = JSON.parse(await redis.get(`user:${pubkey}`)); + if (user) follows.push(user); } + + follows = uniq(follows, e => e.pubkey); + follows.sort((a, b) => a.username.localeCompare(b.username)); + + res.send(follows); } catch (e) { console.log(e); res.code(500).send(e.message); @@ -686,15 +705,18 @@ app.get("/:pubkey/follows", async (req, res) => { app.get("/:pubkey/followers", async (req, res) => { try { let { pubkey } = req.params; - let followers = await redis.sMembers(`${pubkey}:followers`); + let pubkeys = await redis.sMembers(`${pubkey}:followers`); - if (followers.length) { - followers = await db.User.findAll({ - where: { pubkey: followers } - }); - - res.send(followers); + let followers = []; + for (let pubkey of pubkeys) { + let user = JSON.parse(await redis.get(`user:${pubkey}`)); + if (user) followers.push(user); } + + followers = uniq(followers, e => e.pubkey); + followers.sort((a, b) => a.username.localeCompare(b.username)); + + res.send(followers); } catch (e) { console.log(e); res.code(500).send(e.message); -- cgit v1.2.3