106 lines
2.7 KiB
TypeScript
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,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
})();
|