generated from Dicken/dickendock
round28: Portscan-Retry fuer bekannte Dienste (Echo/Samsung-Falschmeldungen behoben), 7-Tage-Schwelle jetzt auch fuer einzelne Dienste, geraeteuebergreifender Scan-Status in der Navigation
This commit is contained in:
@@ -15,6 +15,7 @@ function mapRow(row: typeof services.$inferSelect): Service {
|
||||
displayName: row.displayName,
|
||||
hostname: row.hostname,
|
||||
url: row.url,
|
||||
updatedAt: row.updatedAt,
|
||||
https: row.https,
|
||||
port: row.port,
|
||||
category: row.category,
|
||||
|
||||
@@ -71,7 +71,11 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
// erkennen, welche davon diesmal nicht mehr gefunden wurden ("stale").
|
||||
const servicesBeforeScan = serviceRepo.listServicesByDevice(device.id);
|
||||
|
||||
const { services: discovered, suggestedHostname } = await scanDeviceServices(device);
|
||||
const { services: discovered, suggestedHostname } = await scanDeviceServices(
|
||||
device,
|
||||
undefined,
|
||||
servicesBeforeScan.map((s) => s.port)
|
||||
);
|
||||
|
||||
// Jede erkannte Kategorie auch in der categories-Tabelle anlegen, damit
|
||||
// sie unter Admin -> Kategorien auftaucht und dort umbenannt/sortiert
|
||||
@@ -112,9 +116,20 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
|
||||
// Dienste, die es vorher gab, aber diesmal nicht mehr gefunden wurden
|
||||
// (Port nicht mehr offen) – werden NICHT automatisch gelöscht, sondern
|
||||
// zur manuellen Durchsicht zurückgegeben (siehe Admin -> Scanner).
|
||||
// erst nach dem konfigurierten Schwellenwert (gleiche Einstellung wie
|
||||
// bei nicht mehr gemeldeten Geräten, siehe Einstellungen) zur
|
||||
// manuellen Durchsicht zurückgegeben. Ein einzelner verpasster Scan
|
||||
// (z. B. Gerät kurz neu gestartet) soll nicht sofort als "verschwunden"
|
||||
// gemeldet werden.
|
||||
const foundPorts = new Set(discovered.map((d) => d.port));
|
||||
const staleServices = servicesBeforeScan.filter((s) => !foundPorts.has(s.port));
|
||||
const staleThresholdDays = Number(settingsRepo.listSettings().staleDeviceThresholdDays ?? 7);
|
||||
const staleThresholdMs = staleThresholdDays * 24 * 60 * 60 * 1000;
|
||||
const now = Date.now();
|
||||
const staleServices = servicesBeforeScan.filter((s) => {
|
||||
if (foundPorts.has(s.port)) return false;
|
||||
const lastSeen = s.updatedAt ? new Date(s.updatedAt).getTime() : 0;
|
||||
return now - lastSeen >= staleThresholdMs;
|
||||
});
|
||||
|
||||
// Vorschläge für abweichende Namen/Kategorien bereits bekannter Dienste
|
||||
// einsammeln (siehe upsertServiceFromScan) - werden NICHT automatisch
|
||||
|
||||
@@ -78,7 +78,8 @@ export interface DeviceScanResult {
|
||||
*/
|
||||
export async function scanDeviceServices(
|
||||
device: ScanTarget,
|
||||
extraPorts: number[] = TYPICAL_PORTS
|
||||
extraPorts: number[] = TYPICAL_PORTS,
|
||||
priorityPorts: number[] = []
|
||||
): Promise<DeviceScanResult> {
|
||||
const dnsResult = await resolveHostname(device.hostname);
|
||||
// Fällt auf die IP zurück, falls keine DNS-Variante auflösbar ist.
|
||||
@@ -90,7 +91,7 @@ export async function scanDeviceServices(
|
||||
// gemeldeten Namen ein.
|
||||
const suggestedHostname = dnsResult ? null : await reverseLookup(device.ip);
|
||||
|
||||
const candidatePorts = Array.from(new Set([80, 443, ...extraPorts]));
|
||||
const candidatePorts = Array.from(new Set([80, 443, ...extraPorts, ...priorityPorts]));
|
||||
|
||||
// Die offenen Ports werden PARALLEL geprüft, nicht nacheinander - bei
|
||||
// einem nicht erreichbaren/gefilterten Gerät (z. B. ein schlafender
|
||||
@@ -102,7 +103,21 @@ export async function scanDeviceServices(
|
||||
const openChecks = await Promise.all(
|
||||
candidatePorts.map(async (port) => ({ port, open: await isPortOpen(device.ip, port) }))
|
||||
);
|
||||
const openPorts = openChecks.filter((c) => c.open).map((c) => c.port);
|
||||
let openPorts = openChecks.filter((c) => c.open).map((c) => c.port);
|
||||
|
||||
// Bereits bekannte Dienst-Ports (priorityPorts, vom Aufrufer übergeben -
|
||||
// siehe scan.ts), die im ersten, stark parallelen Durchlauf NICHT als
|
||||
// offen erkannt wurden, bekommen einen zweiten, einzelnen Versuch mit
|
||||
// etwas mehr Zeit. Grund: ~20 gleichzeitige Verbindungsversuche können
|
||||
// schwächere Geräte (z. B. Echo-Lautsprecher, Smart-TVs) kurzzeitig
|
||||
// überfordern und dabei ausgerechnet den einen tatsächlich offenen Port
|
||||
// verpassen - das führte zu falschen "nicht mehr gefunden"-Meldungen,
|
||||
// obwohl sich am Gerät nichts geändert hatte.
|
||||
const missedPriorityPorts = priorityPorts.filter((p) => !openPorts.includes(p));
|
||||
for (const port of missedPriorityPorts) {
|
||||
const open = await isPortOpen(device.ip, port, 1500);
|
||||
if (open) openPorts.push(port);
|
||||
}
|
||||
|
||||
const found: DiscoveredService[] = [];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user