Fix: Restore Native caching business logic and implement 3-mode launcher
- Implemented Default, Onsite, and Native launcher modes in launcher_file_cont.svelte. - Restored background pre-caching logic with configurable timers in new LauncherBackgroundSync component. - Fixed standard browser download regression for regular website mode. - Modernized electron_relay to TypeScript and standardized bridge detection in layout. - Detailed startup and background sync technical flow in documentation.
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* launcher_background_sync.svelte
|
||||
* Handles background pre-caching of event files when running in Native mode.
|
||||
* Uses configurable timers from the device configuration.
|
||||
*/
|
||||
import { onMount, untrack, onDestroy } from 'svelte';
|
||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||
import { events_slct } from '$lib/stores/ae_events_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import * as native from '$lib/electron/electron_relay';
|
||||
|
||||
let { log_lvl = 0 } = $props();
|
||||
|
||||
let currently_syncing: string | null = $state(null);
|
||||
let sync_results: Record<string, 'success' | 'error' | 'pending'> = $state({});
|
||||
let sync_interval: any = null;
|
||||
|
||||
// Trigger initial sync and setup interval
|
||||
onMount(() => {
|
||||
if (!$ae_loc.is_native) return;
|
||||
|
||||
// 1. Initial Immediate Sync
|
||||
setTimeout(() => {
|
||||
if (log_lvl) console.log('Sync: Triggering immediate startup sync cycle.');
|
||||
const files = $events_slct.event_file_obj_li;
|
||||
if (files && files.length > 0) {
|
||||
const ids = files.map((f: any) => f.event_file_id);
|
||||
process_sync_queue(ids);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// 2. Setup Loop Timer
|
||||
// Default to 60 seconds if not specified in native_device config
|
||||
const loop_period = $ae_loc.native_device?.check_event_loop_period || 60000;
|
||||
if (log_lvl) console.log(`Sync: Starting background loop with period: ${loop_period}ms`);
|
||||
|
||||
sync_interval = setInterval(() => {
|
||||
const files = $events_slct.event_file_obj_li;
|
||||
if (files && files.length > 0) {
|
||||
const ids = files.map((f: any) => f.event_file_id);
|
||||
process_sync_queue(ids);
|
||||
}
|
||||
}, loop_period);
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (sync_interval) clearInterval(sync_interval);
|
||||
});
|
||||
|
||||
// Reactive Watch: Also trigger if the file list changes significantly
|
||||
$effect(() => {
|
||||
if (!$ae_loc.is_native) return;
|
||||
|
||||
const files = $events_slct.event_file_obj_li;
|
||||
if (!files || files.length === 0) return;
|
||||
|
||||
untrack(() => {
|
||||
const file_ids = files.map((f: any) => f.event_file_id);
|
||||
// Only process if we haven't checked these specific IDs recently
|
||||
process_sync_queue(file_ids);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Iterates through the file list and downloads missing files.
|
||||
*/
|
||||
async function process_sync_queue(ids: string[]) {
|
||||
const cacheRoot = $ae_loc.local_file_cache_path;
|
||||
if (!cacheRoot) {
|
||||
console.warn('Sync: local_file_cache_path not set. Skipping sync.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (log_lvl) console.log(`Sync: Processing queue of ${ids.length} files...`);
|
||||
|
||||
for (const id of ids) {
|
||||
// Skip if already successfully cached in this session to avoid redundant IPC calls
|
||||
if (sync_results[id] === 'success') continue;
|
||||
|
||||
try {
|
||||
const file_obj = await db_events.file.get(id);
|
||||
if (!file_obj || !file_obj.hash_sha256) continue;
|
||||
|
||||
const exists = await native.check_hash_file_cache({
|
||||
cacheRoot,
|
||||
hash: file_obj.hash_sha256
|
||||
});
|
||||
|
||||
if (exists) {
|
||||
sync_results[id] = 'success';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (log_lvl) console.log(`Sync: Downloading missing file: ${file_obj.filename}`);
|
||||
currently_syncing = file_obj.filename;
|
||||
|
||||
const url = `${$ae_api.base_url}/v3/crud/hosted_file/${file_obj.hosted_file_id}/download`;
|
||||
const result = await native.download_to_cache({
|
||||
url,
|
||||
cacheRoot,
|
||||
hash: file_obj.hash_sha256,
|
||||
apiKey: $ae_api.api_secret_key
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
sync_results[id] = 'success';
|
||||
if (log_lvl) console.log(`Sync: Successfully cached ${file_obj.filename}`);
|
||||
} else {
|
||||
console.error(`Sync: Failed to cache ${file_obj.filename}:`, result.error);
|
||||
sync_results[id] = 'error';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Sync: Error processing file ${id}:`, err);
|
||||
}
|
||||
}
|
||||
currently_syncing = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if currently_syncing && log_lvl}
|
||||
<div class="fixed bottom-4 right-4 bg-black/80 text-white p-2 rounded-lg text-[10px] z-[9999] border border-primary-500 animate-pulse">
|
||||
<span class="fas fa-sync fa-spin mr-2"></span>
|
||||
Pre-Caching: {currently_syncing}
|
||||
</div>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user