init
This commit is contained in:
+98
@@ -0,0 +1,98 @@
|
||||
const fs = require('node:fs')
|
||||
const http = require('node:http')
|
||||
const path = require('node:path')
|
||||
|
||||
const PORT = Number(process.env.PORT || 3001)
|
||||
const API_UPSTREAM = process.env.API_UPSTREAM || 'http://127.0.0.1:6000'
|
||||
const DIST_DIR = path.join(__dirname, 'dist')
|
||||
|
||||
const mimeTypes = {
|
||||
'.css': 'text/css; charset=utf-8',
|
||||
'.html': 'text/html; charset=utf-8',
|
||||
'.ico': 'image/x-icon',
|
||||
'.js': 'text/javascript; charset=utf-8',
|
||||
'.json': 'application/json; charset=utf-8',
|
||||
'.map': 'application/json; charset=utf-8',
|
||||
'.png': 'image/png',
|
||||
'.svg': 'image/svg+xml',
|
||||
'.webp': 'image/webp',
|
||||
}
|
||||
|
||||
function send(res, status, body, headers = {}) {
|
||||
res.writeHead(status, headers)
|
||||
res.end(body)
|
||||
}
|
||||
|
||||
function proxyRequest(req, res) {
|
||||
const target = new URL(req.url, API_UPSTREAM)
|
||||
const proxy = http.request(
|
||||
target,
|
||||
{
|
||||
method: req.method,
|
||||
headers: {
|
||||
...req.headers,
|
||||
host: target.host,
|
||||
},
|
||||
},
|
||||
(proxyRes) => {
|
||||
res.writeHead(proxyRes.statusCode || 502, proxyRes.headers)
|
||||
proxyRes.pipe(res)
|
||||
},
|
||||
)
|
||||
|
||||
proxy.on('error', (error) => {
|
||||
send(
|
||||
res,
|
||||
502,
|
||||
JSON.stringify({ error: 'API proxy failed', detail: error.message }),
|
||||
{ 'content-type': 'application/json; charset=utf-8' },
|
||||
)
|
||||
})
|
||||
|
||||
req.pipe(proxy)
|
||||
}
|
||||
|
||||
function serveStatic(req, res) {
|
||||
const requestPath = decodeURIComponent(new URL(req.url, `http://localhost:${PORT}`).pathname)
|
||||
const relativePath = requestPath === '/' ? '/index.html' : requestPath
|
||||
const filePath = path.normalize(path.join(DIST_DIR, relativePath))
|
||||
|
||||
if (!filePath.startsWith(DIST_DIR)) {
|
||||
return send(res, 403, 'Forbidden', { 'content-type': 'text/plain; charset=utf-8' })
|
||||
}
|
||||
|
||||
fs.readFile(filePath, (error, data) => {
|
||||
if (error) {
|
||||
fs.readFile(path.join(DIST_DIR, 'index.html'), (indexError, indexData) => {
|
||||
if (indexError) {
|
||||
return send(res, 404, 'Build not found. Run npm run build first.', {
|
||||
'content-type': 'text/plain; charset=utf-8',
|
||||
})
|
||||
}
|
||||
|
||||
send(res, 200, indexData, { 'content-type': mimeTypes['.html'] })
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const ext = path.extname(filePath)
|
||||
send(res, 200, data, {
|
||||
'content-type': mimeTypes[ext] || 'application/octet-stream',
|
||||
'cache-control': ext === '.html' ? 'no-cache' : 'public, max-age=31536000, immutable',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
http
|
||||
.createServer((req, res) => {
|
||||
if (req.url === '/health' || req.url.startsWith('/api/')) {
|
||||
proxyRequest(req, res)
|
||||
return
|
||||
}
|
||||
|
||||
serveStatic(req, res)
|
||||
})
|
||||
.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`tssbot-web serving http://localhost:${PORT}`)
|
||||
console.log(`proxying API requests to ${API_UPSTREAM}`)
|
||||
})
|
||||
Reference in New Issue
Block a user