round60: Delta-Vergleich zum vorherigen Scan (FritzBox + Sammel-Scan) statt statischer Zahlen

This commit is contained in:
2026-07-26 14:09:11 +02:00
parent a7036849b1
commit eef4ddc775
2 changed files with 103 additions and 12 deletions

View File

@@ -334,6 +334,10 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
const allStale: DeviceScanResult["staleServices"] = [];
const allNameChanges: DeviceScanResult["nameChanges"] = [];
const allNew: DeviceScanResult["newServices"] = [];
// Sammelt die IDs ALLER gefundenen Dienste über den kompletten
// Sammel-Scan hinweg - für den Vergleich mit dem vorherigen Lauf (siehe
// weiter unten bei finishJob).
const allServiceIds: string[] = [];
let cancelled = false;
try {
@@ -536,6 +540,7 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
allStale.push(...result.staleServices);
allNameChanges.push(...result.nameChanges);
allNew.push(...result.newServices);
allServiceIds.push(...result.services.map((s) => s.id));
return;
}
@@ -566,6 +571,7 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
allStale.push(...result.staleServices);
allNameChanges.push(...result.nameChanges);
allNew.push(...result.newServices);
allServiceIds.push(...result.services.map((s) => s.id));
} catch (err) {
// Einzelnes fehlgeschlagenes Gerät soll den Rest nicht
// abbrechen - ABER trotzdem persistent loggen, statt
@@ -598,6 +604,38 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
updateJobProgress("devices", scannedCount, null);
}
// NEU (round60): Vergleich mit dem VORHERIGEN Sammel-Scan (siehe
// gleiches Prinzip beim FritzBox-Scan oben) - Mengenvergleich der
// gefundenen Dienst-IDs statt reiner Zahlenvergleich.
const previousServiceIdsRaw = settingsRepo.getSetting("deviceScanLastServiceIds");
const previousServiceIds: string[] | null = previousServiceIdsRaw ? JSON.parse(previousServiceIdsRaw) : null;
const currentServiceIdSet = new Set(allServiceIds);
let changesSinceLastScan: string;
if (cancelled) {
changesSinceLastScan = "Abgebrochen - kein vollständiger Vergleich möglich.";
} else if (previousServiceIds === null) {
changesSinceLastScan = "Erster Scan - kein Vergleich zu einem vorherigen Lauf möglich.";
} else {
const previousSet = new Set(previousServiceIds);
const newlyAppeared = allServiceIds.filter((id) => !previousSet.has(id));
const noLongerSeen = previousServiceIds.filter((id) => !currentServiceIdSet.has(id));
if (newlyAppeared.length === 0 && noLongerSeen.length === 0) {
changesSinceLastScan = "Keine Änderungen seit dem letzten Sammel-Scan.";
} else {
const parts: string[] = [];
if (newlyAppeared.length > 0) parts.push(`${newlyAppeared.length} neue(r) Dienst(e)`);
if (noLongerSeen.length > 0) parts.push(`${noLongerSeen.length} Dienst(e) fehlen jetzt`);
changesSinceLastScan = `Änderungen seit dem letzten Sammel-Scan: ${parts.join(", ")}.`;
}
}
// Bei einem abgebrochenen Lauf NICHT als Vergleichsbasis speichern -
// sonst würde ein unvollständiger Durchlauf fälschlich "Dienste
// fehlen jetzt" für alle noch gar nicht gescannten Geräte anzeigen.
if (!cancelled) {
settingsRepo.setSetting("deviceScanLastServiceIds", JSON.stringify(allServiceIds));
}
finishJob("devices", {
totalDevices: devices.length,
scannedCount,
@@ -607,6 +645,7 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
staleServices: allStale,
nameChanges: allNameChanges,
newServices: allNew,
changesSinceLastScan,
});
} catch (err) {
// WICHTIG: Vorher wurde ein Abbruch des GESAMTEN Sammel-Scans nur im
@@ -794,10 +833,43 @@ function mergeFritzboxHosts(hosts: FritzBoxHost[]): FritzBoxHost[] {
return now - lastSeen >= staleThresholdMs;
});
// NEU (round60): Vergleich mit dem VORHERIGEN Scan-Lauf - vorher
// stand hier bei jedem Scan nur eine absolute Zahl ("45 Einträge"),
// egal ob sich seit dem letzten Mal etwas geändert hatte oder nicht
// (siehe Bugreport: "wird immer nur angezeigt wieviel Einträge beim
// letzten Scan waren, das die ganze Zeit"). Die Geräte-IDs des
// letzten erfolgreichen Laufs werden dafür in den Einstellungen
// (app_settings) gemerkt und mit den JETZT gefundenen verglichen -
// ein einfacher Mengenvergleich (nicht nur ein Zahlenvergleich),
// damit "3 raus, 3 rein" nicht fälschlich als "keine Änderung"
// durchgeht.
const previousDeviceIdsRaw = settingsRepo.getSetting("fritzboxScanLastDeviceIds");
const previousDeviceIds: string[] = previousDeviceIdsRaw ? JSON.parse(previousDeviceIdsRaw) : null;
const currentDeviceIds = devices.map((d) => d.id);
const currentDeviceIdSet = new Set(currentDeviceIds);
let changesSinceLastScan: string;
if (previousDeviceIds === null) {
changesSinceLastScan = "Erster Scan - kein Vergleich zu einem vorherigen Lauf möglich.";
} else {
const previousSet = new Set(previousDeviceIds);
const newlyAppeared = currentDeviceIds.filter((id) => !previousSet.has(id));
const noLongerSeen = previousDeviceIds.filter((id) => !currentDeviceIdSet.has(id));
if (newlyAppeared.length === 0 && noLongerSeen.length === 0) {
changesSinceLastScan = "Keine Änderungen seit dem letzten Scan.";
} else {
const parts: string[] = [];
if (newlyAppeared.length > 0) parts.push(`${newlyAppeared.length} neue(s) Gerät(e)`);
if (noLongerSeen.length > 0) parts.push(`${noLongerSeen.length} Gerät(e) fehlen jetzt`);
changesSinceLastScan = `Änderungen seit dem letzten Scan: ${parts.join(", ")}.`;
}
}
settingsRepo.setSetting("fritzboxScanLastDeviceIds", JSON.stringify(currentDeviceIds));
logRepo.logScan({
type: "fritzbox",
level: "info",
message: `FritzBox-Scan: ${hosts.length} Eintrag/Einträge (${devices.length} eindeutige Geräte)${staleDevices.length > 0 ? `, ${staleDevices.length} nicht mehr gemeldet` : ""}${deviceChanges.length > 0 ? `, ${deviceChanges.length} Änderung(en) vorgeschlagen` : ""}`,
message: `FritzBox-Scan: ${hosts.length} Eintrag/Einträge (${devices.length} eindeutige Geräte)${staleDevices.length > 0 ? `, ${staleDevices.length} nicht mehr gemeldet` : ""}${deviceChanges.length > 0 ? `, ${deviceChanges.length} Änderung(en) vorgeschlagen` : ""} - ${changesSinceLastScan}`,
});
finishJob("fritzbox", {
@@ -805,6 +877,7 @@ function mergeFritzboxHosts(hosts: FritzBoxHost[]): FritzBoxHost[] {
uniqueDevices: devices.length,
staleDevices,
deviceChanges,
changesSinceLastScan,
});
} catch (err) {
const detail = err instanceof Error ? err.message : String(err);