diff --git a/lib/src/core/implementation/thing_discovery.dart b/lib/src/core/implementation/thing_discovery.dart index 662ef941..ebe1e206 100644 --- a/lib/src/core/implementation/thing_discovery.dart +++ b/lib/src/core/implementation/thing_discovery.dart @@ -6,6 +6,7 @@ import "dart:async"; +import "package:basic_utils/basic_utils.dart"; import "package:coap/coap.dart"; import "package:collection/collection.dart"; import "package:multicast_dns/multicast_dns.dart"; @@ -222,7 +223,7 @@ class ThingDiscovery extends Stream if (dnsName.endsWith("local")) { yield* _discoverUsingMdnssd(dnsName); } else { - throw UnimplementedError("Only mDNS-SD is currently supported!"); + yield* _discoverUsingDnsSd(dnsName); } } @@ -242,6 +243,16 @@ class ThingDiscovery extends Stream ); } + Map _parseTxtRecords(String txtRecords) { + final recordsList = txtRecords + .split("\n") + .map((property) => property.split("=")) + .where((list) => list.length > 1) + .map((list) => MapEntry(list[0], list[1])); + + return Map.fromEntries(recordsList); + } + Future?> _lookupTxtRecords( MDnsClient client, String domainName, @@ -249,17 +260,80 @@ class ThingDiscovery extends Stream final txtRecords = await client .lookup(ResourceRecordQuery.text(domainName)) .toList(); - final recordsList = txtRecords.firstOrNull?.text - .split("\n") - .map((property) => property.split("=")) - .where((list) => list.length > 1) - .map((list) => MapEntry(list[0], list[1])); - if (recordsList == null) { + final firstTxtRecord = txtRecords.firstOrNull?.text; + + if (firstTxtRecord == null) { return null; } - return Map.fromEntries(recordsList); + return _parseTxtRecords(firstTxtRecord); + } + + Stream _discoverUsingDnsSd(String name) async* { + // TODO: Refactor + final ptrRecords = await DnsUtils.lookupRecord(name, RRecordType.PTR); + final defaultScheme = _isUdpDiscovery(name) ? "coap" : "http"; + final discoveredUris = {}; + const defaultType = "Thing"; + + for (final ptrRecord in ptrRecords ?? []) { + final srvRecords = + await DnsUtils.lookupRecord(ptrRecord.name, RRecordType.SRV); + + for (final srvRecord in srvRecords ?? []) { + final srvRecordEntries = srvRecord.data.split(" "); + + final validSrvRecord = srvRecordEntries.length == 7; + + if (!validSrvRecord) { + continue; + } + + final target = srvRecordEntries.last; + final port = + int.tryParse(srvRecordEntries[srvRecordEntries.length - 2]); + + if (port == null) { + continue; + } + + final txtRecords = + await DnsUtils.lookupRecord(srvRecord.name, RRecordType.TXT) ?? []; + + final txtRecord = txtRecords.firstOrNull; + + if (txtRecord == null) { + continue; + } + + final parsedTxtRecord = _parseTxtRecords(txtRecord.data); + + final uri = Uri( + host: target, + port: port, + path: parsedTxtRecord["td"], + scheme: parsedTxtRecord["scheme"] ?? defaultScheme, + ); + + final duplicate = discoveredUris.add(uri); + + if (duplicate) { + continue; + } + + final type = parsedTxtRecord["type"] ?? defaultType; + + print(parsedTxtRecord); + switch (type) { + case "Thing": + yield* _discoverDirectly(uri); + case "Directory": + // TODO(JKRhb): Implement directory discovery. + break; + } + } + } } Stream _discoverUsingMdnssd(String name) async* { diff --git a/pubspec.yaml b/pubspec.yaml index fb8a0097..4d81cbb4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,6 +15,7 @@ dev_dependencies: test: ^1.24.3 dependencies: + basic_utils: ^5.6.1 cbor: ^6.1.0 coap: ^9.0.0 collection: ^1.17.2