nsite-ts/src/blossom.ts

62 lines
2.1 KiB
TypeScript
Raw Normal View History

2025-03-16 22:18:44 +00:00
import { IncomingMessage } from "node:http";
2024-09-25 13:37:32 -05:00
import { getServersFromServerListEvent, USER_BLOSSOM_SERVER_LIST_KIND } from "blossom-client-sdk";
import { BLOSSOM_SERVERS, MAX_FILE_SIZE } from "./env.js";
import { makeRequestWithAbort } from "./helpers/http.js";
import pool from "./nostr.js";
2024-09-25 13:37:32 -05:00
export async function getUserBlossomServers(pubkey: string, relays: string[]) {
const blossomServersEvent = await pool.get(relays, { kinds: [USER_BLOSSOM_SERVER_LIST_KIND], authors: [pubkey] });
2024-09-25 13:37:32 -05:00
return blossomServersEvent ? getServersFromServerListEvent(blossomServersEvent).map((u) => u.toString()) : undefined;
2024-09-25 13:37:32 -05:00
}
2025-03-16 22:18:44 +00:00
/**
* Downloads a file from multiple servers
* @todo download the file to /tmp and verify it
*/
export function downloadFile(sha256: string, servers = BLOSSOM_SERVERS): Promise<IncomingMessage> {
return new Promise((resolve, reject) => {
const controllers = new Map<string, AbortController>();
// make all requests in parallel
servers.forEach(async (server) => {
const url = new URL(sha256, server);
const controller = new AbortController();
let res: IncomingMessage | undefined = undefined;
controllers.set(server, controller);
2024-09-25 13:37:32 -05:00
2024-10-04 12:31:19 -05:00
try {
2025-03-16 22:18:44 +00:00
const response = await makeRequestWithAbort(url, controller);
res = response;
2024-10-04 12:31:19 -05:00
if (!response.statusCode) throw new Error("Missing headers or status code");
const size = response.headers["content-length"];
if (size && parseInt(size) > MAX_FILE_SIZE) throw new Error("File too large");
2024-09-25 13:37:32 -05:00
2024-10-04 12:31:19 -05:00
if (response.statusCode >= 200 && response.statusCode < 300) {
2025-03-16 22:18:44 +00:00
// cancel the other requests
for (const [other, abort] of controllers) {
if (other !== server) abort.abort();
}
controllers.delete(server);
return resolve(response);
}
2024-10-04 12:31:19 -05:00
} catch (error) {
2025-03-16 22:18:44 +00:00
controllers.delete(server);
if (res) res.resume();
2024-09-25 13:37:32 -05:00
}
2025-03-16 22:18:44 +00:00
// reject if last
if (controllers.size === 0) reject(new Error("Failed to find blob on servers"));
});
// reject if all servers don't respond in 30s
setTimeout(() => {
reject(new Error("Timeout"));
}, 30_000);
});
2024-09-25 13:37:32 -05:00
}