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:
@@ -797,7 +797,7 @@ export async function qry_ae_obj_li__event_v2({
|
|||||||
return filtered_obj_li.slice(0, limit);
|
return filtered_obj_li.slice(0, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2025-05-09
|
// Updated 2026-03-10
|
||||||
export const properties_to_save = [
|
export const properties_to_save = [
|
||||||
'id',
|
'id',
|
||||||
'event_id',
|
'event_id',
|
||||||
@@ -858,7 +858,23 @@ export const properties_to_save = [
|
|||||||
'file_count',
|
'file_count',
|
||||||
'file_count_all',
|
'file_count_all',
|
||||||
'internal_use_count',
|
'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>>({
|
async function _process_generic_props<T extends Record<string, any>>({
|
||||||
|
|||||||
@@ -21,16 +21,18 @@
|
|||||||
let last_heartbeat: string | null = $state(null);
|
let last_heartbeat: string | null = $state(null);
|
||||||
|
|
||||||
// Loop Timings (Visible in UI)
|
// Loop Timings (Visible in UI)
|
||||||
// WHY: Session was 15s which combined with the SWR background-refresh pattern
|
// WHY: Session was originally 15s which combined with the SWR background-refresh
|
||||||
// caused a continuous API call every 15s even on cache hits. 60s is still
|
// 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.
|
// 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({
|
let loop_info = $state({
|
||||||
event: 90000,
|
event: 90000,
|
||||||
device: 60000,
|
device: 60000,
|
||||||
location: 60000,
|
location: 60000,
|
||||||
session: 60000,
|
session: 60000,
|
||||||
presentation: 120000,
|
presentation: 120000,
|
||||||
presenter: 120000
|
presenter: 120000,
|
||||||
|
file_sync: 30000
|
||||||
});
|
});
|
||||||
|
|
||||||
// Timer Handles
|
// Timer Handles
|
||||||
@@ -72,27 +74,28 @@
|
|||||||
const dev = $ae_loc.native_device || {};
|
const dev = $ae_loc.native_device || {};
|
||||||
const cfg = $events_loc.launcher.sync_intervals || {};
|
const cfg = $events_loc.launcher.sync_intervals || {};
|
||||||
|
|
||||||
// Load timings from persistent config, with fallbacks to device config or defaults
|
// Load timings from persistent config, with fallbacks to device config or defaults.
|
||||||
loop_info.event = cfg.event || dev.check_event_loop_period || 90000;
|
// Fallback values here must match the loop_info $state defaults above — keep in sync.
|
||||||
loop_info.device = cfg.device || dev.check_event_device_loop_period || 60000;
|
loop_info.event = cfg.event || dev.check_event_loop_period || 90000;
|
||||||
loop_info.location = cfg.location || dev.check_event_location_loop_period || 30000;
|
loop_info.device = cfg.device || dev.check_event_device_loop_period || 60000;
|
||||||
loop_info.session = cfg.session || dev.check_event_session_loop_period || 15000;
|
loop_info.location = cfg.location || dev.check_event_location_loop_period || 60000;
|
||||||
loop_info.presentation = cfg.presentation || dev.check_event_presentation_loop_period || 45000;
|
loop_info.session = cfg.session || dev.check_event_session_loop_period || 60000;
|
||||||
loop_info.presenter = cfg.presenter || dev.check_event_presenter_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
|
// 1. Structural/Metadata Loops
|
||||||
timer__event = setInterval(() => refresh_event_data(), loop_info.event);
|
timer__event = setInterval(() => refresh_event_data(), loop_info.event);
|
||||||
timer__device = setInterval(() => run_device_heartbeat(), loop_info.device);
|
timer__device = setInterval(() => run_device_heartbeat(), loop_info.device);
|
||||||
timer__location = setInterval(() => refresh_location_config(), loop_info.location);
|
timer__location = setInterval(() => refresh_location_config(), loop_info.location);
|
||||||
|
|
||||||
// 2. Room Content Refresh Loops (API -> Dexie)
|
// 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__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)
|
// 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(), loop_info.file_sync);
|
||||||
timer__file_sync = setInterval(() => run_sync_cycle(), sync_period);
|
|
||||||
|
|
||||||
// Immediate first run for metadata
|
// Immediate first run for metadata
|
||||||
refresh_event_data();
|
refresh_event_data();
|
||||||
@@ -241,6 +244,11 @@
|
|||||||
let missing_count = 0;
|
let missing_count = 0;
|
||||||
|
|
||||||
for (const file_obj of files) {
|
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 (!file_obj.hash_sha256) continue;
|
||||||
if (sync_results[file_obj.event_file_id] === 'success') {
|
if (sync_results[file_obj.event_file_id] === 'success') {
|
||||||
cached_count++;
|
cached_count++;
|
||||||
|
|||||||
Reference in New Issue
Block a user