import express from "express"; import { UrlPoolStorage } from "./urlpool"; import { Readable } from 'stream'; let storage = new UrlPoolStorage; export class Webserver { constructor() { const app = express(); app.use(express.static('public')); app.get("/status/:id", async (req, res) => { let p = await storage.get(req.params.id); if(!p) { res.status(404); res.end(); return; } res.writeHead(200, { "Content-Type": "application/json" }); res.write(JSON.stringify({ file: { name: p.file_name, size: p.total_size }, stream: { total: p.urls.length, available: p.available().length, generating: p.generating, downloaders: p.downloaders.length, urls: p.urls } })); res.end(); }); app.get("/u/:id", async (req, res) => { let p = await storage.get(req.params.id); if(!p) { res.status(404); res.end(); return; } let range: Range = {from: 0, to: null}; if(req.headers.range) range = this.parse_range(req.headers.range); if(!range.from) range.from = 0; let d = p.get_downloader(range.from); let contentLength = p.total_size-range.from; let headers = { "Content-Range": `bytes ${range.from}-${p.total_size-1}/${p.total_size}`, "Range": `bytes=${range.from}-${p.total_size-1}/${p.total_size}`, "Accept-Ranges": "bytes", "Content-Length": contentLength, "Content-Type": "application/octet-stream", }; res.writeHead(206, headers); res.on("close", () => { d.destroy(); }); const readable = new Readable(); readable._read = async () => { let stream = await d.more(); readable.push(stream); } let stream = await d.more(); readable.push(stream); readable.pipe(res); }); app.listen(8000, function () { console.log("Listening on port 8000!"); }); } parse_range(input: string): Range { let [from, to]: (number|null)[] = [null, null]; let parts = input.split("="); if(parts[1]) [from, to] = parts[1].split("-").map(i => i ? parseInt(i) : null); return {from, to}; } from_to(range: [number, number], max: number) { if(range[0] > max) range[0] = max; if(range[1] > max) range[1] = max; return range; } } interface Range { from: number | null; to: number | null; }