Files
mangabaka-seeder/src/server/bun.ts
T

40 lines
1.5 KiB
TypeScript

// Self-hosted entry: Bun.serve behind our reverse proxy (spec §4.10). Keep it thin.
import { join, resolve } from "node:path";
import { createApp } from "./app";
import { SERVER_IDLE_TIMEOUT_S, clientIp, readConfig } from "./config";
import { DirStorage } from "./storage-dir";
const config = readConfig(process.env);
const storage = config.storageDir ? await DirStorage.open(config.storageDir, config.storageMaxBytes) : null;
if (storage) {
const sweep = () =>
storage
.sweep()
.then((n) => n > 0 && console.log(`swept ${n} expired cover(s)`))
.catch((err) => console.error("sweep failed:", err));
await sweep();
setInterval(sweep, 24 * 60 * 60 * 1000);
}
const assetsRoot = resolve(config.assetsDir);
let server: ReturnType<typeof Bun.serve>;
const app = createApp({
storage,
publicUrl: config.publicUrl,
// `relativePath` is already checked by resolveAssetPath (no dot-segments, no dotfiles).
assets: async (relativePath) => {
const file = Bun.file(join(assetsRoot, relativePath));
return (await file.exists()) ? new Response(file) : null;
},
clientIp: (req) => clientIp(req, config.trustProxy, server.requestIP(req)?.address),
});
server = Bun.serve({ port: config.port, hostname: config.hostname, idleTimeout: SERVER_IDLE_TIMEOUT_S, fetch: app });
console.log(
`mangabaka-seeder on http://${server.hostname}:${server.port} · storage: ${
storage ? `${config.storageDir} (${storage.usedBytes()} of ${config.storageMaxBytes} bytes)` : "off"
}`,
);