round30: alle drei Scanner als Hintergrund-Job, Dienst-Duplikate strukturell verhindert (Migration+Constraint+Geraete-Sperre), zweiter Erkennungsversuch bei leerem Ersttreffer

This commit is contained in:
2026-07-24 15:14:00 +02:00
parent 2106c17301
commit 87fed21348
7 changed files with 308 additions and 140 deletions

View File

@@ -148,6 +148,34 @@ export async function scanDeviceServices(
});
const titleIsJunk = isLikelyJunkTitle(probe.title);
// Verbindung stand, aber weder Titel noch Software erkennbar (z. B. eine
// SPA, die beim allerersten Laden noch keinen Inhalt geliefert hat, oder
// ein Dienst, der kurz gebraucht hat um hochzufahren) - ein zweiter
// Versuch, bevor Sichtbarkeit/Favicon/Name dauerhaft auf Basis eines
// einzelnen, möglicherweise unvollständigen ersten Aufrufs entschieden
// werden.
let finalProbe = probe;
let finalSoftware = software;
let finalTitleIsJunk = titleIsJunk;
if (probe.ok && titleIsJunk && !software) {
const retryProbe = await probeHttp(baseUrl);
const retrySoftware = detectSoftware({
server: retryProbe.server,
body: retryProbe.bodySnippet,
title: retryProbe.title,
port,
});
const retryTitleIsJunk = isLikelyJunkTitle(retryProbe.title);
if (retrySoftware || !retryTitleIsJunk) {
finalProbe = retryProbe;
finalSoftware = retrySoftware;
finalTitleIsJunk = retryTitleIsJunk;
}
}
probe = finalProbe;
const softwareResolved = finalSoftware;
const titleIsJunkResolved = finalTitleIsJunk;
// Kein brauchbarer Titel gefunden (z. B. weil eine SPA ihren echten Titel
// erst per JavaScript setzt, das der Scanner nicht ausführt) - dann lieber
// den bereits bekannten Gerätenamen ("plug-shelly-heiz-links" ->
@@ -160,7 +188,7 @@ export async function scanDeviceServices(
// Nur sichtbar, wenn Software erkannt wurde oder eine erfolgreiche Antwort
// (Status < 400) mit einem brauchbaren Titel vorliegt. Fehlerseiten und
// Ladebildschirme landen als ausgeblendeter Dienst im Adminbereich.
const visible = !!software || (probe.ok && !titleIsJunk);
const visible = !!softwareResolved || (probe.ok && !titleIsJunkResolved);
found.push({
hostname: address,
@@ -168,10 +196,11 @@ export async function scanDeviceServices(
https: isHttps,
port,
favicon: probe.faviconUrl,
description: software ? `${software.name} (automatisch erkannt)` : probe.title,
suggestedDisplayName: software?.name ?? (titleIsJunk ? fallbackName : probe.title ?? fallbackName),
category: software?.category,
icon: software?.icon,
description: softwareResolved ? `${softwareResolved.name} (automatisch erkannt)` : probe.title,
suggestedDisplayName:
softwareResolved?.name ?? (titleIsJunkResolved ? fallbackName : probe.title ?? fallbackName),
category: softwareResolved?.category,
icon: softwareResolved?.icon,
visible,
});
}