From d3bf314c6271bc0d10ccbef32ee2cf223780e501 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Wed, 27 May 2026 20:12:10 -0400 Subject: [PATCH] fix(launcher): refresh file lists periodically to prune deleted/hidden files The Launcher's background sync never called load_ae_obj_li__event_file for presenter/session files. That function contains stale-record pruning that removes deleted or hidden files from Dexie; without it, the Launcher's IDB retained stale file records indefinitely until manually cleared. Changes: - refresh_presenter_data: add inc_file_li=true so presenter files are pruned every 120s via the existing presenter loop - refresh_current_session_files(): new function that fetches/prunes session- level file lists for the selected session - timer__file_list: 60s interval for refresh_current_session_files - $effect on event_session_id: fires refresh_current_session_files immediately on session switch (no wait for next timer tick) Propagation time: deleted/hidden files visible on remote Launchers within ~60s (session files) or ~120s (presenter files) automatically. Co-Authored-By: Claude Sonnet 4.6 --- .../launcher_background_sync.svelte | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/routes/events/[event_id]/(launcher)/launcher_background_sync.svelte b/src/routes/events/[event_id]/(launcher)/launcher_background_sync.svelte index daad20b9..b81621d6 100644 --- a/src/routes/events/[event_id]/(launcher)/launcher_background_sync.svelte +++ b/src/routes/events/[event_id]/(launcher)/launcher_background_sync.svelte @@ -124,6 +124,7 @@ let timer__session: any = $state(null); let timer__presentation: any = $state(null); let timer__presenter: any = $state(null); let timer__file_sync: any = $state(null); +let timer__file_list: any = $state(null); let is_syncing = false; let show_monitor = $state(false); @@ -196,6 +197,15 @@ onMount(async () => { // 3. Native File Sync Loop (Dexie -> Disk) timer__file_sync = setInterval(() => run_sync_cycle(), loop_info.file_sync); + // 4. File List Refresh Loop (API -> Dexie, prunes deleted/hidden session files) + // WHY: The presenter/session refresh loops don't fetch file lists, so deleted or + // hidden files can stay in Dexie on the Launcher machine indefinitely (until IDB is + // manually cleared). This loop calls load_ae_obj_li__event_file for the selected + // session, which triggers the stale-record pruning in _refresh_file_li_background. + // 60s matches the session/location loops; presenter files are pruned via inc_file_li + // in refresh_presenter_data which runs every 120s. + timer__file_list = setInterval(() => refresh_current_session_files(), 60000); + // Immediate first run for metadata refresh_event_data(); run_device_heartbeat(); @@ -211,6 +221,7 @@ onMount(async () => { setTimeout(() => refresh_session_data(), 1000); setTimeout(() => refresh_presentation_data(), 3000); setTimeout(() => refresh_presenter_data(), 5000); + setTimeout(() => refresh_current_session_files(), 7000); // Clean up stale .tmp files (interrupted downloads) on startup. // Age threshold is user-configurable (cfg → General → Cache Maintenance), default 24h. @@ -235,6 +246,7 @@ onDestroy(() => { if (timer__presentation) clearInterval(timer__presentation); if (timer__presenter) clearInterval(timer__presenter); if (timer__file_sync) clearInterval(timer__file_sync); + if (timer__file_list) clearInterval(timer__file_list); }); // WHY: refresh_location_config() runs on a 60s timer. Without this effect, @@ -248,6 +260,15 @@ $effect(() => { } }); +// WHY: fires refresh_current_session_files() immediately when the operator switches +// sessions so deleted/hidden files are pruned without waiting for the 60s timer. +$effect(() => { + const session_id = $events_slct.event_session_id; + if (session_id) { + refresh_current_session_files(); + } +}); + // Force Sync Trigger: fetches ALL child metadata for ALL sessions in the room. // WHY: by default, the launcher only warms presentation/presenter caches for the // *selected* session to save bandwidth. Onsite operators use this trigger to @@ -341,6 +362,7 @@ async function refresh_presenter_data() { api_cfg: $ae_api, for_obj_type: 'event_session', for_obj_id: session_id, + inc_file_li: true, // WHY: triggers pruning of deleted/hidden presenter files in Dexie try_cache: true, log_lvl: 0 }); @@ -600,6 +622,29 @@ async function refresh_location_config() { } } +/** + * Session File List Refresh + * Fetches the file list for the SELECTED session and prunes stale/deleted/hidden records. + * WHY: The regular session/presenter refresh loops don't fetch file lists, so deleted or + * hidden files persist in the Launcher's Dexie indefinitely. This runs on a 60s timer + * and also fires immediately when the selected session changes. Presenter-level files are + * handled separately via inc_file_li=true in refresh_presenter_data (120s timer). + */ +async function refresh_current_session_files() { + if ($events_loc.launcher.sync_paused) return; + const session_id = $events_slct.event_session_id; + if (!session_id) return; + try { + await events_func.load_ae_obj_li__event_file({ + api_cfg: $ae_api, + for_obj_type: 'event_session', + for_obj_id: session_id, + try_cache: true, + log_lvl: 0 + }); + } catch (err) {} +} + /** * Force Location Sync * Fetches ALL sessions and their children (presentations, presenters, files)