234 lines
7.5 KiB
JavaScript
234 lines
7.5 KiB
JavaScript
import {
|
|
loadGeoJSONFromPath,
|
|
loadLandingPoints,
|
|
getCableLegendItems,
|
|
toggleCables,
|
|
} from "./cables.js";
|
|
import {
|
|
clearSatelliteData,
|
|
getSatelliteLegendItems,
|
|
loadSatellites,
|
|
toggleSatellites,
|
|
} from "./satellites.js";
|
|
import {
|
|
loadBGPAnomalies,
|
|
toggleBGP,
|
|
} from "./bgp.js";
|
|
import {
|
|
loadComputeCenters,
|
|
toggleComputeCenters,
|
|
} from "./compute-centers.js";
|
|
import {
|
|
getCountryBoundaryLegendItems,
|
|
loadCountryBoundaries,
|
|
toggleCountryBoundaries,
|
|
} from "./country-boundaries.js";
|
|
|
|
/**
|
|
* Layer startup task registry.
|
|
*
|
|
* This module is the startup-task counterpart to the layer registry in controls.js:
|
|
* - controls.js owns layer metadata such as startupPriority/startupMode/startupMessage
|
|
* - this file owns the executable startup task factory for each layer id
|
|
*
|
|
* A startup task is registered via registerLayerStartupTask(id, taskFactory).
|
|
* The taskFactory receives a startup context from main.js and must return an async
|
|
* function with the signature async (layerDefinition) => void.
|
|
*
|
|
* Put a task here only when a layer needs dedicated startup loading work:
|
|
* - preloading data at boot
|
|
* - staged loading with progress/loading messages
|
|
* - post-load UI refresh or warmup
|
|
*
|
|
* Do not put plain visibility toggles or persistent UI state here; those still belong
|
|
* to the layer registry/state flow in controls.js.
|
|
*/
|
|
const startupTaskRegistry = new Map();
|
|
|
|
export function resolveStartupMessage(layer, key, fallback) {
|
|
const message = layer?.startupMessage;
|
|
if (message && typeof message === "object" && key in message) {
|
|
return message[key];
|
|
}
|
|
if (typeof message === "string" && message.trim()) {
|
|
return message;
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
export function createLayerStartupTaskMap(context) {
|
|
return Object.fromEntries(
|
|
Array.from(startupTaskRegistry.entries()).map(([id, taskFactory]) => [
|
|
id,
|
|
taskFactory(context),
|
|
]),
|
|
);
|
|
}
|
|
|
|
export function registerLayerStartupTask(id, taskFactory) {
|
|
if (typeof id !== "string" || !id.trim()) {
|
|
throw new Error("registerLayerStartupTask 需要有效的图层 id");
|
|
}
|
|
if (typeof taskFactory !== "function") {
|
|
throw new Error("registerLayerStartupTask 需要可调用的任务工厂");
|
|
}
|
|
startupTaskRegistry.set(id, taskFactory);
|
|
}
|
|
|
|
function registerBuiltinLayerStartupTasks() {
|
|
startupTaskRegistry.clear();
|
|
registerCountryBoundaryStartupTask();
|
|
registerCableStartupTask();
|
|
registerComputeCenterStartupTask();
|
|
registerBGPStartupTask();
|
|
registerSatelliteStartupTask();
|
|
}
|
|
|
|
function registerCableStartupTask() {
|
|
registerLayerStartupTask("cables", (context) => async (layer) => {
|
|
if (!context.isCablesEnabled()) return;
|
|
|
|
context.setLoadingMessage(
|
|
resolveStartupMessage(layer, "prepare", "正在加载登陆点..."),
|
|
);
|
|
await context.yieldFrame(12);
|
|
try {
|
|
await loadLandingPoints(context.scene, context.earth, { silent: true });
|
|
} catch (error) {
|
|
context.reportError("登陆点", error);
|
|
}
|
|
if (context.isCancelled()) return;
|
|
await context.yieldFrame(16);
|
|
|
|
context.setLoadingMessage(
|
|
resolveStartupMessage(layer, "load", "正在加载海缆..."),
|
|
);
|
|
await context.yieldFrame(12);
|
|
try {
|
|
await loadGeoJSONFromPath(context.scene, context.earth, { silent: true });
|
|
if (!context.isCancelled() && context.isCablesEnabled()) {
|
|
toggleCables(true);
|
|
context.updateCableToggleUi(true);
|
|
context.setLegendItems("cables", getCableLegendItems());
|
|
context.refreshLegend();
|
|
}
|
|
} catch (error) {
|
|
context.reportError(layer?.startupLabel || layer?.label || "海缆", error);
|
|
}
|
|
if (context.isCancelled()) return;
|
|
await context.yieldFrame(16);
|
|
});
|
|
}
|
|
|
|
function registerSatelliteStartupTask() {
|
|
registerLayerStartupTask("satellites", (context) => async (layer) => {
|
|
if (!context.isSatellitesEnabled()) return;
|
|
|
|
context.setLoadingMessage(
|
|
resolveStartupMessage(layer, "load", "正在加载卫星..."),
|
|
);
|
|
await context.yieldFrame(12);
|
|
try {
|
|
clearSatelliteData();
|
|
const loadResult = await loadSatellites({
|
|
limit: context.getInitialSatelliteLoadLimit(),
|
|
});
|
|
if (!context.isCancelled() && context.isSatellitesEnabled()) {
|
|
context.updateSatelliteToggleUi(true, loadResult.count);
|
|
context.setLegendItems("satellites", getSatelliteLegendItems());
|
|
context.refreshLegend();
|
|
context.scheduleSatellitePositionWarmup(() => {
|
|
if (!context.isCancelled() && context.isSatellitesEnabled()) {
|
|
toggleSatellites(true);
|
|
}
|
|
});
|
|
|
|
if (context.shouldHydrateFullSatelliteSet(loadResult)) {
|
|
const hydrationToken = context.nextSatelliteHydrationToken();
|
|
context.hydrateAllSatellitesInBackground(
|
|
() =>
|
|
hydrationToken === context.getSatelliteHydrationToken() &&
|
|
!context.isCancelled() &&
|
|
context.isSatellitesEnabled(),
|
|
);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
context.reportError(layer?.startupLabel || layer?.label || "卫星", error);
|
|
}
|
|
if (context.isCancelled()) return;
|
|
await context.yieldFrame(16);
|
|
});
|
|
}
|
|
|
|
function registerBGPStartupTask() {
|
|
registerLayerStartupTask("bgp", (context) => async (layer) => {
|
|
context.setLoadingMessage(
|
|
resolveStartupMessage(layer, "load", "正在加载BGP态势..."),
|
|
);
|
|
await context.yieldFrame(12);
|
|
try {
|
|
const bgpResult = await loadBGPAnomalies(context.scene, context.earth);
|
|
if (!context.isCancelled()) {
|
|
toggleBGP(context.getShowBGP());
|
|
context.updateBGPHud(bgpResult);
|
|
context.syncBGPKnownEventIds();
|
|
}
|
|
} catch (error) {
|
|
context.reportError(layer?.startupLabel || layer?.label || "BGP态势", error);
|
|
}
|
|
if (context.isCancelled()) return;
|
|
await context.yieldFrame(16);
|
|
});
|
|
}
|
|
|
|
function registerCountryBoundaryStartupTask() {
|
|
registerLayerStartupTask("countryBoundaries", (context) => async (layer) => {
|
|
context.setLoadingMessage(
|
|
resolveStartupMessage(layer, "load", "正在加载海陆基座..."),
|
|
);
|
|
await context.yieldFrame(12);
|
|
try {
|
|
await loadCountryBoundaries();
|
|
if (!context.isCancelled()) {
|
|
const textureOn = context.isEarthTextureVisible();
|
|
toggleCountryBoundaries(context.getShowCountryBoundaries(), {
|
|
showTint: !textureOn,
|
|
showLandFill: true,
|
|
suppressLandFill: false,
|
|
});
|
|
context.setLegendItems("countryBoundaries", getCountryBoundaryLegendItems());
|
|
context.refreshLegend();
|
|
}
|
|
} catch (error) {
|
|
context.reportError(layer?.startupLabel || layer?.label || "国界", error);
|
|
}
|
|
if (context.isCancelled()) return;
|
|
await context.yieldFrame(16);
|
|
});
|
|
}
|
|
|
|
function registerComputeCenterStartupTask() {
|
|
registerLayerStartupTask("computeCenters", (context) => async (layer) => {
|
|
context.setLoadingMessage(
|
|
resolveStartupMessage(layer, "load", "正在加载算力中心..."),
|
|
);
|
|
await context.yieldFrame(12);
|
|
try {
|
|
const computeCenterResult = await loadComputeCenters(context.scene, context.earth);
|
|
if (!context.isCancelled()) {
|
|
toggleComputeCenters(context.getShowComputeCenters());
|
|
context.updateComputeCenterHud(computeCenterResult);
|
|
context.setLegendItems("computeCenters", context.getComputeCenterLegendItems());
|
|
context.refreshLegend();
|
|
}
|
|
} catch (error) {
|
|
context.reportError(layer?.startupLabel || layer?.label || "算力中心", error);
|
|
}
|
|
if (context.isCancelled()) return;
|
|
await context.yieldFrame(16);
|
|
});
|
|
}
|
|
|
|
registerBuiltinLayerStartupTasks();
|