|
| 1 | +const fs = require("node:fs"); |
| 2 | +const http = require("node:http"); |
| 3 | +const path = require("node:path"); |
| 4 | + |
| 5 | +const mime = require("mime"); |
| 6 | + |
| 7 | +const logger = require("./logger"); |
| 8 | + |
| 9 | +const DEFAULT_INDEX_FILE = process.env.DEFAULT_INDEX_FILE || "index.html"; |
| 10 | +const FALLBACK_FILE = process.env.FALLBACK_FILE || null; |
| 11 | +const PORT = process.env.PORT || 8080; |
| 12 | +const ROOT_FILE_PATH = process.env.ROOT_FILE_PATH || "build"; |
| 13 | + |
| 14 | +function getFile(filePath) { |
| 15 | + try { |
| 16 | + const file = fs.readFileSync(filePath); |
| 17 | + return file; |
| 18 | + } catch { |
| 19 | + logger.error(`Could not find file "${filePath}"`); |
| 20 | + return; |
| 21 | + } |
| 22 | +} |
| 23 | + |
| 24 | +function getFileMime(filePath) { |
| 25 | + return mime.getType(filePath); |
| 26 | +} |
| 27 | + |
| 28 | +function getDomainFromRequest(req) { |
| 29 | + const headers = req.headers; |
| 30 | + const host = headers.host; |
| 31 | + const domain = host.split(":")[0]; |
| 32 | + return domain; |
| 33 | +} |
| 34 | + |
| 35 | +function getFilePathFromRequest(req) { |
| 36 | + return req.url.split("?")[0]; |
| 37 | +} |
| 38 | + |
| 39 | +function createFilePath(domain, filePath) { |
| 40 | + if (filePath === "/") { |
| 41 | + filePath = DEFAULT_INDEX_FILE; |
| 42 | + } |
| 43 | + return path.join(ROOT_FILE_PATH, domain, filePath); |
| 44 | +} |
| 45 | + |
| 46 | +function handleRequest(req, res) { |
| 47 | + const domain = getDomainFromRequest(req); |
| 48 | + const filePath = getFilePathFromRequest(req); |
| 49 | + logger.debug(`Requesting ${domain}${filePath}`); |
| 50 | + |
| 51 | + const actualFilePath = createFilePath(domain, filePath); |
| 52 | + let file = getFile(actualFilePath); |
| 53 | + |
| 54 | + if (!file && FALLBACK_FILE) { |
| 55 | + const fallbackFilePath = createFilePath(domain, FALLBACK_FILE); |
| 56 | + logger.debug(`Serving fallback file: ${fallbackFilePath}`); |
| 57 | + file = getFile(fallbackFilePath); |
| 58 | + } |
| 59 | + |
| 60 | + if (!file) { |
| 61 | + res.writeHead(404); |
| 62 | + res.end(); |
| 63 | + logger.accessLog(req, res); |
| 64 | + return; |
| 65 | + } |
| 66 | + |
| 67 | + const mimeType = getFileMime(actualFilePath); |
| 68 | + |
| 69 | + res.setHeader("Content-Type", mimeType); |
| 70 | + res.writeHead(200); |
| 71 | + res.end(file); |
| 72 | + logger.accessLog(req, res); |
| 73 | +} |
| 74 | + |
| 75 | +exports.createServer = function (port = PORT) { |
| 76 | + const server = http.createServer(handleRequest); |
| 77 | + server.listen(port); |
| 78 | + |
| 79 | + logger.info(`Listening on port ${port}`); |
| 80 | + return server; |
| 81 | +}; |
0 commit comments