micro_blog_repo_fetchers/old_node_src/nostr.ts

106 lines
2.7 KiB
TypeScript

import pino from "pino";
import WebSocket from "ws";
import { MicroBlogBackend } from "./pocketbase";
const logger = pino();
const pb = new MicroBlogBackend(logger);
const fetcherNpub = process.env.NOSTR_FETCHER_NPUB;
const myNpub = process.env.NOSTR_ID;
if (!fetcherNpub) {
throw new Error("NOSTR_FETCHER_NPUB is not set");
}
if (!myNpub) {
throw new Error("NOSTR_ID is not set");
}
type NostrTag = ["t" | "r" | "imeta", string];
type NostrEvent = [
"EVENT" | "EOSE",
string,
{
id: string;
pubkey: string;
created_at: number;
kind: number; // 1
tags: NostrTag[];
content: string;
sig: string;
},
];
(async () => {
logger.info("Starting Nostr Fetcher");
// figure out when the last post of wasved
const lastSavedPost = await pb.getLatestPostBySource("nostr");
if (!lastSavedPost) {
throw new Error("No last saved nostr post found");
}
let since: number | undefined;
since = new Date(lastSavedPost.posted).getTime() / 1000;
logger.info(
{ lastSavedPostId: lastSavedPost.id, since },
"lastSavedPost nostr post",
);
// listen for new events for 30 seconds
logger.info("trying to connecting to nostr relay");
const relay = process.env.NOSTR_RELAY;
if (!relay) {
throw new Error("No NOSTR_RELAY environment variable found");
}
const events: NostrEvent[] = [];
const ws = new WebSocket(relay);
ws.on("error", logger.error);
ws.on("message", function message(data: Buffer) {
const decodedData = JSON.parse(
Buffer.from(data).toString("utf8"),
) as NostrEvent;
logger.info({ decodedData }, "recived a message from nostr relay");
if (decodedData[0] === "EVENT") {
events.push(decodedData);
}
});
ws.on("open", function open() {
logger.info("connection established");
ws.send(
JSON.stringify([
"REQ",
fetcherNpub,
{ kinds: [1], authors: [myNpub], ...(since ? { since } : {}) },
]),
);
});
await new Promise((resolve) => setTimeout(resolve, 30000));
logger.info("closing connection to nostr relay");
ws.close();
logger.info({ count: events.length }, "saving nostr posts");
for (const event of events) {
const post = await pb.savePost({
remoteId: event[2].id,
fullPost: event[2],
posted: new Date(event[2].created_at * 1000).toISOString(),
source: "nostr",
authorId: event[1],
});
for (const tag of event[2].tags) {
if (tag[0] === "t") {
await pb.setTag(tag[1], post.id);
} else if (tag[0] === "imeta") {
const value = tag[1];
// remove "url " from the start of the string
const url = value.slice(4);
await pb.saveAndSetImage(
{
remoteURL: url,
},
post.id,
);
}
}
}
})();