Organizes 11 projects for Cerbo GX/Venus OS into a single repository: - axiom-nmea: Raymarine LightHouse protocol decoder - dbus-generator-ramp: Generator current ramp controller - dbus-lightning: Blitzortung lightning monitor - dbus-meteoblue-forecast: Meteoblue weather forecast - dbus-no-foreign-land: noforeignland.com tracking - dbus-tides: Tide prediction from depth + harmonics - dbus-vrm-history: VRM cloud history proxy - dbus-windy-station: Windy.com weather upload - mfd-custom-app: MFD app deployment package - venus-html5-app: Custom Victron HTML5 app fork - watermaker: Watermaker PLC control UI Adds root README, .gitignore, project template, and per-project .gitignore files. Sensitive config files excluded via .gitignore with .example templates provided. Made-with: Cursor
69 lines
1.8 KiB
JavaScript
69 lines
1.8 KiB
JavaScript
const http = require("http")
|
|
const fs = require("fs")
|
|
const path = require("path")
|
|
|
|
const PORT = parseInt(process.env.SERVE_PORT, 10) || 3001
|
|
const DIST_DIR = path.resolve(__dirname, "..", "dist")
|
|
const APP_PREFIX = "/app"
|
|
|
|
const MIME_TYPES = {
|
|
".html": "text/html",
|
|
".js": "application/javascript",
|
|
".css": "text/css",
|
|
".json": "application/json",
|
|
".png": "image/png",
|
|
".jpg": "image/jpeg",
|
|
".svg": "image/svg+xml",
|
|
".ico": "image/x-icon",
|
|
".woff": "font/woff",
|
|
".woff2": "font/woff2",
|
|
".ttf": "font/ttf",
|
|
".map": "application/json",
|
|
".txt": "text/plain",
|
|
".webmanifest": "application/manifest+json",
|
|
}
|
|
|
|
const server = http.createServer((req, res) => {
|
|
let urlPath = req.url.split("?")[0]
|
|
|
|
if (urlPath === "/") {
|
|
res.writeHead(302, { Location: "/app/" })
|
|
res.end()
|
|
return
|
|
}
|
|
|
|
if (!urlPath.startsWith(APP_PREFIX)) {
|
|
res.writeHead(404)
|
|
res.end("Not Found")
|
|
return
|
|
}
|
|
|
|
let filePath = urlPath.slice(APP_PREFIX.length) || "/index.html"
|
|
if (filePath === "/") filePath = "/index.html"
|
|
|
|
const fullPath = path.join(DIST_DIR, filePath)
|
|
|
|
if (!fullPath.startsWith(DIST_DIR)) {
|
|
res.writeHead(403)
|
|
res.end("Forbidden")
|
|
return
|
|
}
|
|
|
|
fs.stat(fullPath, (err, stats) => {
|
|
if (!err && stats.isFile()) {
|
|
const ext = path.extname(fullPath)
|
|
const contentType = MIME_TYPES[ext] || "application/octet-stream"
|
|
res.writeHead(200, { "Content-Type": contentType })
|
|
fs.createReadStream(fullPath).pipe(res)
|
|
} else {
|
|
const indexPath = path.join(DIST_DIR, "index.html")
|
|
res.writeHead(200, { "Content-Type": "text/html" })
|
|
fs.createReadStream(indexPath).pipe(res)
|
|
}
|
|
})
|
|
})
|
|
|
|
server.listen(PORT, "0.0.0.0", () => {
|
|
console.log(`Serving venus-html5-app on http://0.0.0.0:${PORT}/app/`)
|
|
})
|