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; };