isle.pizza/src/core/service-worker.js

171 lines
5.3 KiB
JavaScript

// Service Worker registration and messaging
import { showUpdatePopup, installState, swRegistration } from '../stores.js';
let downloaderWorker = null;
export async function registerServiceWorker() {
if (import.meta.env.DEV || !('serviceWorker' in navigator)) {
return null;
}
try {
const registration = await navigator.serviceWorker.register('/sw.js');
await navigator.serviceWorker.ready;
swRegistration.set(registration);
// Check if there's already a waiting service worker (update ready)
if (registration.waiting) {
showUpdatePopup.set(true);
}
// Listen for new service worker updates
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing;
if (newWorker) {
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
showUpdatePopup.set(true);
}
});
}
});
navigator.serviceWorker.addEventListener('message', handleServiceWorkerMessage);
navigator.serviceWorker.addEventListener('controllerchange', () => {
checkCacheStatus();
});
return registration;
} catch (error) {
console.error('Service worker registration failed:', error);
return null;
}
}
function handleServiceWorkerMessage(event) {
const { action, language, isInstalled, success, missingFiles } = event.data;
const languageSelect = document.getElementById('language-select');
if (language && languageSelect && language !== languageSelect.value) return;
switch (action) {
case 'cache_status':
installState.update(state => ({
...state,
installed: isInstalled,
missingFiles: missingFiles || []
}));
break;
case 'uninstall_complete':
installState.update(state => ({
...state,
installed: !success,
installing: false
}));
checkCacheStatus();
break;
default:
console.warn('Unknown service worker action:', action);
break;
}
}
export function checkCacheStatus() {
if (!navigator.serviceWorker.controller) return;
const languageSelect = document.getElementById('language-select');
const hdTextures = document.getElementById('check-hd-textures');
const hdMusic = document.getElementById('check-hd-music');
const widescreenBgs = document.getElementById('check-widescreen-bgs');
const badEnding = document.getElementById('check-ending');
const siFiles = getSiFilesForCache(hdMusic, widescreenBgs, badEnding);
navigator.serviceWorker.controller.postMessage({
action: 'check_cache_status',
language: languageSelect?.value || 'en',
hdTextures: hdTextures?.checked || false,
siFiles
});
}
export function getSiFilesForCache(hdMusic, widescreenBgs, badEnding) {
const siFiles = [];
if (hdMusic?.checked) siFiles.push('/LEGO/extra/hdmusic.si');
if (widescreenBgs?.checked) siFiles.push('/LEGO/extra/widescreen.si');
if (badEnding?.checked) siFiles.push('/LEGO/extra/badend.si');
return siFiles;
}
export async function startInstall(missingFiles, language) {
await requestPersistentStorage();
if (downloaderWorker) downloaderWorker.terminate();
downloaderWorker = new Worker(new URL('./downloader.worker.js', import.meta.url));
downloaderWorker.onmessage = handleWorkerMessage;
installState.update(state => ({
...state,
installing: true,
progress: 0
}));
downloaderWorker.postMessage({
action: 'install',
missingFiles,
language
});
}
export function startUninstall(language) {
navigator.serviceWorker.controller.postMessage({
action: 'uninstall_language_pack',
language
});
}
export async function requestPersistentStorage() {
try {
if (navigator.storage && navigator.storage.persist) {
const isPersisted = await navigator.storage.persisted();
if (!isPersisted) {
await navigator.storage.persist();
}
}
} catch (e) {
console.warn('Failed to request persistent storage:', e);
}
}
function handleWorkerMessage(event) {
const { action, progress, success, error } = event.data;
switch (action) {
case 'install_progress':
installState.update(state => ({
...state,
installing: true,
progress
}));
break;
case 'install_complete':
installState.update(state => ({
...state,
installed: success,
installing: false
}));
if (downloaderWorker) downloaderWorker.terminate();
break;
case 'install_failed':
alert(`Download failed: ${error}`);
installState.update(state => ({
...state,
installing: false
}));
if (downloaderWorker) downloaderWorker.terminate();
break;
default:
console.warn('Unknown worker action:', action);
break;
}
}