Skip to content

Commit f4a8726

Browse files
committed
feat: implement unicast DNS-SD
1 parent 3a2d79a commit f4a8726

File tree

2 files changed

+83
-8
lines changed

2 files changed

+83
-8
lines changed

lib/src/core/implementation/thing_discovery.dart

+82-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import "dart:async";
88

9+
import "package:basic_utils/basic_utils.dart";
910
import "package:coap/coap.dart";
1011
import "package:collection/collection.dart";
1112
import "package:multicast_dns/multicast_dns.dart";
@@ -219,7 +220,7 @@ class ThingDiscovery extends Stream<ThingDescription>
219220
if (dnsName.endsWith("local")) {
220221
yield* _discoverUsingMdnssd(dnsName);
221222
} else {
222-
throw UnimplementedError("Only mDNS-SD is currently supported!");
223+
yield* _discoverUsingDnsSd(dnsName);
223224
}
224225
}
225226

@@ -239,24 +240,97 @@ class ThingDiscovery extends Stream<ThingDescription>
239240
);
240241
}
241242

243+
Map<String, String> _parseTxtRecords(String txtRecords) {
244+
final recordsList = txtRecords
245+
.split("\n")
246+
.map((property) => property.split("="))
247+
.where((list) => list.length > 1)
248+
.map((list) => MapEntry(list[0], list[1]));
249+
250+
return Map.fromEntries(recordsList);
251+
}
252+
242253
Future<Map<String, String>?> _lookupTxtRecords(
243254
MDnsClient client,
244255
String domainName,
245256
) async {
246257
final txtRecords = await client
247258
.lookup<TxtResourceRecord>(ResourceRecordQuery.text(domainName))
248259
.toList();
249-
final recordsList = txtRecords.firstOrNull?.text
250-
.split("\n")
251-
.map((property) => property.split("="))
252-
.where((list) => list.length > 1)
253-
.map((list) => MapEntry(list[0], list[1]));
254260

255-
if (recordsList == null) {
261+
final firstTxtRecord = txtRecords.firstOrNull?.text;
262+
263+
if (firstTxtRecord == null) {
256264
return null;
257265
}
258266

259-
return Map.fromEntries(recordsList);
267+
return _parseTxtRecords(firstTxtRecord);
268+
}
269+
270+
Stream<ThingDescription> _discoverUsingDnsSd(String name) async* {
271+
// TODO: Refactor
272+
final ptrRecords = await DnsUtils.lookupRecord(name, RRecordType.PTR);
273+
final defaultScheme = _isUdpDiscovery(name) ? "coap" : "http";
274+
final discoveredUris = <Uri>{};
275+
const defaultType = "Thing";
276+
277+
for (final ptrRecord in ptrRecords ?? <RRecord>[]) {
278+
final srvRecords =
279+
await DnsUtils.lookupRecord(ptrRecord.name, RRecordType.SRV);
280+
281+
for (final srvRecord in srvRecords ?? <RRecord>[]) {
282+
final srvRecordEntries = srvRecord.data.split(" ");
283+
284+
final validSrvRecord = srvRecordEntries.length == 7;
285+
286+
if (!validSrvRecord) {
287+
continue;
288+
}
289+
290+
final target = srvRecordEntries.last;
291+
final port =
292+
int.tryParse(srvRecordEntries[srvRecordEntries.length - 2]);
293+
294+
if (port == null) {
295+
continue;
296+
}
297+
298+
final txtRecords =
299+
await DnsUtils.lookupRecord(srvRecord.name, RRecordType.TXT) ?? [];
300+
301+
final txtRecord = txtRecords.firstOrNull;
302+
303+
if (txtRecord == null) {
304+
continue;
305+
}
306+
307+
final parsedTxtRecord = _parseTxtRecords(txtRecord.data);
308+
309+
final uri = Uri(
310+
host: target,
311+
port: port,
312+
path: parsedTxtRecord["td"],
313+
scheme: parsedTxtRecord["scheme"] ?? defaultScheme,
314+
);
315+
316+
final duplicate = discoveredUris.add(uri);
317+
318+
if (duplicate) {
319+
continue;
320+
}
321+
322+
final type = parsedTxtRecord["type"] ?? defaultType;
323+
324+
print(parsedTxtRecord);
325+
switch (type) {
326+
case "Thing":
327+
yield* _discoverDirectly(uri);
328+
case "Directory":
329+
// TODO(JKRhb): Implement directory discovery.
330+
break;
331+
}
332+
}
333+
}
260334
}
261335

262336
Stream<ThingDescription> _discoverUsingMdnssd(String name) async* {

pubspec.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ dev_dependencies:
1515
test: ^1.24.3
1616

1717
dependencies:
18+
basic_utils: ^5.6.1
1819
cbor: ^6.1.0
1920
coap: ^9.0.0
2021
collection: ^1.17.2

0 commit comments

Comments
 (0)