aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/nostr.ts30
-rw-r--r--lib/strfry.ts102
-rw-r--r--lib/utils.ts1
-rw-r--r--routes/nostr.ts72
-rwxr-xr-xstrsrvbin0 -> 420516 bytes
5 files changed, 97 insertions, 108 deletions
diff --git a/lib/nostr.ts b/lib/nostr.ts
index 0bb01521..4fb92b86 100644
--- a/lib/nostr.ts
+++ b/lib/nostr.ts
@@ -1,13 +1,15 @@
import config from "$config";
import { db, g, s } from "$lib/db";
import { l, warn } from "$lib/logging";
-import { count, scan, sync } from "$lib/strfry";
+import { scan } from "$lib/strfry";
import { fail, fields, getUser, pick } from "$lib/utils";
import { finalizeEvent, getPublicKey, nip19 } from "nostr-tools";
+import type { Event } from "nostr-tools";
import { AbstractSimplePool } from "nostr-tools/abstract-pool";
import { Relay } from "nostr-tools/relay";
export const EX = 60 * 60 * 24;
+const coinos = await Relay.connect(config.nostr);
export const serverPubkey = getPublicKey(
nip19.decode(config.nostrKey).data as Uint8Array,
@@ -158,7 +160,8 @@ export const getCount = async (pubkey) => {
if (follows === null) {
const result = await get({ authors: [pubkey], kinds: [3] });
follows = result ? result.tags.filter((t) => t[0] === "p").length : 0;
- if (follows?.length) await db.set(`${pubkey}:follows:n`, JSON.stringify(follows), { EX });
+ if (follows?.length)
+ await db.set(`${pubkey}:follows:n`, JSON.stringify(follows), { EX });
}
const k = `${pubkey}:followers:n`;
@@ -215,19 +218,28 @@ export const getNostrUser = async (key) => {
};
export const q = async (f) => {
- const events = await scan(f);
+ let events = (await scan(f)) as Event[];
const k = JSON.stringify(f).replace(/[^a-zA-Z0-9]/g, "");
const since = await g(`${k}:since}`);
if (since) f.since = since;
- const p = sync("wss://relay.primal.net", f).then(async () => {
- const r = await scan(f);
- if (r.length) await s(`${k}:since`, r[r.length - 1].created_at);
- return r;
+ const p = new Promise((resolve) => {
+ const r = [];
+ pool.subscribeMany(["wss://relay.primal.net"], [f], {
+ onevent(e) {
+ r.push(e);
+ coinos.publish(e);
+ },
+ oneose() {
+ resolve(r);
+ },
+ });
});
- if (events.length > 0) return events;
- return p;
+ if (events.length) return events;
+ events = (await p) as Event[];
+ if (events.length) db.set(`${k}:since`, events[events.length - 1].created_at);
+ return events;
};
export const get = async (f) => {
diff --git a/lib/strfry.ts b/lib/strfry.ts
index 65b77709..b2791e74 100644
--- a/lib/strfry.ts
+++ b/lib/strfry.ts
@@ -1,83 +1,29 @@
-import { randomUUID } from "crypto";
-import { connect, createServer } from "net";
+import * as net from "net";
import type { Event } from "nostr-tools";
-const exec = async (cmd: string, data = ""): Promise<Event[]> =>
- new Promise((resolve, reject) => {
- const c = `${cmd} 2>/dev/null`;
- const id = randomUUID();
- const resultSocketPath = `/sockets/result_${id}`;
-
- const resultServer = createServer((socket) => {
- let resultBuffer = "";
-
- const results = [];
- socket.on("data", (chunk) => {
- resultBuffer += chunk.toString();
- const parts = resultBuffer.split("\n");
-
- for (let i = 0; i < parts.length - 1; i++) {
- try {
- const parsedObject = JSON.parse(parts[i]);
- results.push(parsedObject);
- } catch (e) {
- console.error("Failed to parse:", parts[i]);
- }
- }
+const controlSocketPath = "/home/bun/app/data/sockets/strsrv.sock";
- resultBuffer = parts[parts.length - 1];
- });
-
- socket.on("end", () => {
- socket.write("DONE");
- resolve(results);
- socket.end();
-
- resultServer.close();
- });
- });
-
- resultServer.listen(resultSocketPath, () => {
- const controlClient = connect("/sockets/ctrl", () => {
- // Send the command and data payload
- const message = `${resultSocketPath} ${c}\n${data}\n`;
- controlClient.write(message);
- controlClient.end();
- });
-
- controlClient.on("error", (e) => {
- reject(`Control socket error: ${e.message}`);
+export const scan = (f: object): Promise<Event[]> =>
+ new Promise((resolve, reject) => {
+ const result = [];
+ const client = net
+ .createConnection(controlSocketPath)
+ .on("connect", () => {
+ client.write(`${JSON.stringify(f)}\n`);
+ })
+ .on("data", (data) => {
+ result.push(data);
+ })
+ .on("end", () => {
+ resolve(
+ Buffer.concat(result)
+ .toString("utf8")
+ .split("\n")
+ .filter((l) => l)
+ .map((l) => JSON.parse(l) as Event),
+ );
+ })
+ .on("error", (e) => {
+ reject(e.message);
});
- });
-
- resultServer.on("error", (e) => {
- reject(`Result server error: ${e.message}`);
- });
});
-
-// const filter2params = (f) => {
-// let r = "";
-//
-// const { limit, since, until } = f;
-//
-// if (limit) r += `-l ${limit} `;
-// if (since) r += `-s ${since} `;
-// if (until) r += `-u ${until} `;
-//
-// for (const k of f.kinds || []) r += `-k ${k} `;
-// for (const a of f.authors || []) r += `-a ${a} `;
-// for (const e of f["#e"] || []) r += `-e ${e} `;
-// for (const p of f["#p"] || []) r += `-p ${p} `;
-//
-// return r;
-// };
-
-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`);
-export const sync = (r, f) =>
- exec(`/app/strfry sync ${r} --dir down --filter '${JSON.stringify(f)}'\n`);
diff --git a/lib/utils.ts b/lib/utils.ts
index a0a831d9..79b95e62 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -2,7 +2,6 @@ import config from "$config";
import { g, s } from "$lib/db";
import locales from "$lib/locales/index";
import migrate from "$lib/migrate";
-import whitelist from "$lib/whitelist";
import { bytesToHex, randomBytes } from "@noble/hashes/utils";
import { getPublicKey } from "nostr";
diff --git a/routes/nostr.ts b/routes/nostr.ts
index 962e45f9..5000ccc7 100644
--- a/routes/nostr.ts
+++ b/routes/nostr.ts
@@ -1,3 +1,4 @@
+import config from "$config";
import { db, g, s } from "$lib/db";
import ln from "$lib/ln";
import {
@@ -6,11 +7,12 @@ import {
getCount,
getNostrUser,
getProfile,
+ pool,
q,
serverPubkey,
} from "$lib/nostr";
import { parseContent } from "$lib/notes";
-import { load, scan, sync } from "$lib/strfry";
+import { scan } from "$lib/strfry";
import { bail, fail, fields, getUser } from "$lib/utils";
import got from "got";
import type { Event } from "nostr-tools";
@@ -36,18 +38,12 @@ export default {
if (!full) return res.send(event);
const parts = parseContent(event);
- const names = {};
- for (const { type, value } of parts) {
- if (type.includes("nprofile") || type.includes("npub")) {
- const { name } = await getProfile(value.pubkey);
- names[value.pubkey] = name;
- }
- }
-
- event.parts = parts;
- event.names = names;
- event.author = await getProfile(event.pubkey);
+ let pubkeys = parts
+ .filter(
+ ({ type }) => type.includes("nprofile") || type.includes("npub"),
+ )
+ .map(({ value }) => value.pubkey);
const zapEvents = await scan({ kinds: [9735], "#e": [id] });
const zaps = [];
@@ -61,16 +57,52 @@ export default {
if (amount_msat) amount = Math.round(amount_msat / 1000);
} catch (e) {}
- let user;
- if (pubkey) {
- try {
- user = await getNostrUser(pubkey);
- zaps.push({ amount, user });
- } catch (e) {}
- }
+ zaps.push({ amount, pubkey });
}
- event.zaps = zaps.filter((z) => z.amount > 0);
+ pubkeys.push(event.pubkey);
+ pubkeys.push(...zaps.map((z) => z.pubkey));
+ pubkeys = [...new Set(pubkeys)];
+ const profiles = await scan({ kinds: [0], authors: pubkeys });
+ const found = profiles.map((p) => p.pubkey);
+ const missing = pubkeys.filter((p) => !found.includes(p));
+
+ const missingProfiles = (
+ await pool.querySync(config.relays, {
+ kinds: [0],
+ authors: missing,
+ })
+ )
+ .reduce((a, b) => {
+ a.set(
+ b.pubkey,
+ b.created_at > (a.get(b.pubkey)?.created_at || 0)
+ ? b
+ : a.get(b.pubkey),
+ );
+ return a;
+ }, new Map())
+ .values();
+
+ profiles.push(...missingProfiles);
+
+ event.parts = parts;
+ event.names = profiles.reduce((a, b) => {
+ const { content } = b;
+ const { name } = JSON.parse(content);
+ a[b.pubkey] = name;
+ return a;
+ }, {});
+
+ event.author = profiles.find((p) => p.pubkey === event.pubkey);
+
+ event.zaps = zaps
+ .filter((z) => z.amount > 0)
+ .map(({ amount, pubkey }) => ({
+ amount,
+ user: profiles.find((p) => p.pubkey === pubkey),
+ }));
+
await db.set(k, JSON.stringify(event), { EX });
res.send(event);
diff --git a/strsrv b/strsrv
new file mode 100755
index 00000000..39240ff4
--- /dev/null
+++ b/strsrv
Binary files differ