| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 |
- // Local-only review server. Serves model evidence and proxies the existing app's real engine/GIS assets.
- // Nothing from this tool is copied into the production web build.
- import http from 'node:http'
- import { createReadStream, existsSync, statSync } from 'node:fs'
- import { dirname, resolve, extname, sep } from 'node:path'
- import { fileURLToPath } from 'node:url'
- const root = dirname(fileURLToPath(import.meta.url))
- const upstream = new URL(process.env.COCKPIT_BASE || 'http://127.0.0.1:8001')
- const port = Number(process.env.MODEL_REVIEW_PORT || 8092)
- const mime = {
- '.html': 'text/html; charset=utf-8',
- '.json': 'application/json',
- '.glb': 'model/gltf-binary',
- '.png': 'image/png',
- }
- const server = http.createServer((req, res) => {
- const url = new URL(req.url, 'http://localhost')
- if (url.pathname === '/' || url.pathname === '/preview.html' || url.pathname.startsWith('/review-assets/')) {
- const relative = url.pathname.startsWith('/review-assets/')
- ? decodeURIComponent(url.pathname.slice(15))
- : 'preview.html'
- const file = resolve(root, relative)
- if (!file.startsWith(root + sep) || !existsSync(file) || !statSync(file).isFile()) {
- res.writeHead(404)
- res.end()
- return
- }
- res.writeHead(200, {
- 'Content-Type': mime[extname(file)] || 'application/octet-stream',
- 'Cache-Control': 'no-store',
- })
- createReadStream(file).pipe(res)
- return
- }
- const proxy = http.request(
- new URL(req.url, upstream),
- { method: req.method, headers: { ...req.headers, host: upstream.host } },
- (response) => {
- res.writeHead(response.statusCode, response.headers)
- response.pipe(res)
- }
- )
- proxy.on('error', () => {
- res.writeHead(502)
- res.end('Local cockpit preview server unavailable')
- })
- req.pipe(proxy)
- })
- server.listen(port, '127.0.0.1', () =>
- console.log(`Model review: http://127.0.0.1:${port}/preview.html (engine/GIS: ${upstream.origin})`)
- )
|