// `archilyzer seed` and `archilyzer tracker` (release 21 D4b). The work and // its rules are controller/seeder.ts; the settings are `settings.seeder` // (SETTINGS.md). Both run until interrupted. // // RUN THEM BEHIND THE VPN. The docker profile `seeder` // (docker-compose.seeder.yml) is the supported way: its namespace has no route // but the tunnel. Run on a bare host, the seeder uploads from the home address. import { getPaths } from "../lib/paths"; import { getSettings } from "../lib/settings"; import { seederConfigured } from "../lib/seederSettings"; import { listSeedTargets, runSeeder, startTracker } from "../controller/seeder"; export async function seedMain(opts: { signal: AbortSignal }): Promise { const settings = getSettings().seeder; if (!seederConfigured(settings)) { console.error("seed: the seeder is not configured — name the sites it seeds in settings.seeder.sites (SETTINGS.md)"); return 2; } try { await runSeeder({ paths: getPaths(), settings, onLog: (line) => console.log(line.replace(/\n$/, "")), signal: opts.signal, }); return 0; } catch (err) { console.error(`seed: ${(err as Error).message}`); return 1; } } // How long the tracker trusts its list of infohashes before re-reading the // manifests (an announce arrives every few minutes per peer; a manifest read // per announce would be a disk walk per announce). const ALLOWED_TTL_MS = 60_000; export async function trackerMain(opts: { host: string; port: number; signal: AbortSignal }): Promise { const settings = getSettings().seeder; if (!seederConfigured(settings)) { console.error("tracker: it tracks the seeder's torrents, and the seeder is not configured — settings.seeder.sites is empty"); return 2; } const paths = getPaths(); let cache: { at: number; set: Set } | null = null; const allowed = async () => { if (!cache || Date.now() - cache.at > ALLOWED_TTL_MS) { const targets = await listSeedTargets(paths, settings, (l) => console.log(l)); cache = { at: Date.now(), set: new Set(targets.map((t) => t.infoHash)) }; } return cache.set; }; try { const n = (await allowed()).size; const tracker = await startTracker({ host: opts.host, port: opts.port, allowed, onLog: (l) => console.log(l) }); console.log(`tracker: ${n} torrent(s) tracked; nothing else is`); await new Promise((resolve) => opts.signal.addEventListener("abort", () => resolve(), { once: true })); await tracker.close(); return 0; } catch (err) { console.error(`tracker: ${(err as Error).message}`); return 1; } }