diff options
| author | Adam Soltys <[email protected]> | 2023-02-06 16:48:13 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2023-02-06 16:48:13 -0800 |
| commit | 9c667055c6367e1b2e239686e72f52995679a47e (patch) | |
| tree | 0b1d4aee51ec2d4e92d08a9d1404ba4e2ecd462a /lib/nostr.js | |
| parent | 15294844dbc8e73b4d1e92008a7eebc6b86b9ec5 (diff) | |
| parent | 6f5602d112b68adb7452abf3047f20c32e7725b6 (diff) | |
| download | coinos-server-9c667055c6367e1b2e239686e72f52995679a47e.tar.gz coinos-server-9c667055c6367e1b2e239686e72f52995679a47e.zip | |
Merge branch 'master' into test
Diffstat (limited to 'lib/nostr.js')
| -rw-r--r-- | lib/nostr.js | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/lib/nostr.js b/lib/nostr.js new file mode 100644 index 00000000..065fafb0 --- /dev/null +++ b/lib/nostr.js @@ -0,0 +1,164 @@ +import config from "$config"; +import { Relay, RelayPool } from "nostr"; +import { broadcast } from "$lib/sockets"; +import store from "$lib/store"; +import { g, s, db } from "$lib/db"; +import { nada, wait } from "$lib/utils"; + +export let pool; + +export let fillPool = () => { + pool = RelayPool(config.relays); + pool.on("open", relay => { + if (relay.url.includes(config.relay)) coinos = relay; + relay.subscribe("live", { limit: 1 }); + }); + + pool.on("event", async (relay, sub, ev) => { + if (!coinos) return; + if (timeouts[sub]) timeouts[sub].extend(ev); + try { + let content; + try { + content = JSON.parse(ev.content); + } catch (e) { + content = ev.content; + } + + if (sub === "live") { + let { pubkey } = ev; + + if (Math.abs(Math.floor(Date.now() / 1000) - ev.created_at) > 7200) + return; + + if (seen.includes(ev.id)) return; + seen.push(ev.id); + seen.length > 1000 && seen.shift(); + + if (coinos && ev.kind < 5) { + // coinos.send(["EVENT", ev]); + ev.user = await getUser(pubkey); + // broadcast("event", ev); + } + } else if (sub.includes("profile")) { + let { pubkey } = ev; + let user = await getUser(pubkey); + + if (user.updated > ev.created_at) return; + + if (content.name && user.username === pubkey.substr(0, 6)) + user.username = content.name; + + delete content.name; + + user = { + ...user, + ...content, + updated: ev.created_at + }; + + await s(`user:${pubkey}`, JSON.stringify(user)); + coinos.send(ev); + } else if (sub.includes("follows")) { + let pubkey = sub.split(":")[0]; + await s(`${pubkey}:follows`, JSON.stringify(ev.tags)); + for (let f of ev.tags) { + let [_, followPubkey] = f; + await db.sAdd(`${followPubkey}:followers`, pubkey); + } + coinos.send(ev); + } else if (sub.includes("followers")) { + let followed = sub.split(":")[0]; + let { pubkey } = ev; + await db.sAdd(`${followed}:followers`, pubkey); + coinos.send(ev); + } else if (sub.includes("notes")) { + let pubkey = sub.split(":")[0]; + await db.sAdd(pubkey, ev.id); + await s(`ev:${ev.id}`, JSON.stringify(ev)); + } + } catch (e) { + console.log(e); + } + }); +}; + +export let coinos; +let now = () => Math.round(Date.now() / 1000); + +let timeouts = {}; +export let q = async ( + sub, + query, + { timeout = 20000, since = 3600, eager = 200 } +) => + new Promise(async (r, j) => { + let start = Date.now(); + let seen = []; + let rejected; + query.since = await g(`since:${sub}`); + if (now() - query.since < since) return r(); + + let done = { [sub]: [] }; + + let check = s => { + let elapsed = Date.now() - start; + if (rejected) return true; + if ( + done[s] && + (done[s].length === pool.relays.length || + (done[s].length && elapsed > eager)) + ) { + r(); + if (timeouts[s]) timeouts[s].clear(); + return true; + } + }; + + timeouts[sub] = { + async clear() { + clearTimeout(this.timer); + delete timeouts[sub]; + pool.unsubscribe(sub); + await s(`since:${sub}`, now()); + }, + extend(ev) { + if (ev) { + if (seen.includes(ev.id)) return; + seen.push(ev.id); + seen.length > 1000 && seen.shift(); + } + + clearTimeout(this.timer); + this.timer = setTimeout(() => { + j(new Error(`query timed out: ${sub} ${Date.now()}`)); + pool.unsubscribe(sub); + rejected = true; + }, timeout); + }, + timer: undefined + }; + + timeouts[sub].extend(); + pool.subscribe(sub, query); + + pool.on("eose", (relay, s) => { + if (done[s]) done[s].push(relay.url); + check(s); + }); + + try { + await wait(() => check(sub), 100, 200); + } catch (e) { + console.log(e); + } + }); + +let seen = []; + +let getUser = async pubkey => + JSON.parse(await g(`user:${pubkey}`)) || { + username: pubkey.substr(0, 6), + pubkey, + anon: true + }; |
