Launcher: preserve legacy address fields in IDB; add file_sync to loop_info

ae_events__event.ts: Add legacy flat address fields (address_name,
address_line_1, address_city, etc.) to properties_to_save. Events
predating location_address_json still return these flat fields from
the API; they must survive an IDB round-trip without being stripped
by _process_generic_props, or the edit form's fallback reads return
undefined.

launcher_background_sync.svelte:
- Move file_sync interval into loop_info $state alongside other
  intervals; load from cfg/device config with fallback (30 s). Keeps
  all intervals in one place for UI display consistency.
- Align onMount fallback values to match loop_info defaults.
- Add sync_paused mid-loop break: long sync cycles now honour a pause
  request per-iteration rather than waiting for the entire batch.
This commit is contained in:
Scott Idem
2026-03-10 14:21:37 -04:00
parent ffc430a727
commit 46c2d2da12
2 changed files with 42 additions and 18 deletions

View File

@@ -797,7 +797,7 @@ export async function qry_ae_obj_li__event_v2({
return filtered_obj_li.slice(0, limit);
}
// Updated 2025-05-09
// Updated 2026-03-10
export const properties_to_save = [
'id',
'event_id',
@@ -858,7 +858,23 @@ export const properties_to_save = [
'file_count',
'file_count_all',
'internal_use_count',
'event_file_id_li_json'
'event_file_id_li_json',
// Legacy flat address fields — preserved so background SWR re-fires do not wipe
// address data for events that predate location_address_json. The edit form reads
// these as a fallback: location_address_json?.name ?? address_name ?? ''.
// New saves always write structured data into location_address_json, but the API
// may still return the flat fields for older records and they must survive an IDB
// round-trip without being stripped by _process_generic_props.
'address_location_id',
'address_name',
'address_line_1',
'address_line_2',
'address_city',
'address_state',
'address_postal_code',
'address_country',
'address_country_alpha_2_code',
'address_country_subdivision_code'
];
async function _process_generic_props<T extends Record<string, any>>({

View File

@@ -21,16 +21,18 @@
let last_heartbeat: string | null = $state(null);
// Loop Timings (Visible in UI)
// WHY: Session was 15s which combined with the SWR background-refresh pattern
// caused a continuous API call every 15s even on cache hits. 60s is still
// WHY: Session was originally 15s which combined with the SWR background-refresh
// pattern caused a continuous API call every 15s even on cache hits. 60s is still
// responsive for live conference use but dramatically reduces server load.
// Defaults here must match the onMount fallbacks below — keep in sync.
let loop_info = $state({
event: 90000,
device: 60000,
location: 60000,
session: 60000,
presentation: 120000,
presenter: 120000
presenter: 120000,
file_sync: 30000
});
// Timer Handles
@@ -72,27 +74,28 @@
const dev = $ae_loc.native_device || {};
const cfg = $events_loc.launcher.sync_intervals || {};
// Load timings from persistent config, with fallbacks to device config or defaults
loop_info.event = cfg.event || dev.check_event_loop_period || 90000;
loop_info.device = cfg.device || dev.check_event_device_loop_period || 60000;
loop_info.location = cfg.location || dev.check_event_location_loop_period || 30000;
loop_info.session = cfg.session || dev.check_event_session_loop_period || 15000;
loop_info.presentation = cfg.presentation || dev.check_event_presentation_loop_period || 45000;
loop_info.presenter = cfg.presenter || dev.check_event_presenter_loop_period || 60000;
// Load timings from persistent config, with fallbacks to device config or defaults.
// Fallback values here must match the loop_info $state defaults above — keep in sync.
loop_info.event = cfg.event || dev.check_event_loop_period || 90000;
loop_info.device = cfg.device || dev.check_event_device_loop_period || 60000;
loop_info.location = cfg.location || dev.check_event_location_loop_period || 60000;
loop_info.session = cfg.session || dev.check_event_session_loop_period || 60000;
loop_info.presentation = cfg.presentation || dev.check_event_presentation_loop_period || 120000;
loop_info.presenter = cfg.presenter || dev.check_event_presenter_loop_period || 120000;
loop_info.file_sync = cfg.file_sync || dev.check_file_sync_loop_period || 30000;
// 1. Structural/Metadata Loops
timer__event = setInterval(() => refresh_event_data(), loop_info.event);
timer__device = setInterval(() => run_device_heartbeat(), loop_info.device);
timer__event = setInterval(() => refresh_event_data(), loop_info.event);
timer__device = setInterval(() => run_device_heartbeat(), loop_info.device);
timer__location = setInterval(() => refresh_location_config(), loop_info.location);
// 2. Room Content Refresh Loops (API -> Dexie)
timer__session = setInterval(() => refresh_session_data(), loop_info.session);
timer__session = setInterval(() => refresh_session_data(), loop_info.session);
timer__presentation = setInterval(() => refresh_presentation_data(), loop_info.presentation);
timer__presenter = setInterval(() => refresh_presenter_data(), loop_info.presenter);
timer__presenter = setInterval(() => refresh_presenter_data(), loop_info.presenter);
// 3. Native File Sync Loop (Dexie -> Disk)
const sync_period = cfg.file_sync || dev.check_file_sync_loop_period || 10000;
timer__file_sync = setInterval(() => run_sync_cycle(), sync_period);
timer__file_sync = setInterval(() => run_sync_cycle(), loop_info.file_sync);
// Immediate first run for metadata
refresh_event_data();
@@ -241,6 +244,11 @@
let missing_count = 0;
for (const file_obj of files) {
// Re-check pause flag each iteration — a sync cycle can run for many
// seconds if there are missing files, so we must honour a pause request
// mid-loop rather than waiting for the entire batch to finish.
if ($events_loc.launcher.sync_paused) break;
if (!file_obj.hash_sha256) continue;
if (sync_results[file_obj.event_file_id] === 'success') {
cached_count++;