2022-02-23 19:50:47 +01:00
|
|
|
import express from "express";
|
2022-03-14 20:18:08 +01:00
|
|
|
import { UrlPoolStorage } from "./urlpool";
|
2022-02-23 23:26:12 +01:00
|
|
|
import { Readable } from 'stream';
|
|
|
|
|
2022-03-14 20:18:08 +01:00
|
|
|
|
|
|
|
let storage = new UrlPoolStorage;
|
2022-02-23 19:50:47 +01:00
|
|
|
|
|
|
|
export class Webserver {
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
|
|
const app = express();
|
|
|
|
|
2022-11-13 11:37:30 +01:00
|
|
|
app.use(express.static('public'));
|
|
|
|
|
2022-03-14 20:18:08 +01:00
|
|
|
app.get("/status/:id", async (req, res) => {
|
|
|
|
|
2022-04-23 01:37:41 +02:00
|
|
|
let p = await storage.get(req.params.id);
|
|
|
|
if(!p) {
|
|
|
|
res.status(404);
|
|
|
|
res.end();
|
|
|
|
return;
|
|
|
|
}
|
2022-03-14 20:18:08 +01:00
|
|
|
|
2022-04-23 14:49:12 +02:00
|
|
|
res.writeHead(200, {
|
|
|
|
"Content-Type": "application/json"
|
|
|
|
});
|
2022-03-14 20:18:08 +01:00
|
|
|
res.write(JSON.stringify({
|
2023-02-06 22:18:56 +01:00
|
|
|
file: {
|
|
|
|
name: p.file_name,
|
|
|
|
size: p.total_size
|
|
|
|
},
|
|
|
|
stream: {
|
2022-03-14 20:18:08 +01:00
|
|
|
total: p.urls.length,
|
|
|
|
available: p.available().length,
|
2022-04-23 14:49:12 +02:00
|
|
|
generating: p.generating,
|
2023-02-06 21:43:07 +01:00
|
|
|
downloaders: p.downloaders.length,
|
|
|
|
urls: p.urls
|
2022-03-14 20:18:08 +01:00
|
|
|
}
|
|
|
|
}));
|
|
|
|
res.end();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2022-11-13 11:37:30 +01:00
|
|
|
app.get("/u/:id", async (req, res) => {
|
2022-03-14 20:18:08 +01:00
|
|
|
|
2022-04-23 01:37:41 +02:00
|
|
|
let p = await storage.get(req.params.id);
|
|
|
|
if(!p) {
|
|
|
|
res.status(404);
|
|
|
|
res.end();
|
|
|
|
return;
|
|
|
|
}
|
2022-02-23 19:50:47 +01:00
|
|
|
|
|
|
|
let range: Range = {from: 0, to: null};
|
|
|
|
if(req.headers.range) range = this.parse_range(req.headers.range);
|
|
|
|
if(!range.from) range.from = 0;
|
|
|
|
|
2022-04-23 14:49:12 +02:00
|
|
|
let d = p.get_downloader(range.from);
|
2022-02-23 19:50:47 +01:00
|
|
|
|
2023-02-09 01:10:55 +01:00
|
|
|
let contentLength = p.total_size-range.from;
|
2022-02-23 23:26:12 +01:00
|
|
|
let headers = {
|
2023-02-09 01:10:55 +01:00
|
|
|
"Content-Range": `bytes ${range.from}-${p.total_size-1}/${p.total_size}`,
|
|
|
|
"Range": `bytes=${range.from}-${p.total_size-1}/${p.total_size}`,
|
2022-02-23 19:50:47 +01:00
|
|
|
"Accept-Ranges": "bytes",
|
|
|
|
"Content-Length": contentLength,
|
2022-02-23 20:50:10 +01:00
|
|
|
"Content-Type": "application/octet-stream",
|
2022-02-23 19:50:47 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
res.writeHead(206, headers);
|
2022-04-23 14:49:12 +02:00
|
|
|
res.on("close", () => {
|
|
|
|
d.destroy();
|
|
|
|
});
|
2022-02-23 19:50:47 +01:00
|
|
|
|
2022-04-23 14:49:12 +02:00
|
|
|
const readable = new Readable();
|
2022-02-23 23:26:12 +01:00
|
|
|
readable._read = async () => {
|
2022-04-23 14:49:12 +02:00
|
|
|
let stream = await d.more();
|
|
|
|
readable.push(stream);
|
2022-02-23 23:26:12 +01:00
|
|
|
}
|
2022-04-23 14:49:12 +02:00
|
|
|
let stream = await d.more();
|
2022-02-23 23:26:12 +01:00
|
|
|
readable.push(stream);
|
|
|
|
readable.pipe(res);
|
2022-02-23 19:50:47 +01:00
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
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};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-23 23:26:12 +01:00
|
|
|
from_to(range: [number, number], max: number) {
|
|
|
|
if(range[0] > max) range[0] = max;
|
|
|
|
if(range[1] > max) range[1] = max;
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2022-02-23 19:50:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
interface Range {
|
|
|
|
from: number | null;
|
|
|
|
to: number | null;
|
|
|
|
}
|