Skip to content

Commit

Permalink
feat: implement unicast DNS-SD
Browse files Browse the repository at this point in the history
  • Loading branch information
JKRhb committed Jan 27, 2024
1 parent 0badb0b commit 7de5d5c
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 8 deletions.
90 changes: 82 additions & 8 deletions lib/src/core/implementation/thing_discovery.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -222,7 +223,7 @@ class ThingDiscovery extends Stream<ThingDescription>
if (dnsName.endsWith("local")) {
yield* _discoverUsingMdnssd(dnsName);
} else {
throw UnimplementedError("Only mDNS-SD is currently supported!");
yield* _discoverUsingDnsSd(dnsName);
}
}

Expand All @@ -242,24 +243,97 @@ class ThingDiscovery extends Stream<ThingDescription>
);
}

Map<String, String> _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<Map<String, String>?> _lookupTxtRecords(
MDnsClient client,
String domainName,
) async {
final txtRecords = await client
.lookup<TxtResourceRecord>(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<ThingDescription> _discoverUsingDnsSd(String name) async* {
// TODO: Refactor
final ptrRecords = await DnsUtils.lookupRecord(name, RRecordType.PTR);
final defaultScheme = _isUdpDiscovery(name) ? "coap" : "http";
final discoveredUris = <Uri>{};
const defaultType = "Thing";

for (final ptrRecord in ptrRecords ?? <RRecord>[]) {
final srvRecords =
await DnsUtils.lookupRecord(ptrRecord.name, RRecordType.SRV);

for (final srvRecord in srvRecords ?? <RRecord>[]) {
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<ThingDescription> _discoverUsingMdnssd(String name) async* {
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 7de5d5c

Please sign in to comment.