66
77import 'dart:async' ;
88
9+ import 'package:basic_utils/basic_utils.dart' ;
910import 'package:coap/coap.dart' ;
1011import 'package:collection/collection.dart' ;
1112import 'package:multicast_dns/multicast_dns.dart' ;
@@ -231,7 +232,7 @@ class ThingDiscovery extends Stream<ThingDescription>
231232 if (dnsName.endsWith ('local' )) {
232233 yield * _discoverUsingMdnssd (dnsName);
233234 } else {
234- throw UnimplementedError ( 'Only mDNS-SD is currently supported!' );
235+ yield * _discoverUsingDnsSd (dnsName );
235236 }
236237 }
237238
@@ -251,24 +252,97 @@ class ThingDiscovery extends Stream<ThingDescription>
251252 );
252253 }
253254
255+ Map <String , String > _parseTxtRecords (String txtRecords) {
256+ final recordsList = txtRecords
257+ .split ('\n ' )
258+ .map ((property) => property.split ('=' ))
259+ .where ((list) => list.length > 1 )
260+ .map ((list) => MapEntry (list[0 ], list[1 ]));
261+
262+ return Map .fromEntries (recordsList);
263+ }
264+
254265 Future <Map <String , String >?> _lookupTxtRecords (
255266 MDnsClient client,
256267 String domainName,
257268 ) async {
258269 final txtRecords = await client
259270 .lookup <TxtResourceRecord >(ResourceRecordQuery .text (domainName))
260271 .toList ();
261- final recordsList = txtRecords.firstOrNull? .text
262- .split ('\n ' )
263- .map ((property) => property.split ('=' ))
264- .where ((list) => list.length > 1 )
265- .map ((list) => MapEntry (list[0 ], list[1 ]));
266272
267- if (recordsList == null ) {
273+ final firstTxtRecord = txtRecords.firstOrNull? .text;
274+
275+ if (firstTxtRecord == null ) {
268276 return null ;
269277 }
270278
271- return Map .fromEntries (recordsList);
279+ return _parseTxtRecords (firstTxtRecord);
280+ }
281+
282+ Stream <ThingDescription > _discoverUsingDnsSd (String name) async * {
283+ // TODO: Refactor
284+ final ptrRecords = await DnsUtils .lookupRecord (name, RRecordType .PTR );
285+ final defaultScheme = _isUdpDiscovery (name) ? 'coap' : 'http' ;
286+ final discoveredUris = < Uri > {};
287+ const defaultType = 'Thing' ;
288+
289+ for (final ptrRecord in ptrRecords ?? < RRecord > []) {
290+ final srvRecords =
291+ await DnsUtils .lookupRecord (ptrRecord.name, RRecordType .SRV );
292+
293+ for (final srvRecord in srvRecords ?? < RRecord > []) {
294+ final srvRecordEntries = srvRecord.data.split (' ' );
295+
296+ final validSrvRecord = srvRecordEntries.length == 7 ;
297+
298+ if (! validSrvRecord) {
299+ continue ;
300+ }
301+
302+ final target = srvRecordEntries.last;
303+ final port =
304+ int .tryParse (srvRecordEntries[srvRecordEntries.length - 2 ]);
305+
306+ if (port == null ) {
307+ continue ;
308+ }
309+
310+ final txtRecords =
311+ await DnsUtils .lookupRecord (srvRecord.name, RRecordType .TXT ) ?? [];
312+
313+ final txtRecord = txtRecords.firstOrNull;
314+
315+ if (txtRecord == null ) {
316+ continue ;
317+ }
318+
319+ final parsedTxtRecord = _parseTxtRecords (txtRecord.data);
320+
321+ final uri = Uri (
322+ host: target,
323+ port: port,
324+ path: parsedTxtRecord['td' ],
325+ scheme: parsedTxtRecord['scheme' ] ?? defaultScheme,
326+ );
327+
328+ final duplicate = discoveredUris.add (uri);
329+
330+ if (duplicate) {
331+ continue ;
332+ }
333+
334+ final type = parsedTxtRecord['type' ] ?? defaultType;
335+
336+ print (parsedTxtRecord);
337+ switch (type) {
338+ case 'Thing' :
339+ yield * _discoverDirectly (uri);
340+ case 'Directory' :
341+ // TODO(JKRhb): Implement directory discovery.
342+ break ;
343+ }
344+ }
345+ }
272346 }
273347
274348 Stream <ThingDescription > _discoverUsingMdnssd (String name) async * {
0 commit comments