diff options
Diffstat (limited to 'src/app.ts')
-rw-r--r-- | src/app.ts | 261 |
1 files changed, 0 insertions, 261 deletions
diff --git a/src/app.ts b/src/app.ts deleted file mode 100644 index ac11c4d..0000000 --- a/src/app.ts +++ /dev/null @@ -1,261 +0,0 @@ -import path from "node:path"; -import fs, { Stats } from "node:fs"; -import type { BunFile, Serve } from "bun"; -import * as Sentry from "@sentry/node"; -import prom from "bun-prometheus-client"; -import log from "loglevel"; - -import config from "./config"; - -log.setLevel((Bun.env.LOG_LEVEL || "info") as log.LogLevelDesc); - -Sentry.init({ - release: `homestead@${Bun.env.FLY_MACHINE_VERSION}`, - tracesSampleRate: 1.0, -}); - -const expectedHostURL = new URL( - Bun.env.NODE_ENV === "production" ? config.base_url : "http://localhost:3000", -); -const defaultHeaders = { - ...config.extra.headers, - vary: "Accept-Encoding", -}; - -type File = { - filename: string; - handle: BunFile; - relPath: string; - headers?: Record<string, string>; - type: string; - size: number; - mtime: Date; -}; - -const metrics = { - requests: new prom.Counter({ - name: "homestead_requests", - help: "Number of requests by path, status code, and method", - labelNames: ["path", "status_code", "method", "content_encoding"], - }), - requestDuration: new prom.Histogram({ - name: "homestead_request_duration_seconds", - help: "Request duration in seconds", - labelNames: ["path"], - }), -}; - -let files = new Map<string, File>(); - -function registerFile( - path: string, - pathname: string, - filename: string, - stat: Stats, -): void { - pathname = "/" + (pathname === "." || pathname === "./" ? "" : pathname); - - if (files.get(pathname) !== undefined) { - console.warn("File already registered:", pathname); - } - const handle = Bun.file(filename); - files.set(pathname, { - filename, - relPath: "/" + path, - handle: handle, - type: pathname.startsWith("/feed-styles.xsl") ? "text/xsl" : handle.type, - headers: - pathname === "/404.html" - ? Object.assign({}, defaultHeaders, { "cache-control": "no-cache" }) - : undefined, - size: stat.size, - mtime: stat.mtime, - }); -} - -function walkDirectory(root: string, dir: string) { - const absDir = path.join(root, dir); - for (let pathname of fs.readdirSync(absDir)) { - const relPath = path.join(dir, pathname); - const absPath = path.join(absDir, pathname); - const stat = fs.statSync(absPath); - if (stat.isDirectory()) { - walkDirectory(root, relPath + path.sep); - } else if (stat.isFile()) { - if (pathname.startsWith("index.html")) { - const dir = relPath.replace("index.html", ""); - registerFile(relPath, dir, absPath, stat); - if (dir !== "") { - registerFile(relPath, dir + path.sep, absPath, stat); - } - } else { - registerFile(relPath, relPath, absPath, stat); - } - } - } -} - -walkDirectory("public/", ""); - -async function serveFile( - file: File, - statusCode: number = 200, - extraHeaders: Record<string, string> = {}, -): Promise<Response> { - return new Response(await file.handle.arrayBuffer(), { - headers: { - "last-modified": file.mtime.toUTCString(), - ...extraHeaders, - ...(file.headers || defaultHeaders), - }, - status: statusCode, - }); -} - -function parseIfModifiedSinceHeader(header: string | null): number { - return header ? new Date(header).getTime() + 999 : 0; -} - -export const metricsServer = { - port: 9091, - fetch: async function (request) { - const pathname = new URL(request.url).pathname; - switch (pathname) { - case "/metrics": - return new Response(await prom.register.metrics()); - default: - return new Response("", { status: 404 }); - } - }, -} satisfies Serve; - -export const server = { - fetch: async function (request) { - const url = new URL(request.url); - const pathname = url.pathname.replace(/\/\/+/g, "/"); - const endTimer = metrics.requestDuration.startTimer({ path: pathname }); - let status; - const transaction = Sentry.startTransaction({ - name: pathname, - op: "http.server", - description: `${request.method} ${pathname}`, - tags: { - url: request.url, - "http.host": request.headers.get("host"), - "http.method": request.method, - "http.user_agent": request.headers.get("user-agent"), - }, - }); - try { - if (pathname === "/health") { - return new Response("OK", { status: (status = 200) }); - } else if ( - config.redirect_other_hostnames && - request.headers.get("host") !== expectedHostURL.host - ) { - return new Response("", { - status: (status = 301), - headers: { - location: new URL(pathname, expectedHostURL).toString(), - }, - }); - } - const file = files.get(pathname); - let contentEncoding = "identity"; - let suffix = ""; - if (file && (await file.handle.exists())) { - if ( - parseIfModifiedSinceHeader( - request.headers.get("if-modified-since"), - ) >= file?.mtime.getTime() - ) { - metrics.requests.inc({ - method: request.method, - path: pathname, - status_code: (status = 304), - }); - transaction.setHttpStatus(304); - return new Response("", { status: status, headers: defaultHeaders }); - } - const encodings = (request.headers.get("accept-encoding") || "") - .split(",") - .map((x) => x.trim().toLowerCase()); - if (encodings.includes("br") && files.has(pathname + ".br")) { - contentEncoding = "br"; - suffix = ".br"; - } else if (encodings.includes("zstd") && files.has(pathname + ".zst")) { - contentEncoding = "zstd"; - suffix = ".zst"; - } else if (encodings.includes("gzip") && files.has(pathname + ".gz")) { - contentEncoding = "gzip"; - suffix = ".gz"; - } - - status = 200; - transaction.setHttpStatus(status); - metrics.requests.inc({ - method: request.method, - path: pathname, - status_code: status, - content_encoding: contentEncoding, - }); - const endFile = files.get(pathname + suffix); - if (!endFile) { - throw new Error(`File ${pathname} not found`); - } - return serveFile(endFile, status, { - "content-encoding": contentEncoding, - "content-type": file.type, - }); - } else { - if (files.has(pathname + "/")) { - log.info(`Redirecting to: ${pathname + "/"}`); - metrics.requests.inc({ - method: request.method, - path: pathname, - status_code: (status = 302), - }); - return new Response("", { - status: status, - headers: { location: pathname + "/" }, - }); - } - metrics.requests.inc({ - method: request.method, - path: pathname, - status_code: (status = 404), - content_encoding: "identity", - }); - transaction.setHttpStatus(status); - const notfound = files.get("/404.html"); - if (notfound) { - return serveFile(notfound, status, { - "content-type": "text/html; charset=utf-8", - }); - } else { - log.warn("404.html not found"); - return new Response("404 Not Found", { - status: status, - headers: { "content-type": "text/plain", ...defaultHeaders }, - }); - } - } - } catch (error) { - transaction.setHttpStatus((status = 503)); - metrics.requests.inc({ - method: request.method, - path: pathname, - status_code: status, - content_encoding: "identity", - }); - Sentry.captureException(error); - console.error("Error", error); - return new Response("Something went wrong", { status: status }); - } finally { - const seconds = endTimer(); - metrics.requestDuration.observe(seconds); - transaction.finish(); - console.log(request.method, status, pathname); - } - }, -} satisfies Serve; |