f0bm/src/inc/router.mjs
2020-04-03 13:12:35 +02:00

86 lines
2.7 KiB
JavaScript

import fs from "fs";
import path from "path";
export default new class Router {
#mimes;
constructor() {
this.routes = new Map();
};
route(method, args) {
this.routes.set(args[0], { method: method, f: args[1] });
console.info("route set", method, args[0]);
};
get() {
this.route("GET", arguments);
};
post() {
this.route("POST", arguments);
};
async static({ dir = path.resolve() + "/public", route = /^\/public/ }) {
if(!this.#mimes) {
this.#mimes = new Map();
(await fs.promises.readFile("/etc/mime.types", "utf-8"))
.split("\n")
.filter(e => !e.startsWith("#") && e)
.map(e => e.split(/\s{2,}/))
.filter(e => e.length > 1)
.forEach(m => m[1].split(" ").forEach(ext => this.#mimes.set(ext, m[0])));
}
this.get(route, async (req, res) => {
try {
const mime = this.#mimes.get(req.url.path.split(".").pop());
const file = path.join(dir, req.url.path.replace(route, ""));
let stat;
try {
stat = await fs.promises.stat(file);
} catch {
return res.reply({
code: 404,
body: "404 - file not found."
});
}
if(!mime.startsWith("video") && !mime.startsWith("audio")) {
return res.reply({
type: this.#mimes.get(req.url.path.split(".").pop()).toLowerCase(),
body: await fs.promises.readFile(path.join(dir, req.url.path.replace(route, "")))
});
}
if(req.headers.range) {
const parts = req.headers.range.replace(/bytes=/, "").split("-");
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : stat.size - 1;
res.writeHead(206, {
"Content-Range": `bytes ${start}-${end}/${stat.size}`,
"Accept-Ranges": "bytes",
"Content-Length": (end - start) + 1,
"Content-Type": mime,
});
const stream = fs.createReadStream(file, { start: start, end: end })
.on("open", () => stream.pipe(res))
.on("error", err => res.end(err));
}
else {
res.writeHead(200, {
"Content-Length": stat.size,
"Content-Type": mime,
});
fs.createReadStream(file).pipe(res);
}
} catch(err) {
console.error(err);
return res.reply({
code: 500,
body: "500 - f0ck hat keinen b0ck"
});
}
});
};
};
Map.prototype.getRoute = function(path, method, tmp) {
return (!(tmp = [...this.entries()].filter(r => ( r[0] === path || r[0].exec?.(path) ) && r[1].method.includes(method) )[0])) ? false : tmp[1].f;
};