55 lines
1.9 KiB
TypeScript
55 lines
1.9 KiB
TypeScript
import { useCallback, useState } from 'react';
|
|
import Constants from 'expo-constants';
|
|
import { supabase } from '../lib/supabase';
|
|
import { protection } from '../lib/protection';
|
|
|
|
type SyncResult = { ok: boolean; count?: number; plan?: string; error?: string };
|
|
|
|
/**
|
|
* Synct die binary Blocklist (`blocklist.bin`) vom Server in die App-Group.
|
|
* Die NEFilter-Extension memory-mapped diese Datei — ohne Sync = leere
|
|
* Blocklist = nichts wird geblockt.
|
|
*
|
|
* Triggers:
|
|
* - direkt nach activateUrlFilter() success
|
|
* - nach Domain-Add/-Submit/-Delete
|
|
* - bei App-Resume (in case Server-Updates kamen)
|
|
*
|
|
* Backend respondet 304 wenn ETag matched → kein Re-Download.
|
|
*/
|
|
export function useBlocklistSync() {
|
|
const [syncing, setSyncing] = useState(false);
|
|
const [lastResult, setLastResult] = useState<SyncResult | null>(null);
|
|
|
|
const sync = useCallback(async (): Promise<SyncResult> => {
|
|
if (syncing) return { ok: false, error: 'already_syncing' };
|
|
setSyncing(true);
|
|
try {
|
|
const baseURL = Constants.expoConfig?.extra?.apiUrl as string;
|
|
const session = (await supabase.auth.getSession()).data.session;
|
|
const authToken = session?.access_token;
|
|
|
|
if (!baseURL || !authToken) {
|
|
const result = { ok: false, error: 'missing_baseURL_or_token' };
|
|
setLastResult(result);
|
|
return result;
|
|
}
|
|
|
|
const res = await protection.syncBlocklist({ baseURL, authToken });
|
|
const result = { ok: true, count: res.count, plan: res.plan };
|
|
setLastResult(result);
|
|
console.log('[blocklist-sync] ok:', res);
|
|
return result;
|
|
} catch (e: any) {
|
|
const result = { ok: false, error: e?.message ?? 'sync_failed' };
|
|
setLastResult(result);
|
|
console.error('[blocklist-sync] failed:', e);
|
|
return result;
|
|
} finally {
|
|
setSyncing(false);
|
|
}
|
|
}, [syncing]);
|
|
|
|
return { sync, syncing, lastResult };
|
|
}
|