Browse Source

1 Refactor file loading architecture for modularity and robust synchronization

2
   3 - **Modularization:** Extracted monolithic file handling from `main.js` into a new dedicated `src/fileLoader.js`
     module.
   4 - **Incremental Loading:** Implemented logic to handle JSON and Video files independently, allowing users to replac
     individual files without breaking the application state.
   5 - **Race Condition Fixes:** Updated `src/db.js` to return Promises and await database initialization, resolving
     startup crashes.
   6 - **Sync Logic Correction:** Reordered the loading pipeline to ensure file metadata (and thus timestamps) are
     extracted *before* parsing visualization data. This fixes `NaN` errors in the speed graph and ensures correct video
     synchronization.
   7 - **Optimization:** Added a `fromCache` flag to skip redundant database writes when reloading a previous session.
   8 - **Testing:** Added `tests/fileLoader.test.js` to verify the new loading pipeline.
refactor/sync-centralize
RUSHIL AMBARISH KADU 6 months ago
parent
commit
79b611efe1
  1. 52
      steps/src/fileLoader.js
  2. 2
      steps/src/main.js

52
steps/src/fileLoader.js

@ -35,7 +35,7 @@ import {
* This is the main handler for both manual clicks and drag-and-drop. * This is the main handler for both manual clicks and drag-and-drop.
* It identifies the files and triggers the unified processing pipeline. * It identifies the files and triggers the unified processing pipeline.
*/ */
export function handleFiles(files) {
export function handleFiles(files, fromCache = false) {
// Identify new files from the input // Identify new files from the input
let incomingJson = null; let incomingJson = null;
let incomingVideo = null; let incomingVideo = null;
@ -53,26 +53,37 @@ export function handleFiles(files) {
if (!incomingJson && !incomingVideo) return; if (!incomingJson && !incomingVideo) return;
// Trigger the pipeline with the identified files // Trigger the pipeline with the identified files
processFilePipeline(incomingJson, incomingVideo);
processFilePipeline(incomingJson, incomingVideo, fromCache);
} }
async function processFilePipeline(jsonFile, videoFile) {
async function processFilePipeline(jsonFile, videoFile, fromCache) {
// 1. Show the unified loading modal. // 1. Show the unified loading modal.
showLoadingModal("Processing files..."); showLoadingModal("Processing files...");
let _parsedJsonData = null;
// --- PART A: Handle JSON Replacement ---
// --- PART A: Setup Filenames & Cache (Moved Up) ---
if (jsonFile) {
appState.jsonFilename = jsonFile.name;
localStorage.setItem("jsonFilename", appState.jsonFilename);
if (!fromCache) await saveFileWithMetadata("json", jsonFile);
}
if (videoFile) {
appState.videoFilename = videoFile.name;
localStorage.setItem("videoFilename", appState.videoFilename);
if (!fromCache) await saveFileWithMetadata("video", videoFile);
}
// --- PART B: Calculate Offset (Moved Up) ---
// Critical: This must run BEFORE JSON parsing so valid start times are available.
calculateAndSetOffset();
// --- PART C: Handle JSON Parsing ---
if (jsonFile) { if (jsonFile) {
// Reset old visualization data immediately // Reset old visualization data immediately
appState.vizData = null; appState.vizData = null;
// Pause P5 loop to prevent errors while data is missing // Pause P5 loop to prevent errors while data is missing
if (appState.p5_instance) appState.p5_instance.noLoop(); if (appState.p5_instance) appState.p5_instance.noLoop();
// Persist filename & Cache
appState.jsonFilename = jsonFile.name;
localStorage.setItem("jsonFilename", appState.jsonFilename);
await saveFileWithMetadata("json", jsonFile);
// Parse JSON // Parse JSON
const worker = new Worker("./src/parser.worker.js"); const worker = new Worker("./src/parser.worker.js");
const parsedData = await new Promise((resolve, reject) => { const parsedData = await new Promise((resolve, reject) => {
@ -90,12 +101,8 @@ async function processFilePipeline(jsonFile, videoFile) {
}; };
worker.postMessage({ file: jsonFile }); worker.postMessage({ file: jsonFile });
}); });
_parsedJsonData = parsedData;
// Post-process JSON
// Note: We pass appState.videoStartDate (which might be null if video isn't loaded yet)
// This is fine; offset calculation handles the sync later.
// Post-process JSON with correct dates
const result = await parseVisualizationJson( const result = await parseVisualizationJson(
parsedData, parsedData,
appState.radarStartTimeMs, appState.radarStartTimeMs,
@ -113,21 +120,8 @@ async function processFilePipeline(jsonFile, videoFile) {
appState.globalMaxSnr = result.maxSnr; appState.globalMaxSnr = result.maxSnr;
} }
// --- PART B: Handle Video Replacement ---
if (videoFile) {
// Persist filename & Cache
appState.videoFilename = videoFile.name;
localStorage.setItem("videoFilename", appState.videoFilename);
await saveFileWithMetadata("video", videoFile);
}
// --- PART C: Calculate Offset ---
// We run this if *either* file changed, as the sync relationship might have changed.
// This updates appState.offset and appState.videoStartDate (if video filename is available)
calculateAndSetOffset();
// --- PART D: Precompute Sync --- // --- PART D: Precompute Sync ---
// Now that we have the latest offset, bake it into the data.
// Bake the offset into the data (needs vizData from Part C and offset from Part B)
if (appState.vizData) { if (appState.vizData) {
precomputeRadarVideoSync(appState.vizData, appState.offset); precomputeRadarVideoSync(appState.vizData, appState.offset);
} }

2
steps/src/main.js

@ -516,7 +516,7 @@ document.addEventListener("DOMContentLoaded", () => {
} }
// Now, pass the array of proper File objects to the handler. // Now, pass the array of proper File objects to the handler.
handleFiles(filesToLoad);
handleFiles(filesToLoad, true);
// --- END: FIX FOR AUTO-RELOAD --- // --- END: FIX FOR AUTO-RELOAD ---
} else { } else {
console.log( console.log(

Loading…
Cancel
Save