web-3Dviever-glb/server.js Repository web-3Dviever-glb Original path web-3Dviever-glb/server.jsRole SOURCE Size 2798 bytes Lines 63 SHA-256 555c4a893d51756dd844ec7e356d5acdcffec26766973ba39b13f1cd2b5ca8f6Displayed range 1–63 Previous file/page · Project index
import express from "express";
import path from "path";
import fs from "fs";
import { fileURLToPath } from "url";
const app = express();
const PORT = Number(process.env.PORT || 7600);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const indexPath = path.join(__dirname, "index.html");
const manifestPath = path.join(__dirname, "models.json");
const inputDirectory = path.join(__dirname, "input");
const SUPPORTED_EXTENSIONS = new Set([".ply", ".glb", ".gltf"]);
function extensionPriority(fileName) {
const extension = path.extname(fileName).toLowerCase();
if (extension === ".glb") return 0;
if (extension === ".gltf") return 1;
if (extension === ".ply") return 2;
return 9;
}
function compareModels(left, right) {
const leftBase = path.basename(left, path.extname(left));
const rightBase = path.basename(right, path.extname(right));
const baseComparison = leftBase.localeCompare(rightBase, "pl", { numeric: true, sensitivity: "base" });
return baseComparison !== 0 ? baseComparison : extensionPriority(left) - extensionPriority(right);
}
function readModels() {
fs.mkdirSync(inputDirectory, { recursive: true });
return fs.readdirSync(inputDirectory, { withFileTypes: true })
.filter((entry) => entry.isFile())
.map((entry) => entry.name)
.filter((name) => SUPPORTED_EXTENSIONS.has(path.extname(name).toLowerCase()))
.sort(compareModels);
}
app.disable("x-powered-by");
app.get("/api/models", (_req, res) => { res.setHeader("Cache-Control", "no-store"); res.json(readModels()); });
app.get("/models.json", (_req, res) => {
res.setHeader("Cache-Control", "no-store");
return fs.existsSync(manifestPath) ? res.sendFile(manifestPath) : res.json(readModels());
});
app.use("/input", express.static(inputDirectory, {
etag: false, maxAge: 0, acceptRanges: true,
setHeaders: (res, filePath) => {
const extension = path.extname(filePath).toLowerCase();
if (extension === ".glb") res.setHeader("Content-Type", "model/gltf-binary");
else if (extension === ".gltf") res.setHeader("Content-Type", "model/gltf+json");
else if (extension === ".ply") res.setHeader("Content-Type", "application/octet-stream");
res.setHeader("Cache-Control", "no-store");
}
}));
app.get(["/", "/index.html"], (_req, res) => { res.setHeader("Cache-Control", "no-store"); res.sendFile(indexPath); });
app.get("/favicon.ico", (_req, res) => res.status(204).end());
app.listen(PORT, () => {
console.log(`Scaniverse GLB Web Viewer: http://localhost:${PORT}`);
for (const model of readModels()) {
const stats = fs.statSync(path.join(inputDirectory, model));
console.log(`- ${model} (${(stats.size / 1024 / 1024).toFixed(1)} MB)`);
}
});