6
6
7
7
import "dart:async" ;
8
8
9
+ import "package:basic_utils/basic_utils.dart" ;
9
10
import "package:coap/coap.dart" ;
10
11
import "package:collection/collection.dart" ;
11
12
import "package:multicast_dns/multicast_dns.dart" ;
@@ -219,7 +220,7 @@ class ThingDiscovery extends Stream<ThingDescription>
219
220
if (dnsName.endsWith ("local" )) {
220
221
yield * _discoverUsingMdnssd (dnsName);
221
222
} else {
222
- throw UnimplementedError ( "Only mDNS-SD is currently supported!" );
223
+ yield * _discoverUsingDnsSd (dnsName );
223
224
}
224
225
}
225
226
@@ -239,24 +240,97 @@ class ThingDiscovery extends Stream<ThingDescription>
239
240
);
240
241
}
241
242
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
+
242
253
Future <Map <String , String >?> _lookupTxtRecords (
243
254
MDnsClient client,
244
255
String domainName,
245
256
) async {
246
257
final txtRecords = await client
247
258
.lookup <TxtResourceRecord >(ResourceRecordQuery .text (domainName))
248
259
.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 ]));
254
260
255
- if (recordsList == null ) {
261
+ final firstTxtRecord = txtRecords.firstOrNull? .text;
262
+
263
+ if (firstTxtRecord == null ) {
256
264
return null ;
257
265
}
258
266
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
+ }
260
334
}
261
335
262
336
Stream <ThingDescription > _discoverUsingMdnssd (String name) async * {
0 commit comments