fix(assets): publish controllable traffic signal runtime
This commit is contained in:
@@ -28,6 +28,8 @@ function normalizeAreaConfig(raw, options = {}) {
|
||||
const pipelineDir = path.resolve(outputOverrides.pipelineDir || path.join(areaDir, "_pipeline"));
|
||||
const packageDir = path.resolve(outputOverrides.packageDir || path.join(areaDir, "package"));
|
||||
const packageStagingDir = path.resolve(outputOverrides.packageStagingDir || path.join(pipelineDir, "package-staging"));
|
||||
const packageRuntimeDir = path.resolve(outputOverrides.packageRuntimeDir || path.join(packageDir, "runtime"));
|
||||
const packageStagingRuntimeDir = path.resolve(outputOverrides.packageStagingRuntimeDir || path.join(packageStagingDir, "runtime"));
|
||||
const previewDir = path.resolve(outputOverrides.previewDir || path.join(areaDir, "_preview"));
|
||||
const geojsonDir = path.resolve(outputOverrides.geojsonDir || path.join(areaDir, "osm2streets_web_out"));
|
||||
const outputs = {
|
||||
@@ -47,11 +49,13 @@ function normalizeAreaConfig(raw, options = {}) {
|
||||
packageStagingModelDir: path.resolve(outputOverrides.packageStagingModelDir || path.join(packageStagingDir, "models")),
|
||||
packagePrimaryGlb: path.resolve(outputOverrides.packagePrimaryGlb || path.join(packageDir, "models", `${fileStem}.glb`)),
|
||||
glb: path.resolve(outputOverrides.glb || path.join(packageStagingDir, "models", `${fileStem}.glb`)),
|
||||
trafficSignalsDynamicGlb: path.resolve(
|
||||
outputOverrides.trafficSignalsDynamicGlb || path.join(previewDir, `${fileStem}-traffic-signals-dynamic.glb`),
|
||||
),
|
||||
trafficSignalsCountdown0Glb: path.resolve(outputOverrides.trafficSignalsCountdown0Glb || path.join(previewDir, `${fileStem}-traffic-signals-countdown-0.glb`)),
|
||||
trafficSignalsCountdown1Glb: path.resolve(outputOverrides.trafficSignalsCountdown1Glb || path.join(previewDir, `${fileStem}-traffic-signals-countdown-1.glb`)),
|
||||
packageRuntimeDir,
|
||||
packageStagingRuntimeDir,
|
||||
trafficSignalsDynamicGlb: path.resolve(outputOverrides.trafficSignalsDynamicGlb || path.join(packageStagingRuntimeDir, "traffic-signals-dynamic.glb")),
|
||||
trafficSignalsCountdown0Glb: path.resolve(outputOverrides.trafficSignalsCountdown0Glb || path.join(packageStagingRuntimeDir, "traffic-signals-countdown-0.glb")),
|
||||
trafficSignalsCountdown1Glb: path.resolve(outputOverrides.trafficSignalsCountdown1Glb || path.join(packageStagingRuntimeDir, "traffic-signals-countdown-1.glb")),
|
||||
packageTrafficSignals: path.resolve(outputOverrides.packageTrafficSignals || path.join(packageRuntimeDir, "traffic-signals.json")),
|
||||
packageStagingTrafficSignals: path.resolve(outputOverrides.packageStagingTrafficSignals || path.join(packageStagingRuntimeDir, "traffic-signals.json")),
|
||||
metadata: path.resolve(outputOverrides.metadata || path.join(packageStagingDir, "manifest.json")),
|
||||
cesiumPreview: path.resolve(
|
||||
outputOverrides.cesiumPreview || path.join(areaDir, `${fileStem}-cesium-preview.html`),
|
||||
|
||||
@@ -329,7 +329,7 @@ function artifactStatus(area) {
|
||||
["QGIS project", area.outputs.qgisProject, true, "file"],
|
||||
["QGIS preview", area.outputs.qgisPreview, true, "file"],
|
||||
["Traffic signal assemblies", area.outputs.trafficSignalAssemblies, true, "file"],
|
||||
["Traffic signal runtime", area.outputs.trafficSignals, true, "file"],
|
||||
["Traffic signal runtime", area.outputs.packageTrafficSignals, true, "file"],
|
||||
["Blend scene", area.outputs.blend, true, "file"],
|
||||
["Render PNG", area.outputs.render, true, "file"],
|
||||
["Package manifest", area.outputs.packageManifest, true, "file"],
|
||||
@@ -403,7 +403,7 @@ function stageManifestStatus(area, configPath = null) {
|
||||
geojsonDir: area.outputs.geojsonDir,
|
||||
...sceneGeojsonFiles(area),
|
||||
trafficSignalAssemblies: area.outputs.trafficSignalAssemblies,
|
||||
trafficSignals: area.outputs.trafficSignals,
|
||||
trafficSignals: area.outputs.packageTrafficSignals,
|
||||
gpkg: area.outputs.gpkg,
|
||||
qgisProject: area.outputs.qgisProject,
|
||||
qgisPreview: optionalExpectedFile(area.outputs.qgisPreview),
|
||||
@@ -421,7 +421,7 @@ function stageManifestStatus(area, configPath = null) {
|
||||
geojsonDir: area.outputs.geojsonDir,
|
||||
...sceneGeojsonFiles(area),
|
||||
trafficSignalAssemblies: area.outputs.trafficSignalAssemblies,
|
||||
trafficSignals: area.outputs.trafficSignals,
|
||||
trafficSignals: area.outputs.packageTrafficSignals,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -433,7 +433,7 @@ function stageManifestStatus(area, configPath = null) {
|
||||
geojsonDir: area.outputs.geojsonDir,
|
||||
...sceneGeojsonFiles(area),
|
||||
trafficSignalAssemblies: area.outputs.trafficSignalAssemblies,
|
||||
trafficSignals: area.outputs.trafficSignals,
|
||||
trafficSignals: area.outputs.packageTrafficSignals,
|
||||
},
|
||||
outputs: {
|
||||
blend: area.outputs.blend,
|
||||
|
||||
@@ -110,7 +110,7 @@ function previewSummary(area) {
|
||||
metadataName: "package/manifest.json",
|
||||
routeName: path.relative(area.outputs.areaDir, area.outputs.vehicleRoute).split(path.sep).join("/"),
|
||||
vehicleModelName: path.relative(area.outputs.areaDir, area.outputs.vehicleModel).split(path.sep).join("/"),
|
||||
trafficSignalsName: path.relative(area.outputs.areaDir, area.outputs.trafficSignals).split(path.sep).join("/"),
|
||||
trafficSignalsName: "package/runtime/traffic-signals.json",
|
||||
routeSegments: Array.isArray(route.segments) ? route.segments.length : null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -177,7 +177,16 @@
|
||||
category: asset.category,
|
||||
semantic: asset.role === "layer",
|
||||
}));
|
||||
return staticAssets.concat(metadata.previewAssets || []);
|
||||
const runtimeAssets = (metadata.runtime || []).filter((asset) => asset.type !== "traffic-signal-anchors").map((asset) => ({
|
||||
id: asset.id,
|
||||
label: asset.id,
|
||||
type: "model",
|
||||
url: new URL(asset.uri, new URL(config.metadataName, window.location.href)).href,
|
||||
enabled: true,
|
||||
category: asset.type === "traffic-signal-lenses" ? "dynamic" : asset.type === "traffic-signal-countdown" ? "countdown" : asset.type,
|
||||
phaseGroup: asset.phaseGroup,
|
||||
}));
|
||||
return staticAssets.concat(runtimeAssets, metadata.previewAssets || []);
|
||||
}
|
||||
const assets = Array.isArray(metadata.assets) && metadata.assets.length
|
||||
? metadata.assets
|
||||
|
||||
@@ -49,6 +49,17 @@ function validateManifest(manifest, packageDir, options = {}) {
|
||||
if (!resolved.startsWith(`${path.resolve(packageDir)}${path.sep}`) || !fs.existsSync(resolved)) fail(`asset '${asset.id}' is missing from package: ${asset.uri}`);
|
||||
}
|
||||
}
|
||||
if (manifest.runtime !== undefined && !Array.isArray(manifest.runtime)) fail("runtime must be an array");
|
||||
for (const runtime of manifest?.runtime || []) {
|
||||
if (!runtime || typeof runtime.id !== "string" || !runtime.id) { fail("runtime asset id is required"); continue; }
|
||||
if (ids.has(runtime.id)) fail(`duplicate asset id '${runtime.id}'`); ids.add(runtime.id);
|
||||
if (typeof runtime.type !== "string" || !runtime.type) fail(`runtime '${runtime.id}' type is required`);
|
||||
try { relativeUri(runtime.uri); } catch (error) { fail(error.message); continue; }
|
||||
if (packageDir && options.requireFiles !== false) {
|
||||
const resolved = path.resolve(packageDir, runtime.uri);
|
||||
if (!resolved.startsWith(`${path.resolve(packageDir)}${path.sep}`) || !fs.existsSync(resolved)) fail(`runtime '${runtime.id}' is missing from package: ${runtime.uri}`);
|
||||
}
|
||||
}
|
||||
if (sceneCount !== 1) fail("exactly one scene asset is required");
|
||||
if (errors.length) throw new Error(`Invalid asset package manifest: ${errors.join("; ")}`);
|
||||
return manifest;
|
||||
@@ -60,6 +71,11 @@ function addIntegrity(manifest, packageDir) {
|
||||
const buffer = fs.readFileSync(file);
|
||||
asset.integrity = { bytes: buffer.length, sha256: crypto.createHash("sha256").update(buffer).digest("hex") };
|
||||
}
|
||||
for (const runtime of manifest.runtime || []) {
|
||||
const file = path.resolve(packageDir, runtime.uri);
|
||||
const buffer = fs.readFileSync(file);
|
||||
runtime.integrity = { bytes: buffer.length, sha256: crypto.createHash("sha256").update(buffer).digest("hex") };
|
||||
}
|
||||
return manifest;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user