feat(launcher): implement device heartbeat and background sync engine

- Hardened 'find_object_id' in Dexie to support 'event_' prefixed IDs.
- Implemented singleton 'LauncherBackgroundSync' in root launcher layout.
- Added V3-compliant heartbeat and room refresh cycles.
- Fixed redundant component imports and Skeleton UI prop errors.
- Added 'inc_file_li' support to event API loader.
This commit is contained in:
Scott Idem
2026-01-26 11:23:12 -05:00
parent 54a2cfa59f
commit 79917edffc
9 changed files with 61 additions and 27 deletions

View File

@@ -47,7 +47,7 @@
events_trigger,
events_trig
} from '$lib/stores/ae_events_stores';
// import { events_func } from '$lib/ae_events_functions';
import { events_func } from '$lib/ae_events_functions';
import Launcher_cfg from '../launcher_cfg.svelte';
import Launcher_menu from '../launcher_menu.svelte';
@@ -1222,7 +1222,6 @@
</div>
<Drawer
bgColor="bg-blue"
class="bg-orange-100 opacity-90 hover:opacity-97 transition-all duration-1000 border border-gray-300 dark:border-gray-600"
placement="left"
transitionType="fly"
@@ -1231,7 +1230,6 @@
duration: 200,
easing: sineIn
}}
width={'w-md'}
bind:hidden={$events_loc.launcher.hide_drawer__cfg}
id="sidebar1"
>
@@ -1276,7 +1274,6 @@
<Drawer
activateClickOutside={false}
backdrop={false}
class="bg-red-100 opacity-75 hover:opacity-95 transition-all duration-1000"
placement="bottom"
transitionType="fly"
@@ -1285,7 +1282,6 @@
duration: 200,
easing: sineIn
}}
width={'min-h-96 h-1/2'}
bind:hidden={$events_loc.launcher.hide_drawer__debug}
id="sidebar2"
>
@@ -1321,7 +1317,6 @@
open={$events_sess.launcher?.modal__open_event_file_id}
autoclose={false}
placement="top-center"
size=""
class="
bg-gray-500/90 dark:bg-gray-800/90 text-gray-800 dark:text-gray-200
rounded-lg border-gray-200 dark:border-gray-700

View File

@@ -47,7 +47,7 @@
get_device_info
} from '$lib/electron/electron_relay';
import LauncherBackgroundSync from '../../launcher_background_sync.svelte';
// import LauncherBackgroundSync from '../../launcher_background_sync.svelte';
// import Event_launcher_menu from '../../launcher_menu.svelte';
// import Event_launcher_session_view from '../../launcher_session_view.svelte';

View File

@@ -6,6 +6,7 @@
import { onMount, onDestroy } from 'svelte';
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
import { events_slct } from '$lib/stores/ae_events_stores';
import { events_func } from '$lib/ae_events_functions';
import { db_events } from '$lib/ae_events/db_events';
import * as native from '$lib/electron/electron_relay';
@@ -14,6 +15,7 @@
let currently_syncing: string | null = $state(null);
let sync_results: Record<string, 'success' | 'error' | 'pending'> = $state({});
let sync_stats = $state({ total: 0, cached: 0, missing: 0 });
let last_heartbeat: string | null = $state(null);
// Loop Timings (Visible in UI)
let loop_info = $state({
@@ -24,10 +26,10 @@
});
// Timer Handles
let timer__event: any = null;
let timer__device: any = null;
let timer__location: any = null;
let timer__session: any = null;
let timer__event: any = $state(null);
let timer__device: any = $state(null);
let timer__location: any = $state(null);
let timer__session: any = $state(null);
let is_syncing = false;
let show_monitor = $state(false);
@@ -44,12 +46,14 @@
loop_info.session = dev.check_event_session_loop_period || 10000;
timer__event = setInterval(() => run_sync_cycle(), loop_info.event);
timer__device = setInterval(() => { /* TODO: Heartbeat */ }, loop_info.device);
timer__location = setInterval(() => { /* TODO: Refresh Loc */ }, loop_info.location);
timer__device = setInterval(() => run_device_heartbeat(), loop_info.device);
timer__location = setInterval(() => refresh_location_config(), loop_info.location);
timer__session = setInterval(() => run_sync_cycle(), loop_info.session);
// Immediate first run
run_sync_cycle();
run_device_heartbeat();
refresh_location_config();
});
onDestroy(() => {
@@ -128,8 +132,15 @@
* Gathers OS info and updates the device record in the cloud.
*/
async function run_device_heartbeat() {
const device_id = $ae_loc.native_device?.event_device_id || $ae_loc.native_device?.id;
if (!device_id) return;
const dev = $ae_loc.native_device;
const device_id = dev?.event_device_id_random || dev?.id_random || dev?.event_device_id || dev?.id;
if (!device_id) {
if (log_lvl) console.warn('Sync: Heartbeat skipped, no device_id found in $ae_loc.native_device.');
return;
}
if (log_lvl > 1) console.log(`Sync: Running heartbeat for device: ${device_id}`);
try {
const info = await native.get_device_info();
@@ -151,11 +162,12 @@
await events_func.update_ae_obj__event_device({
api_cfg: $ae_api,
event_device_id: device_id,
event_device_id: String(device_id),
data_kv: update_payload,
log_lvl: 0
});
last_heartbeat = new Date().toLocaleTimeString();
if (log_lvl > 1) console.log('Sync: Device heartbeat SUCCESS.');
} catch (err) {
console.error('Sync: Device heartbeat FAILED:', err);
@@ -198,6 +210,11 @@
<span class="opacity-70 text-primary-300">Prefix Len:</span>
<span class="text-right">{$ae_loc.native_device?.hash_prefix_length || 2} chars</span>
<span class="opacity-70 text-primary-300">Heartbeat:</span>
<span class="text-right {last_heartbeat ? 'text-success-500' : 'text-error-500'}">
{last_heartbeat || 'Pending...'}
</span>
</div>
<div class="border-t border-white/10 pt-2 flex flex-col gap-1">

View File

@@ -422,7 +422,7 @@ max-w-max -->
<!-- lg:bg-green-100
xl:bg-green-200 -->
<Event_page_menu {data} {lq__event_obj} />
<Event_page_menu {lq__event_obj} />
{#if !$lq__event_obj}
<div>