This repository has been archived on 2023-11-29. You can view files and clone it, but cannot push or open issues or pull requests.
Uloz.to-rychle/webserver.ts

108 lines
2.5 KiB
TypeScript

import express from "express";
import { Downloader } from "./downloader";
import { UrlPoolStorage } from "./urlpool";
import { Readable } from 'stream';
let storage = new UrlPoolStorage;
export class Webserver {
chunk_size = 5*1024*1024;
partial_size = this.chunk_size*10;
constructor() {
const app = express();
app.get("/status/:id", async (req, res) => {
let p = storage.get(req.params.id);
res.write(JSON.stringify({
streams: {
total: p.urls.length,
available: p.available().length,
generating: p.generating
}
}));
res.end();
});
app.get("/stream/:id", async (req, res) => {
let p = storage.get(req.params.id);
let d = p.get_downloader();
let range: Range = {from: 0, to: null};
if(req.headers.range) range = this.parse_range(req.headers.range);
if(!range.from) range.from = 0;
if(!d.ready) await d.init();
let [from, to] = this.from_to([range.from, range.from+this.chunk_size], d.total_size);
let contentLength = d.total_size-from;
let headers = {
"Content-Range": `bytes ${from}-${d.total_size}/${d.total_size+1}`,
"Range": `bytes=${from}-${d.total_size}/${d.total_size+1}`,
"Accept-Ranges": "bytes",
"Content-Length": contentLength,
"Content-Type": "application/octet-stream",
};
res.writeHead(206, headers);
const readable = new Readable()
readable._read = async () => {
[from, to] = this.from_to([to+1, to+1+this.chunk_size], d.total_size);
if(from == d.total_size) {
readable.push(null);
//res.end();
}
else {
let stream = await this.download_chunk(d, from, to);
readable.push(stream);
}
}
let stream = await this.download_chunk(d, from, to);
readable.push(stream);
readable.pipe(res);
});
app.listen(8000, function () {
console.log("Listening on port 8000!");
});
}
async download_chunk(d: Downloader, from: number, to: number) {
console.log("downloading...", from, to);
let stream = await d.download_range(from, to);
console.log("downloaded ", from, to);
return stream;
}
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;
}