generated from Dicken/dickendock
round12: FritzBox-Merge-Bug vor Doppel-Ausloesung fixen, Scan-Meldungen entschaerfen, Dienstname-Fallback aus Hostname statt IP
This commit is contained in:
@@ -4,7 +4,52 @@ import * as serviceRepo from "../db/repositories/services.js";
|
||||
import * as categoryRepo from "../db/repositories/categories.js";
|
||||
import * as logRepo from "../db/repositories/logs.js";
|
||||
import { scanDeviceServices } from "../scanner/networkScanner.js";
|
||||
import { fetchFritzBoxHosts } from "../scanner/fritzbox.js";
|
||||
import { fetchFritzBoxHosts, type FritzBoxHost } from "../scanner/fritzbox.js";
|
||||
|
||||
/**
|
||||
* Erkennt den von der FritzBox selbst generierten Platzhalter-Namen für
|
||||
* Geräte ohne bekannten Hostnamen (Muster "PC-192-168-1-73"). Ein solcher
|
||||
* Name ist nie einer echten Namensänderung wert, sondern nur ein Rückfall.
|
||||
*/
|
||||
function isGenericFritzboxHostname(hostname: string, ip: string): boolean {
|
||||
return hostname === `PC-${ip.replace(/\./g, "-")}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die FritzBox liefert für ein einzelnes physisches Gerät oft MEHRERE
|
||||
* TR-064-Einträge (IPv4+IPv6, WLAN+Mesh, oder ein alter Platzhaltername neben
|
||||
* dem aktuellen) - alle mit derselben MAC-Adresse. Werden diese einzeln
|
||||
* nacheinander upgeserted, legt der erste Eintrag das Gerät an und der
|
||||
* zweite wird sofort als "Änderung" gegen das gerade erst selbst angelegte
|
||||
* Gerät vorgeschlagen - verwirrend, besonders bei einer leeren Datenbank
|
||||
* (siehe Bugreport). Deshalb hier VOR dem Upsert je MAC zu einem Eintrag
|
||||
* zusammenführen und dabei den aussagekräftigsten Hostnamen wählen (echter
|
||||
* Name statt "PC-<ip>"-Platzhalter, sofern vorhanden).
|
||||
*/
|
||||
function mergeFritzboxHosts(hosts: FritzBoxHost[]): FritzBoxHost[] {
|
||||
const byMac = new Map<string, FritzBoxHost[]>();
|
||||
const withoutMac: FritzBoxHost[] = [];
|
||||
|
||||
for (const host of hosts) {
|
||||
if (!host.mac) {
|
||||
withoutMac.push(host);
|
||||
continue;
|
||||
}
|
||||
const key = host.mac.toLowerCase();
|
||||
const group = byMac.get(key);
|
||||
if (group) group.push(host);
|
||||
else byMac.set(key, [host]);
|
||||
}
|
||||
|
||||
const merged: FritzBoxHost[] = Array.from(byMac.values()).map((group) => {
|
||||
const named = group.find((h) => !isGenericFritzboxHostname(h.hostname, h.ip));
|
||||
const chosen = named ?? group[0];
|
||||
const online = group.find((h) => h.online) ?? group[0];
|
||||
return { ip: online.ip, mac: chosen.mac, hostname: chosen.hostname, online: online.online };
|
||||
});
|
||||
|
||||
return [...merged, ...withoutMac];
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan-Endpunkte. Werden ausschließlich manuell per Knopfdruck ("Jetzt
|
||||
@@ -139,7 +184,11 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
const devicesBeforeScan = deviceRepo.listDevices().filter((d) => d.source === "fritzbox");
|
||||
|
||||
const hosts = await fetchFritzBoxHosts({ host, port, username, password });
|
||||
const results = hosts.map((h) =>
|
||||
// Mehrere TR-064-Einträge für dasselbe physische Gerät (gleiche MAC)
|
||||
// werden VOR dem Upsert zusammengeführt (siehe mergeFritzboxHosts oben) -
|
||||
// deshalb kann "gefundene Einträge" > Anzahl eindeutiger Geräte sein.
|
||||
const mergedHosts = mergeFritzboxHosts(hosts);
|
||||
const results = mergedHosts.map((h) =>
|
||||
deviceRepo.upsertDeviceFromScan({
|
||||
hostname: h.hostname,
|
||||
ip: h.ip,
|
||||
@@ -149,18 +198,7 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
})
|
||||
);
|
||||
|
||||
// Mehrere TR-064-Einträge können auf dasselbe Gerät zusammengeführt
|
||||
// werden (z. B. IPv4+IPv6 oder WLAN+Mesh-Eintrag desselben Geräts,
|
||||
// abgeglichen über MAC/IP) - deshalb kann "gefundene Einträge" > Anzahl
|
||||
// eindeutiger Geräte sein. Für die Rückgabe nach Geräte-ID dedupliziert.
|
||||
const seenIds = new Set<string>();
|
||||
const devices = results
|
||||
.map((r) => r.device)
|
||||
.filter((d) => {
|
||||
if (seenIds.has(d.id)) return false;
|
||||
seenIds.add(d.id);
|
||||
return true;
|
||||
});
|
||||
const devices = results.map((r) => r.device);
|
||||
|
||||
// Vorschläge für abweichende Hostnamen/IPs bereits bekannter Geräte
|
||||
// einsammeln (siehe upsertDeviceFromScan) - werden NICHT automatisch
|
||||
|
||||
Reference in New Issue
Block a user