diff --git a/src/modules/discovery/scanners/mdns.scanner.ts b/src/modules/discovery/scanners/mdns.scanner.ts index 97348be..ccf9e19 100644 --- a/src/modules/discovery/scanners/mdns.scanner.ts +++ b/src/modules/discovery/scanners/mdns.scanner.ts @@ -1,13 +1,36 @@ -import { Bonjour } from 'bonjour-service'; +import { Bonjour, type Service } from 'bonjour-service'; import { env } from '@/config/env'; import type { DiscoveryResult, DiscoveryTarget, Scanner } from '../types'; /** - * Découverte via mDNS / DNS-SD (_services._dns-sd._udp.local). - * Écoute pendant `timeout` ms et agrège les annonces reçues. + * Découverte via mDNS / DNS-SD. + * `bonjour-service` exige un `type` par browser : on en lance un par type + * courant en homelab et on agrège les annonces reçues pendant `timeout` ms. */ const DEFAULT_TIMEOUT_MS = 4000; +// Types mDNS les plus fréquents en homelab (sans le préfixe `_` ni le suffixe `._tcp/._udp`) +const COMMON_SERVICE_TYPES: Array<{ type: string; protocol: 'tcp' | 'udp' }> = [ + { type: 'http', protocol: 'tcp' }, + { type: 'https', protocol: 'tcp' }, + { type: 'ssh', protocol: 'tcp' }, + { type: 'sftp-ssh', protocol: 'tcp' }, + { type: 'smb', protocol: 'tcp' }, + { type: 'nfs', protocol: 'tcp' }, + { type: 'afpovertcp', protocol: 'tcp' }, + { type: 'workstation', protocol: 'tcp' }, + { type: 'device-info', protocol: 'tcp' }, + { type: 'printer', protocol: 'tcp' }, + { type: 'ipp', protocol: 'tcp' }, + { type: 'ipps', protocol: 'tcp' }, + { type: 'airplay', protocol: 'tcp' }, + { type: 'raop', protocol: 'tcp' }, + { type: 'googlecast', protocol: 'tcp' }, + { type: 'homekit', protocol: 'tcp' }, + { type: 'hap', protocol: 'tcp' }, + { type: 'spotify-connect', protocol: 'tcp' }, +]; + export const mdnsScanner: Scanner = { kind: 'mdns', label: 'mDNS / Bonjour', @@ -17,11 +40,14 @@ export const mdnsScanner: Scanner = { const bonjour = new Bonjour(); const byIp = new Map(); - const browser = bonjour.find({}); - browser.on('up', (svc) => { + const ingest = (svc: Service) => { const ips = (svc.addresses ?? []).filter((a) => a && !a.includes(':')); // IPv4 for (const ip of ips) { - const existing = byIp.get(ip) ?? { ipAddress: ip, hostname: svc.host, services: [] }; + const existing = byIp.get(ip) ?? { + ipAddress: ip, + hostname: svc.host, + services: [], + }; existing.services!.push({ name: svc.name, type: `_${svc.type}._${svc.protocol}.local`, @@ -29,10 +55,16 @@ export const mdnsScanner: Scanner = { }); byIp.set(ip, existing); } + }; + + const browsers = COMMON_SERVICE_TYPES.map(({ type, protocol }) => { + const browser = bonjour.find({ type, protocol }); + browser.on('up', ingest); + return browser; }); await new Promise((r) => setTimeout(r, DEFAULT_TIMEOUT_MS)); - browser.stop(); + for (const b of browsers) b.stop(); bonjour.destroy(); return [...byIp.values()];