mirror of
https://github.com/hzrd149/nsite-gateway.git
synced 2025-09-24 12:36:10 +00:00
Compare commits
No commits in common. "193db371e3250140b4eee92809440736ea07d239" and "f3cf298ea57137fa2f06423fc44ccda33ac01a38" have entirely different histories.
193db371e3
...
f3cf298ea5
@ -1,11 +1,5 @@
|
||||
# nsite-gateway
|
||||
|
||||
## 1.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 100ff4c: Add more debug logging to blob streaming
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
22
package.json
22
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nsite-gateway",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.0",
|
||||
"description": "A blossom server implementation written in Typescript",
|
||||
"main": "build/index.js",
|
||||
"type": "module",
|
||||
@ -24,24 +24,24 @@
|
||||
"@koa/cors": "^5.0.0",
|
||||
"debug": "^4.4.1",
|
||||
"dotenv": "^16.6.1",
|
||||
"follow-redirects": "^1.15.11",
|
||||
"keyv": "^5.5.0",
|
||||
"koa": "^2.16.2",
|
||||
"follow-redirects": "^1.15.9",
|
||||
"keyv": "^5.4.0",
|
||||
"koa": "^2.16.1",
|
||||
"koa-morgan": "^1.0.1",
|
||||
"koa-range": "^0.3.0",
|
||||
"koa-send": "^5.0.1",
|
||||
"koa-static": "^5.0.0",
|
||||
"mime": "^4.0.7",
|
||||
"nostr-tools": "^2.16.2",
|
||||
"nostr-tools": "^2.15.1",
|
||||
"pac-proxy-agent": "^7.2.0",
|
||||
"proxy-agent": "^6.5.0",
|
||||
"ws": "^8.18.3",
|
||||
"xbytes": "^1.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.29.6",
|
||||
"@swc-node/register": "^1.11.1",
|
||||
"@swc/core": "^1.13.5",
|
||||
"@changesets/cli": "^2.29.5",
|
||||
"@swc-node/register": "^1.10.10",
|
||||
"@swc/core": "^1.13.1",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/follow-redirects": "^1.14.4",
|
||||
@ -52,13 +52,13 @@
|
||||
"@types/koa-static": "^4.0.4",
|
||||
"@types/koa__cors": "^5.0.0",
|
||||
"@types/koa__router": "^12.0.4",
|
||||
"@types/node": "^20.19.13",
|
||||
"@types/node": "^20.19.9",
|
||||
"@types/proxy-from-env": "^1.0.4",
|
||||
"@types/ws": "^8.18.1",
|
||||
"esbuild": "^0.25.9",
|
||||
"esbuild": "^0.25.8",
|
||||
"nodemon": "^3.1.10",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "^5.9.2"
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"websocket-polyfill": "1.0.0"
|
||||
|
793
pnpm-lock.yaml
generated
793
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -12,34 +12,19 @@ export async function findBlobURLs(sha256: string, servers: string[]): Promise<s
|
||||
const cache = await blobURLs.get(sha256);
|
||||
if (cache) return cache;
|
||||
|
||||
const id = sha256.slice(0, 6);
|
||||
const requestLog = log.extend(id);
|
||||
|
||||
requestLog(`Checking ${servers.length} servers for ${sha256}`);
|
||||
const results = await Promise.all(
|
||||
const urls = await Promise.all(
|
||||
servers.map(async (server) => {
|
||||
const url = new URL(sha256, server);
|
||||
const domain = url.hostname;
|
||||
|
||||
try {
|
||||
const check = await fetch(url, { method: "HEAD" });
|
||||
if (check.status === 200) {
|
||||
requestLog(`✓ ${domain} - HTTP ${check.status} (success)`);
|
||||
return url.toString();
|
||||
} else {
|
||||
requestLog(`✗ ${domain} - HTTP ${check.status} (failed)`);
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
requestLog(`✗ ${domain} - Network error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
||||
return null;
|
||||
}
|
||||
const check = await fetch(url, { method: "HEAD" }).catch(() => null);
|
||||
if (check?.status === 200) return url.toString();
|
||||
else return null;
|
||||
}),
|
||||
);
|
||||
|
||||
const filtered = results.filter((url) => url !== null);
|
||||
const filtered = urls.filter((url) => url !== null);
|
||||
|
||||
requestLog(`Found ${filtered.length}/${servers.length} Servers`);
|
||||
log(`Found ${filtered.length}/${servers.length} URLs for ${sha256}`);
|
||||
await blobURLs.set(sha256, filtered);
|
||||
return filtered;
|
||||
}
|
||||
@ -50,72 +35,38 @@ export async function streamBlob(
|
||||
servers: string[],
|
||||
headers?: Record<string, string>,
|
||||
): Promise<IncomingMessage | undefined> {
|
||||
const id = sha256.slice(0, 6);
|
||||
const streamLog = log.extend(id);
|
||||
|
||||
if (servers.length === 0) {
|
||||
streamLog(`No servers provided for blob ${sha256}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
streamLog(`Starting blob stream for ${sha256} from ${servers.length} servers`);
|
||||
if (servers.length === 0) return undefined;
|
||||
|
||||
// First find all available URLs
|
||||
const urls = await findBlobURLs(sha256, servers);
|
||||
if (urls.length === 0) {
|
||||
streamLog(`No available URLs found for blob ${sha256}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
streamLog(`Attempting to stream from ${urls.length} available URLs`);
|
||||
if (urls.length === 0) return undefined;
|
||||
|
||||
// Try each URL sequentially with timeout
|
||||
for (let i = 0; i < urls.length; i++) {
|
||||
const urlString = urls[i];
|
||||
const url = new URL(urlString);
|
||||
const domain = url.hostname;
|
||||
|
||||
streamLog(`Trying server ${i + 1}/${urls.length}: ${domain}`);
|
||||
|
||||
for (const urlString of urls) {
|
||||
const controller = new AbortController();
|
||||
let res: IncomingMessage | undefined = undefined;
|
||||
|
||||
try {
|
||||
// Set up timeout to abort after 10s
|
||||
const timeout = setTimeout(() => {
|
||||
streamLog(`Request to ${domain} timed out after 10s`);
|
||||
controller.abort();
|
||||
}, 10_000);
|
||||
|
||||
const url = new URL(urlString);
|
||||
const response = await makeRequestWithAbort(url, controller, headers);
|
||||
res = response;
|
||||
clearTimeout(timeout);
|
||||
|
||||
if (!response.statusCode) {
|
||||
throw new Error("Missing headers or status code");
|
||||
}
|
||||
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: ${size} bytes (max: ${MAX_FILE_SIZE})`);
|
||||
}
|
||||
if (size && parseInt(size) > MAX_FILE_SIZE) throw new Error("File too large");
|
||||
|
||||
// Accept both 200 (full content) and 206 (partial content) status codes
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||
streamLog(`✓ ${domain} - HTTP ${response.statusCode} - Successfully streaming blob ${sha256}`);
|
||||
return response;
|
||||
} else {
|
||||
throw new Error(`HTTP ${response.statusCode}`);
|
||||
}
|
||||
if (response.statusCode >= 200 && response.statusCode < 300) return response;
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
||||
streamLog(`✗ ${domain} - Failed: ${errorMessage}`);
|
||||
|
||||
if (res) res.resume();
|
||||
continue; // Try next URL if this one fails
|
||||
}
|
||||
}
|
||||
|
||||
streamLog(`All servers failed for blob ${sha256}`);
|
||||
return undefined;
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ try {
|
||||
|
||||
// start the server
|
||||
app.listen({ host: NSITE_HOST, port: NSITE_PORT }, () => {
|
||||
console.log("Started on port", HOST);
|
||||
logger("Started on port", HOST);
|
||||
});
|
||||
|
||||
// watch for invalidations
|
||||
@ -205,7 +205,7 @@ process.on("unhandledRejection", (reason, promise) => {
|
||||
});
|
||||
|
||||
async function shutdown() {
|
||||
console.log("Shutting down...");
|
||||
logger("Shutting down...");
|
||||
pool.destroy();
|
||||
process.exit(0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user