fix: serialize WeatherV2 particle loads
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
@@ -20,6 +20,7 @@ export default function App() {
|
||||
const [frames, setFrames] = useState<Record<string, string>>({ T0: "PENDING", T1: "PENDING", T2: "PENDING", T3: "PENDING" });
|
||||
const [transport, setTransport] = useState("PENDING: FILE_REF / FLOAT32_LE / INTERLEAVED_UV");
|
||||
const [httpTransport, setHttpTransport] = useState("PENDING: WeatherV2 HTTP → canonical U/V → WeatherRuntime");
|
||||
const [httpLoading, setHttpLoading] = useState(false);
|
||||
const [weatherVisible, setWeatherVisible] = useState(true);
|
||||
const [particleVisible, setParticleVisible] = useState(true);
|
||||
const [visual, setVisual] = useState(initialVisual);
|
||||
@@ -61,6 +62,8 @@ export default function App() {
|
||||
|
||||
const loadHttpWeather = useCallback(async () => {
|
||||
if (reactTag == null) return setResult("MAP_NOT_READY: wait for GSI/style ready");
|
||||
if (httpLoading) return;
|
||||
setHttpLoading(true);
|
||||
try {
|
||||
setHttpTransport("LOADING: manifest → time index → WVECBIN1 → canonical U/V");
|
||||
const loaded = await loadHttpWeatherV2(reactTag);
|
||||
@@ -71,8 +74,10 @@ export default function App() {
|
||||
} catch (error) {
|
||||
setHttpTransport(`ERROR: ${String(error)}`);
|
||||
setResult(`LOAD HTTP WEATHER: ${String(error)}`);
|
||||
} finally {
|
||||
setHttpLoading(false);
|
||||
}
|
||||
}, [reactTag]);
|
||||
}, [httpLoading, reactTag]);
|
||||
|
||||
const updateVisual = useCallback((key: keyof typeof initialVisual, value: string) => setVisual((current) => ({ ...current, [key]: value })), []);
|
||||
const applyVisual = useCallback(() => void command("particle visual", async (tag) => {
|
||||
@@ -93,7 +98,7 @@ export default function App() {
|
||||
<Text>Basemap: GSI {basemap}</Text><Text>Dataset: ECMWF HRES 20260807 · 513×769 · 3.01 MiB/frame</Text><Text>Runtime: {snapshot.state} / {snapshot.playbackState} / {snapshot.targetFps}</Text><Text selectable>REAL DATA TRANSPORT = {transport}</Text>
|
||||
{realWeatherFrames.map((frame) => <Text selectable key={frame.label}>{frame.label} {frame.cycle}: {frames[frame.label]}</Text>)}
|
||||
<Text selectable>{result}</Text><Button title="LOAD REAL WEATHER T0-T3" onPress={() => void loadRealWeather()} />
|
||||
<Text selectable>HTTP DATA TRANSPORT = {httpTransport}</Text><Button title="LOAD HTTP WEATHER T0-T3" onPress={() => void loadHttpWeather()} />
|
||||
<Text selectable>HTTP DATA TRANSPORT = {httpTransport}</Text><Button title={httpLoading ? "LOADING HTTP WEATHER..." : "LOAD HTTP WEATHER T0-T3"} disabled={httpLoading} onPress={() => void loadHttpWeather()} />
|
||||
<View style={styles.row}>{controls.map(([label, operation]) => <Button key={label} title={label} onPress={() => void command(label, operation)} />)}</View>
|
||||
<View style={styles.row}><Button title={`Weather ${weatherVisible ? "visible" : "hidden"}`} onPress={() => { const next = !weatherVisible; setWeatherVisible(next); void command("weather visible", (tag) => WeatherRuntime.setWeatherColorVisible(tag, next)); }} /><Button title={`Particle ${particleVisible ? "visible" : "hidden"}`} onPress={() => { const next = !particleVisible; setParticleVisible(next); void command("particle visible", (tag) => WeatherRuntime.setParticleVisible(tag, next)); }} /></View>
|
||||
<View style={styles.row}>{realWeatherFrames.map((frame) => <Button key={`seek-${frame.label}`} title={`seek ${frame.label}`} onPress={() => void command(`seek ${frame.label}`, (tag) => WeatherRuntime.setForecastTime(tag, frame.validTime))} />)}</View>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
- 包含 WeatherColor、RasterParticle、HostField binary file ingress、Timeline / Playback 与 React Native WeatherRuntime。
|
||||
- Native/RN binary ingress 已在 STEP-061 验证;GSI + 真实 WeatherV2 + Particle Android 综合验证已在 STEP-062 完成。
|
||||
- 发布前 Consumer 验证修正 MLRN 依赖为 peer dependency,避免嵌套 native module 与 Windows codegen 长路径。
|
||||
- WeatherV2 HTTP 全帧加载增加按 map `reactTag` 的 single-flight 保护,避免重复点击造成并发 clear/submit 与非单调快照拒绝。
|
||||
- 新增纯 JS/TS WeatherV2 HTTP 客户端:manifest/time-index → WVECBIN1 full wind frame → canonical interleaved U/V。
|
||||
- 新增 `loadWeatherV2WindIntoRuntime()`:顺序下载、转换、写临时 binary file 并通过现有 WeatherRuntime 提交,不建立第二套 Timeline/MIX。
|
||||
- WeatherV2 文件存储通过 `WeatherV2BinaryFileStore` 注入,包本身不强依赖 Expo FileSystem,NavSea 可复用自己的缓存实现。
|
||||
|
||||
@@ -21,7 +21,9 @@ function expectedSubmit(index: number): FieldSubmitResult {
|
||||
* U/V contract and submits it through the existing map-owned WeatherRuntime.
|
||||
* Core remains the sole owner of T0/T1/MIX and playback interpolation.
|
||||
*/
|
||||
export async function loadWeatherV2WindIntoRuntime(
|
||||
const inFlightLoads = new Map<number, Promise<LoadWeatherV2WindResult>>();
|
||||
|
||||
async function loadWeatherV2WindIntoRuntimeInternal(
|
||||
options: LoadWeatherV2WindOptions,
|
||||
): Promise<LoadWeatherV2WindResult> {
|
||||
const { reactTag, client, fileStore } = options;
|
||||
@@ -93,3 +95,20 @@ export async function loadWeatherV2WindIntoRuntime(
|
||||
}
|
||||
return { context, frames: loaded, runtime };
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes full WeatherV2 loads per map view. Repeated taps while a load is in flight
|
||||
* reuse the same Promise instead of clearing/submitting a second overlapping timeline.
|
||||
*/
|
||||
export function loadWeatherV2WindIntoRuntime(
|
||||
options: LoadWeatherV2WindOptions,
|
||||
): Promise<LoadWeatherV2WindResult> {
|
||||
const existing = inFlightLoads.get(options.reactTag);
|
||||
if (existing != null) return existing;
|
||||
|
||||
const task = loadWeatherV2WindIntoRuntimeInternal(options).finally(() => {
|
||||
if (inFlightLoads.get(options.reactTag) === task) inFlightLoads.delete(options.reactTag);
|
||||
});
|
||||
inFlightLoads.set(options.reactTag, task);
|
||||
return task;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user