import { ref, computed, onMounted, onUnmounted } from "vue"; import { useTauri, type IphoneDeviceState, type DesktopProtectionState, type MagicDeviceInfo } from "~/composables/useTauri"; import { useIphoneDevice, useMagicDevices, useMagicSession } from "~/composables/useMagicState"; export interface ProtectionStatus { overall: "protected" | "partial" | "unprotected" | "unknown"; label: string; message: string; iosConnected: boolean; iosProtected: boolean; desktopProtected: boolean; anyBackendDevice: boolean; } const IPHONE_POLL_INTERVAL = 5000; const DEVICE_REFRESH_INTERVAL = 30000; function normalizeHostname(value: string): string { return (value.toLowerCase().split(".")[0] ?? "").trim(); } export function useProtectionStatus() { const { detectIphoneState, getDesktopProtectionStatus, getMagicDevices, getMagicStatus, getHostname, } = useTauri(); const iphone = useIphoneDevice(); const devices = useMagicDevices(); const session = useMagicSession(); const desktopProtection = ref(null); const localHostname = ref(null); const loading = ref(false); const lastError = ref(null); const lastUpdated = ref(null); let iphoneTimer: ReturnType | null = null; let deviceTimer: ReturnType | null = null; const iosConnected = computed(() => !!iphone.value); const iosProtected = computed(() => { if (!iphone.value) return false; const hasEnrollment = iphone.value.installedProfileIDs?.includes("org.rebreak.mdm.enrollment"); const hasLock = iphone.value.installedProfileIDs?.includes("org.rebreak.protection.contentfilter.sideload"); return iphone.value.isSupervised && hasEnrollment && hasLock; }); const currentBackendDevice = computed(() => { if (!localHostname.value) return null; const local = normalizeHostname(localHostname.value); return devices.value.find((d) => normalizeHostname(d.hostname) === local) ?? null; }); const desktopProtected = computed(() => !!desktopProtection.value?.active || !!currentBackendDevice.value); const anyBackendDevice = computed(() => devices.value.length > 0); const status = computed(() => { const ios = iosConnected.value; const iosOk = iosProtected.value; const desktopOk = desktopProtected.value; const backendOk = anyBackendDevice.value; if (!ios && !desktopOk && !backendOk) { return { overall: "unprotected", label: "Kein Schutz aktiv", message: "Verbinde ein iPhone oder aktiviere den Desktop-Schutz.", iosConnected: false, iosProtected: false, desktopProtected: false, anyBackendDevice: false, }; } if (ios && !iosOk) { return { overall: "partial", label: "iOS-Schutz unvollständig", message: "Supervision oder Schutz-Profile fehlen. Führe das Setup fort.", iosConnected: true, iosProtected: false, desktopProtected: desktopOk, anyBackendDevice: backendOk, }; } if (iosOk && desktopOk) { return { overall: "protected", label: "Vollständig geschützt", message: "iPhone und Desktop sind aktiv geschützt.", iosConnected: true, iosProtected: true, desktopProtected: true, anyBackendDevice: backendOk, }; } if (iosOk || desktopOk || backendOk) { return { overall: "partial", label: "Teilweise geschützt", message: iosOk ? "iPhone geschützt. Desktop-Schutz ist optional." : desktopOk ? "Desktop geschützt. iPhone noch nicht verbunden." : "Ein registriertes Gerät vorhanden, aber keine lokale Schutzkontrolle.", iosConnected: ios, iosProtected: iosOk, desktopProtected: desktopOk, anyBackendDevice: backendOk, }; } return { overall: "unknown", label: "Status unbekannt", message: "Schutzstatus konnte nicht ermittelt werden.", iosConnected: false, iosProtected: false, desktopProtected: false, anyBackendDevice: false, }; }); async function refreshIphone() { try { const state = await detectIphoneState(); iphone.value = state; } catch (e: any) { // Bei Fehler nicht crashen — Gerät ist einfach nicht verbunden iphone.value = null; } } async function refreshDesktop() { try { desktopProtection.value = await getDesktopProtectionStatus(); } catch (e: any) { lastError.value = e?.message ?? "Desktop-Schutzstatus konnte nicht geladen werden"; } } async function refreshBackendDevices() { try { devices.value = await getMagicDevices(); if (session.value?.dnsToken) { await getMagicStatus(session.value.dnsToken); } } catch (e: any) { lastError.value = e?.message ?? "Geräte konnten nicht geladen werden"; } } async function refresh() { loading.value = true; lastError.value = null; await Promise.all([ refreshIphone(), refreshDesktop(), refreshBackendDevices(), refreshHostname(), ]); lastUpdated.value = new Date(); loading.value = false; } async function refreshHostname() { try { localHostname.value = await getHostname(); } catch (e: any) { localHostname.value = null; } } onMounted(() => { refresh(); iphoneTimer = setInterval(refreshIphone, IPHONE_POLL_INTERVAL); deviceTimer = setInterval(refreshBackendDevices, DEVICE_REFRESH_INTERVAL); }); onUnmounted(() => { if (iphoneTimer) clearInterval(iphoneTimer); if (deviceTimer) clearInterval(deviceTimer); }); return { status, iphone: computed(() => iphone.value), desktopProtection, localHostname, loading, lastError, lastUpdated, iosConnected, iosProtected, desktopProtected, anyBackendDevice, refresh, }; }