110 lines
3.0 KiB
TypeScript
110 lines
3.0 KiB
TypeScript
import { browser } from '$app/environment';
|
|
import { derived, get, writable } from 'svelte/store';
|
|
import { debounce, showSnackbar } from '$lib/util';
|
|
import { currentProfile, profiles } from './settings';
|
|
import { miscSettings } from './misc';
|
|
import { volumes } from './volume-data';
|
|
|
|
export type SyncConfig = {
|
|
key: string | null;
|
|
auto: boolean;
|
|
notifications: boolean;
|
|
};
|
|
|
|
const stored = browser ? window.localStorage.getItem('syncConfig') : undefined;
|
|
const initial: SyncConfig = stored ? JSON.parse(stored) : { key: null, auto: false, notifications: true };
|
|
export const syncConfig = writable<SyncConfig>(initial);
|
|
|
|
syncConfig.subscribe((value) => {
|
|
if (browser) {
|
|
window.localStorage.setItem('syncConfig', JSON.stringify(value));
|
|
}
|
|
});
|
|
|
|
export const isSyncEnabled = derived(syncConfig, ($cfg) => Boolean($cfg.key));
|
|
|
|
async function callApi(method: 'GET' | 'POST', payload?: any) {
|
|
if (!browser) return null;
|
|
const url = method === 'GET' ? `/api/sync?key=${encodeURIComponent(get(syncConfig).key || '')}` : '/api/sync';
|
|
const res = await fetch(url, {
|
|
method,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: method === 'POST' ? JSON.stringify(payload) : undefined
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function pullAll() {
|
|
const cfg = get(syncConfig);
|
|
if (!cfg.key) throw new Error('No sync key configured');
|
|
const data = await callApi('GET');
|
|
if (!data) return;
|
|
|
|
if (data.profiles) {
|
|
profiles.set(data.profiles);
|
|
}
|
|
if (data.current_profile) {
|
|
currentProfile.set(data.current_profile);
|
|
}
|
|
if (data.misc_settings) {
|
|
miscSettings.set(data.misc_settings);
|
|
}
|
|
if (data.volumes) {
|
|
volumes.set(data.volumes);
|
|
}
|
|
if (cfg.notifications) {
|
|
showSnackbar('Pulled from server');
|
|
}
|
|
}
|
|
|
|
export async function pushAll() {
|
|
const cfg = get(syncConfig);
|
|
if (!cfg.key) throw new Error('No sync key configured');
|
|
|
|
const payload = {
|
|
key: cfg.key,
|
|
profiles: get(profiles),
|
|
current_profile: get(currentProfile),
|
|
misc_settings: get(miscSettings),
|
|
volumes: get(volumes)
|
|
};
|
|
await callApi('POST', payload);
|
|
if (cfg.notifications) {
|
|
showSnackbar('Pushed to server');
|
|
}
|
|
}
|
|
|
|
function setupAutoSync() {
|
|
if (!browser) return;
|
|
let unsubscribeFns: Array<() => void> = [];
|
|
|
|
function resubscribe() {
|
|
unsubscribeFns.forEach((fn) => fn());
|
|
unsubscribeFns = [];
|
|
|
|
if (!get(syncConfig).auto || !get(syncConfig).key) return;
|
|
|
|
const schedulePush = () => debounce(() => {
|
|
pushAll().catch((error) => {
|
|
console.error('Auto-sync failed:', error);
|
|
});
|
|
}, 300);
|
|
|
|
unsubscribeFns.push(profiles.subscribe(() => schedulePush()));
|
|
unsubscribeFns.push(currentProfile.subscribe(() => schedulePush()));
|
|
unsubscribeFns.push(miscSettings.subscribe(() => schedulePush()));
|
|
unsubscribeFns.push(volumes.subscribe(() => schedulePush()));
|
|
}
|
|
|
|
resubscribe();
|
|
unsubscribeFns.push(syncConfig.subscribe(() => resubscribe()));
|
|
}
|
|
|
|
if (browser) {
|
|
setupAutoSync();
|
|
}
|
|
|
|
|
|
|