feat: add HTTP server adapter and request-mapping tests
This commit is contained in:
79
src/server.js
Normal file
79
src/server.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const http = require("node:http");
|
||||||
|
const { buildApp } = require("./app");
|
||||||
|
const { config } = require("./config");
|
||||||
|
|
||||||
|
function readBody(req) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let data = "";
|
||||||
|
req.setEncoding("utf8");
|
||||||
|
req.on("data", (chunk) => {
|
||||||
|
data += chunk;
|
||||||
|
if (data.length > 2_000_000) {
|
||||||
|
reject(new Error("payload_too_large"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
req.on("end", () => resolve(data));
|
||||||
|
req.on("error", reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeHeaders(rawHeaders) {
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(rawHeaders || {}).map(([k, v]) => [
|
||||||
|
String(k).toLowerCase(),
|
||||||
|
Array.isArray(v) ? v.join(",") : (v || ""),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapToAppRequest({ req, rawBody }) {
|
||||||
|
const url = new URL(req.url, "http://localhost");
|
||||||
|
return {
|
||||||
|
method: req.method || "GET",
|
||||||
|
path: url.pathname,
|
||||||
|
headers: normalizeHeaders(req.headers),
|
||||||
|
rawBody,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createHttpServer({ app }) {
|
||||||
|
return http.createServer(async (req, res) => {
|
||||||
|
try {
|
||||||
|
const rawBody = await readBody(req);
|
||||||
|
const response = app.handleRequest(mapToAppRequest({ req, rawBody }));
|
||||||
|
|
||||||
|
res.statusCode = response.status;
|
||||||
|
for (const [key, value] of Object.entries(response.headers || {})) {
|
||||||
|
res.setHeader(key, value);
|
||||||
|
}
|
||||||
|
res.end(response.body || "");
|
||||||
|
} catch (error) {
|
||||||
|
res.statusCode = 500;
|
||||||
|
res.setHeader("content-type", "application/json; charset=utf-8");
|
||||||
|
res.end(JSON.stringify({ error: error.message || "internal_error" }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
const app = buildApp({ config });
|
||||||
|
const server = createHttpServer({ app });
|
||||||
|
|
||||||
|
server.listen(config.port, () => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`xartaudio server listening on :${config.port}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mapToAppRequest,
|
||||||
|
normalizeHeaders,
|
||||||
|
createHttpServer,
|
||||||
|
start,
|
||||||
|
};
|
||||||
31
test/server.test.js
Normal file
31
test/server.test.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const test = require("node:test");
|
||||||
|
const assert = require("node:assert/strict");
|
||||||
|
const { mapToAppRequest, normalizeHeaders } = require("../src/server");
|
||||||
|
|
||||||
|
test("normalizeHeaders lowercases and joins array values", () => {
|
||||||
|
const headers = normalizeHeaders({
|
||||||
|
"X-User-Id": "u1",
|
||||||
|
"X-Forwarded-For": ["a", "b"],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(headers["x-user-id"], "u1");
|
||||||
|
assert.equal(headers["x-forwarded-for"], "a,b");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("mapToAppRequest extracts method/path/headers/body correctly", () => {
|
||||||
|
const request = mapToAppRequest({
|
||||||
|
req: {
|
||||||
|
method: "POST",
|
||||||
|
url: "/api/webhooks/x?debug=1",
|
||||||
|
headers: { "X-Signature": "sha256=abc" },
|
||||||
|
},
|
||||||
|
rawBody: "{\"ok\":true}",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(request.method, "POST");
|
||||||
|
assert.equal(request.path, "/api/webhooks/x");
|
||||||
|
assert.equal(request.headers["x-signature"], "sha256=abc");
|
||||||
|
assert.equal(request.rawBody, "{\"ok\":true}");
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user