Seed relay: nodes get their headers through the seed API
Test and deploy / test (push) Successful in 1m28s
Test and deploy / deploy (push) Successful in 2m5s

The seed API keeps a pool of NNTP connections (SEED_NNTP_CONNECTIONS) and
serves GET /api/v1/seed/ranges/:id/chunk?from=&to= for leased ranges:
the gzip stream the news server sent, passed on unopened. seed:node fetches
that way by default (SEED_FETCH=relay), so a node needs only a token and
SEED_CONNECTIONS; SEED_FETCH=direct keeps its own NNTP connections. All
fetching then comes from the indexer's IP (the account allows two).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-05 15:24:39 +02:00
1 parent 3d5cfb2527
commit 41859636d3
13 files changed
+289 -33

No files matched your search

+22
View File
@@ -1,5 +1,6 @@
import type { HttpContext } from '@adonisjs/core/http'
import SeedOrchestrator, { LeaseLost } from '#services/SeedOrchestrator'
import SeedFetchPool from '#services/SeedFetchPool'
import type { SeedBatch } from '#lib/seed/wire'
/**
@@ -31,6 +32,27 @@ export default class SeedController {
})
}
/**
* GET /api/v1/seed/ranges/:id/chunk?from=&to= → the overviews of those
* articles as a zlib/gzip stream (relay nodes fetch through the indexer).
*/
async chunk({ seedNode, params, request, response }: HttpContext) {
if (SeedFetchPool.size === 0) return response.serviceUnavailable({ error: 'Relay is off (SEED_NNTP_CONNECTIONS=0); fetch directly' })
const from = Number(request.input('from'))
const to = Number(request.input('to'))
if (!Number.isSafeInteger(from) || !Number.isSafeInteger(to)) return response.badRequest({ error: 'Expected ?from=&to=' })
return this.leased(response, async () => {
try {
const raw = await SeedOrchestrator.chunk(seedNode.id, Number(params.id), from, to)
response.header('content-type', 'application/octet-stream')
return response.send(raw)
} catch (error) {
if (error instanceof RangeError) return response.badRequest({ error: error.message })
throw error
}
})
}
/** POST /api/v1/seed/ranges/:id/done */
async done({ seedNode, params, response }: HttpContext) {
return this.leased(response, async () => {