133 lines
5.3 KiB
JavaScript
133 lines
5.3 KiB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
import http from "node:http";
|
|
import { URL } from "node:url";
|
|
import querystring from "node:querystring";
|
|
import Router from "./router.js";
|
|
import Tpl from "./template.js";
|
|
export { Router, Tpl };
|
|
export default class Flummpress {
|
|
constructor() {
|
|
this.router = new Router();
|
|
this.tpl = new Tpl();
|
|
this.middleware = [];
|
|
}
|
|
use(plugin) {
|
|
if (plugin instanceof Router)
|
|
this.router.use(plugin);
|
|
else if (plugin instanceof Tpl)
|
|
this.tpl = plugin;
|
|
else if (typeof plugin === "function")
|
|
this.middleware.push(plugin);
|
|
return this;
|
|
}
|
|
processPipeline(handlers, req, res) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
for (const handler of handlers) {
|
|
if (typeof handler !== "function")
|
|
throw new TypeError(`Handler is not a function: ${handler}`);
|
|
let nextCalled = false;
|
|
yield handler(req, res, () => nextCalled = true);
|
|
if (!nextCalled || res.writableEnded)
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
listen(...args) {
|
|
this.server = http.createServer((request, response) => __awaiter(this, void 0, void 0, function* () {
|
|
var _a, _b;
|
|
const req = this.parseRequest(request);
|
|
const res = this.createResponse(response);
|
|
const start = process.hrtime();
|
|
try {
|
|
yield this.processPipeline(this.middleware, req, res);
|
|
const route = this.router.getRoute(req.url.pathname, req.method);
|
|
if (route) {
|
|
const handler = route.methods[(_a = req.method) === null || _a === void 0 ? void 0 : _a.toLowerCase()];
|
|
req.params = ((_b = req.url.pathname.match(new RegExp(route.path))) === null || _b === void 0 ? void 0 : _b.groups) || {};
|
|
req.post = yield this.readBody(req);
|
|
yield this.processPipeline(handler, req, res);
|
|
}
|
|
else {
|
|
res.writeHead(404).end("404 - Not Found");
|
|
}
|
|
}
|
|
catch (err) {
|
|
console.error(err);
|
|
res.writeHead(500).end("500 - Internal Server Error");
|
|
}
|
|
console.log([
|
|
`[${new Date().toISOString()}]`,
|
|
`${(process.hrtime(start)[1] / 1e6).toFixed(2)}ms`,
|
|
`${req.method} ${res.statusCode}`,
|
|
req.url.pathname,
|
|
].join(" | "));
|
|
})).listen(...args);
|
|
return this;
|
|
}
|
|
parseRequest(request) {
|
|
const url = new URL(request.url.replace(/(?!^.)(\/+)?$/, ""), "http://localhost");
|
|
const req = request;
|
|
req.url = {
|
|
pathname: url.pathname,
|
|
split: url.pathname.split("/").slice(1),
|
|
searchParams: url.searchParams,
|
|
qs: Object.fromEntries(url.searchParams.entries()),
|
|
};
|
|
req.cookies = {};
|
|
if (req.headers.cookie) {
|
|
req.headers.cookie.split("; ").forEach(cookie => {
|
|
const [key, value] = cookie.split("=");
|
|
req.cookies[key] = decodeURIComponent(value);
|
|
});
|
|
}
|
|
return req;
|
|
}
|
|
readBody(req) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
return new Promise((resolve, reject) => {
|
|
let body = "";
|
|
req.on("data", (chunk) => {
|
|
body += chunk;
|
|
});
|
|
req.on("end", () => {
|
|
try {
|
|
resolve(req.headers["content-type"] === "application/json"
|
|
? JSON.parse(body)
|
|
: querystring.parse(body));
|
|
}
|
|
catch (err) {
|
|
reject(err);
|
|
}
|
|
});
|
|
req.on("error", reject);
|
|
});
|
|
});
|
|
}
|
|
createResponse(response) {
|
|
const res = response;
|
|
res.reply = ({ code = 200, type = "text/html", body }) => {
|
|
res.writeHead(code, { "Content-Type": `${type}; charset=utf-8` });
|
|
res.end(body);
|
|
};
|
|
res.json = (body, code = 200) => {
|
|
res.reply({ code, type: "application/json", body: JSON.stringify(body) });
|
|
};
|
|
res.html = (body, code = 200) => {
|
|
res.reply({ code, type: "text/html", body });
|
|
};
|
|
res.redirect = (target, code = 302) => {
|
|
res.writeHead(code, { Location: encodeURI(target) });
|
|
res.end();
|
|
};
|
|
return res;
|
|
}
|
|
}
|