generated from Dicken/dickendock
Commit 5: Scanner-Engine (DNS, Portscan, Titel/Favicon, Softwareerkennung, FritzBox TR-064)
This commit is contained in:
@@ -86,9 +86,8 @@ export function createService(input: ServiceCreateInput): Service {
|
||||
|
||||
/**
|
||||
* Aktualisiert einen Dienst anhand von Benutzereingaben (z. B. über die Admin-UI).
|
||||
* Ein separater Pfad für automatische Scan-Ergebnisse folgt in einem späteren
|
||||
* Commit (siehe docs/ROADMAP.md, Commit 5 – Scanner): Scans dürfen displayName,
|
||||
* category, favorite, order, alias und icon niemals überschreiben.
|
||||
* Für automatische Scan-Ergebnisse siehe upsertServiceFromScan() unten – die
|
||||
* NIEMALS displayName, category, favorite, order, alias oder icon überschreibt.
|
||||
*/
|
||||
export function updateService(id: string, input: ServiceUpdateInput): Service | null {
|
||||
const existing = getService(id);
|
||||
@@ -120,3 +119,78 @@ export function deleteService(id: string): boolean {
|
||||
const result = db.delete(services).where(eq(services.id, id)).run();
|
||||
return result.changes > 0;
|
||||
}
|
||||
|
||||
export interface ServiceScanInput {
|
||||
deviceId: string;
|
||||
hostname: string;
|
||||
url: string;
|
||||
https: boolean;
|
||||
port: number;
|
||||
favicon?: string | null;
|
||||
description?: string | null;
|
||||
/** Nur relevant, wenn dabei ein NEUER Dienst angelegt wird. */
|
||||
suggestedDisplayName: string;
|
||||
/** Nur relevant, wenn dabei ein NEUER Dienst angelegt wird. */
|
||||
suggestedCategory?: string | null;
|
||||
}
|
||||
|
||||
export interface ScanUpsertResult {
|
||||
service: Service;
|
||||
created: boolean;
|
||||
}
|
||||
|
||||
function findByDeviceAndPort(deviceId: string, port: number): Service | null {
|
||||
return listServicesByDevice(deviceId).find((s) => s.port === port) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Legt einen per Scan gefundenen Dienst an oder aktualisiert die scan-eigenen
|
||||
* Felder eines bereits bekannten Dienstes (abgeglichen über deviceId + port).
|
||||
*
|
||||
* displayName, category, favorite, order, alias und icon werden bei einem
|
||||
* bestehenden Dienst NIEMALS verändert – nur beim erstmaligen Anlegen dienen
|
||||
* suggestedDisplayName/suggestedCategory als sinnvoller Startwert.
|
||||
*/
|
||||
export function upsertServiceFromScan(input: ServiceScanInput): ScanUpsertResult {
|
||||
const existing = findByDeviceAndPort(input.deviceId, input.port);
|
||||
const timestamp = nowIso();
|
||||
|
||||
if (existing) {
|
||||
db.update(services)
|
||||
.set({
|
||||
hostname: input.hostname,
|
||||
url: input.url,
|
||||
https: input.https,
|
||||
favicon: input.favicon ?? existing.favicon,
|
||||
description: input.description ?? existing.description,
|
||||
updatedAt: timestamp,
|
||||
})
|
||||
.where(eq(services.id, existing.id))
|
||||
.run();
|
||||
return { service: getService(existing.id)!, created: false };
|
||||
}
|
||||
|
||||
const id = randomUUID();
|
||||
db.insert(services)
|
||||
.values({
|
||||
id,
|
||||
deviceId: input.deviceId,
|
||||
displayName: input.suggestedDisplayName,
|
||||
category: input.suggestedCategory ?? null,
|
||||
favorite: false,
|
||||
order: 0,
|
||||
alias: "[]",
|
||||
icon: null,
|
||||
hostname: input.hostname,
|
||||
url: input.url,
|
||||
https: input.https,
|
||||
port: input.port,
|
||||
favicon: input.favicon ?? null,
|
||||
description: input.description ?? null,
|
||||
createdAt: timestamp,
|
||||
updatedAt: timestamp,
|
||||
})
|
||||
.run();
|
||||
|
||||
return { service: getService(id)!, created: true };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user