const logger = require('../utils/log.cjs') const routes = require('./routes.cjs') const httpProxy = require('http-proxy') const proxy = httpProxy.createProxyServer({}) const fs = require('fs') const dist = 'dist' let mime import('mime').then((res) => { mime = res.default }) let proxys = require('../../../src/proxy.cjs') const { Exception } = require("sass"); const httpOk = 200 const httpBadRequest = 400 const matchProxy = (request, response) => { const match = request.url.split('/')[1] const proxyInfo = proxys['/' + match] if (proxyInfo) { const host = request.headers.host; delete request.headers.host if (typeof proxyInfo.rewrite === 'function') { request.url = proxyInfo.rewrite(request.url) } proxy.web(request, response, { target: proxyInfo.target || ("http://" + host), changeOrigin: proxyInfo.changeOrigin }) logger.info(`${request.method} ${httpOk} ${request.url}`) return true } else { return null } } const matchRouter = async (request, response) => { let [url] = request.url.split('?') let route = routes let url_sp = url.split('/') for (let p of url_sp) { if (!p) { continue } if (route[p]) { route = route[p] } else { return false } } if (typeof route === 'function') { await route(request, response) // response.writeHead(httpOk, { 'Content-Type': 'application/json' }) // response.end(JSON.stringify(res)) logger.info(`${request.method} ${httpOk} ${request.url}`) return true } else { return false } } function getMimeType(filePath) { const ext = filePath.split('.').pop()?.toLowerCase() const defaultMimes = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp', svg: 'image/svg+xml', ico: 'image/x-icon', js: 'text/javascript', css: 'text/css', html: 'text/html', json: 'application/json', woff: 'font/woff', woff2: 'font/woff2', ttf: 'font/ttf', otf: 'font/otf', dat: 'application/octet-stream', wasm: 'application/wasm' } if (ext && defaultMimes[ext]) { return defaultMimes[ext] } if (mime && typeof mime.getType === 'function') { return mime.getType(filePath) || 'application/octet-stream' } return 'application/octet-stream' } const matchFile = async (request, response) => { return new Promise((resolve) => { const cleanPath = decodeURIComponent(request.url.split('?')[0]) let targetPath = dist + cleanPath if (!fs.existsSync(targetPath)) { const mappedPath = dist + cleanPath.replace(/^\/(src\/public|public|src)/, '') if (fs.existsSync(mappedPath)) { targetPath = mappedPath } else if (cleanPath.startsWith('/assets/')) { response.writeHead(404, { 'Content-Type': 'text/plain' }) response.end('Asset Not Found') resolve(true) return } } fs.readFile(targetPath, (err, file) => { if (!err) { const mimetype = getMimeType(cleanPath) const responseHeaders = { 'Content-Type': mimetype, 'Access-Control-Allow-Origin': '*' } if (cleanPath.endsWith(".js") || cleanPath.endsWith(".css") || cleanPath.endsWith("-sw.js") || cleanPath.includes("dat-module-map.json")) { responseHeaders["Service-Worker-Allowed"] = '/' responseHeaders["Cache-Control"] = 'no-cache, no-store, must-revalidate' responseHeaders["Pragma"] = 'no-cache' responseHeaders["Expires"] = '0' } response.writeHead(httpOk, responseHeaders) response.end(file) // logger.info(`${request.method} ${httpOk} ${request.url}`) resolve(true) } else { resolve(false) } }) }) } const endIndex = async (request, response) => { console.log(dist + '/index.html') fs.readFile(dist + '/index.html', (err, html) => { if (!err) { response.writeHead(httpOk, { 'Content-type': 'text/html;charset=utf-8', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Access-Control-Allow-Origin': '*' }) response.end(html) logger.info(`${request.method} ${httpOk} ${request.url}`) } }) } const matchType = async (request, response) => { const isRouter = await matchRouter(request, response) if (isRouter) { return } let isFile = await matchFile(request, response) if (isFile) { return } let isProxy = matchProxy(request, response) if (isProxy) { return } await endIndex(request, response) } const httpService = async (request, response) => { try { await matchType(request, response) } catch (e) { response.writeHead(httpBadRequest, { 'Content-Type': 'application/json' }) response.end( JSON.stringify({ code: -1, message: String(e) }) ) logger.info(`${request.method} ${httpBadRequest} ${request.url}`) } } module.exports = { httpService, matchType, matchRouter, matchFile, endIndex, matchProxy, }