torrent/src/api/routes/torrents.ts

63 lines
1.6 KiB
TypeScript

import { Hono } from "hono";
import { res } from "../response.js";
import type { SeederRegistry } from "../SeederRegistry.js";
export function torrentsRouter(registry: SeederRegistry) {
const app = new Hono();
/** List all active torrents with their current stats */
app.get("/", (c) => {
return c.json(registry.listTorrents());
});
/** Add a torrent — accepts multipart/form-data with a 'torrent' file field */
app.post("/", async (c) => {
const body = await c.req.parseBody();
const file = body.torrent;
if (!file || typeof file === "string") {
return res.badRequest(c, "Missing 'torrent' file field");
}
const buf = Buffer.from(await (file as File).arrayBuffer());
try {
const state = await registry.addTorrent(buf);
return res.created(c, state);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
return res.unprocessable(c, msg);
}
});
/** Get stats + announce history for a specific torrent */
app.get("/:hash", (c) => {
const { hash } = c.req.param();
const list = registry.listTorrents();
const torrent = list.find((t) => t.infoHashHex === hash);
if (!torrent) {
return res.notFound(c);
}
return c.json({
...torrent,
history: registry.getHistory(hash),
});
});
/** Remove a torrent — sends 'stopped' to trackers then removes it */
app.delete("/:hash", async (c) => {
const { hash } = c.req.param();
const removed = await registry.removeTorrent(hash);
if (!removed) {
return res.notFound(c);
}
return c.json({ ok: true });
});
return app;
}