OLD | NEW |
1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 library fletchc.driver.developer; | 5 library fletchc.driver.developer; |
6 | 6 |
7 import 'dart:async' show | 7 import 'dart:async' show |
8 Future, | 8 Future, |
9 Timer; | 9 Timer; |
10 | 10 |
(...skipping 14 matching lines...) Expand all Loading... |
25 | 25 |
26 import 'package:fletch_agent/agent_connection.dart' show | 26 import 'package:fletch_agent/agent_connection.dart' show |
27 AgentConnection, | 27 AgentConnection, |
28 AgentException, | 28 AgentException, |
29 VmData; | 29 VmData; |
30 | 30 |
31 import 'package:fletch_agent/messages.dart' show | 31 import 'package:fletch_agent/messages.dart' show |
32 AGENT_DEFAULT_PORT, | 32 AGENT_DEFAULT_PORT, |
33 MessageDecodeException; | 33 MessageDecodeException; |
34 | 34 |
| 35 import 'package:mdns/mdns.dart' show |
| 36 MDnsClient, |
| 37 ResourceRecord, |
| 38 RRType; |
| 39 |
35 import '../../commands.dart' show | 40 import '../../commands.dart' show |
36 CommandCode, | 41 CommandCode, |
37 HandShakeResult, | 42 HandShakeResult, |
38 ProcessBacktrace, | 43 ProcessBacktrace, |
39 ProcessBacktraceRequest, | 44 ProcessBacktraceRequest, |
40 ProcessRun, | 45 ProcessRun, |
41 ProcessSpawnForMain, | 46 ProcessSpawnForMain, |
42 SessionEnd, | 47 SessionEnd, |
43 WriteSnapshotResult; | 48 WriteSnapshotResult; |
44 | 49 |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 settings = settings.copyWith(packages: packagesUri, deviceAddress: address); | 332 settings = settings.copyWith(packages: packagesUri, deviceAddress: address); |
328 print("Created settings file '$uri'"); | 333 print("Created settings file '$uri'"); |
329 await new File.fromUri(uri).writeAsString( | 334 await new File.fromUri(uri).writeAsString( |
330 "${const JsonEncoder.withIndent(' ').convert(settings)}\n"); | 335 "${const JsonEncoder.withIndent(' ').convert(settings)}\n"); |
331 return settings; | 336 return settings; |
332 } | 337 } |
333 | 338 |
334 Future<Address> readAddressFromUser( | 339 Future<Address> readAddressFromUser( |
335 CommandSender commandSender, | 340 CommandSender commandSender, |
336 StreamIterator<Command> commandIterator) async { | 341 StreamIterator<Command> commandIterator) async { |
| 342 String message = |
| 343 "Please enter IP address of remote device (press enter for discovery): "; |
337 commandSender.sendEventLoopStarted(); | 344 commandSender.sendEventLoopStarted(); |
338 commandSender.sendStdout("Please enter IP address of remote device: "); | 345 commandSender.sendStdout(message); |
339 while (await commandIterator.moveNext()) { | 346 while (await commandIterator.moveNext()) { |
340 Command command = commandIterator.current; | 347 Command command = commandIterator.current; |
341 switch (command.code) { | 348 switch (command.code) { |
342 case DriverCommand.Stdin: | 349 case DriverCommand.Stdin: |
343 if (command.data.length == 0) { | 350 if (command.data.length == 0) { |
344 // TODO(ahe): It may be safe to return null here, but we need to | 351 // TODO(ahe): It may be safe to return null here, but we need to |
345 // check how this interacts with the debugger's InputHandler. | 352 // check how this interacts with the debugger's InputHandler. |
346 throwInternalError("Unexpected end of input"); | 353 throwInternalError("Unexpected end of input"); |
347 } | 354 } |
348 // TODO(ahe): This assumes that the user's input arrives as one | 355 // TODO(ahe): This assumes that the user's input arrives as one |
349 // message. It is relatively safe to assume this for a normal terminal | 356 // message. It is relatively safe to assume this for a normal terminal |
350 // session because we use canonical input processing (Unix line | 357 // session because we use canonical input processing (Unix line |
351 // buffering), but it doesn't work in general. So we should fix that. | 358 // buffering), but it doesn't work in general. So we should fix that. |
352 String line = UTF8.decode(command.data).trim(); | 359 String line = UTF8.decode(command.data).trim(); |
353 return parseAddress(line, defaultPort: AGENT_DEFAULT_PORT); | 360 if (line.isEmpty) { |
| 361 await discoverDevices(); |
| 362 commandSender.sendStdout(message); |
| 363 } else { |
| 364 return parseAddress(line, defaultPort: AGENT_DEFAULT_PORT); |
| 365 } |
| 366 break; |
354 | 367 |
355 case DriverCommand.Signal: | 368 case DriverCommand.Signal: |
356 // Send an empty line as the user didn't hit enter. | 369 // Send an empty line as the user didn't hit enter. |
357 commandSender.sendStdout("\n"); | 370 commandSender.sendStdout("\n"); |
358 // Assume user aborted data entry. | 371 // Assume user aborted data entry. |
359 return null; | 372 return null; |
360 | 373 |
361 default: | 374 default: |
362 throwInternalError("Unexpected ${command.code}"); | 375 throwInternalError("Unexpected ${command.code}"); |
363 return null; | 376 return null; |
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
743 | 756 |
744 Future<int> invokeCombinedTasks( | 757 Future<int> invokeCombinedTasks( |
745 CommandSender commandSender, | 758 CommandSender commandSender, |
746 StreamIterator<Command> commandIterator, | 759 StreamIterator<Command> commandIterator, |
747 SharedTask task1, | 760 SharedTask task1, |
748 SharedTask task2) async { | 761 SharedTask task2) async { |
749 await task1(commandSender, commandIterator); | 762 await task1(commandSender, commandIterator); |
750 return task2(commandSender, commandIterator); | 763 return task2(commandSender, commandIterator); |
751 } | 764 } |
752 | 765 |
| 766 Future discoverDevices() async { |
| 767 print('Looking for Fletch capable devices...'); |
| 768 MDnsClient client = new MDnsClient(); |
| 769 await client.start(); |
| 770 String name = '_fletch_agent._tcp.local'; |
| 771 await for (ResourceRecord ptr in client.lookup(RRType.PTR, name)) { |
| 772 String domain = ptr.domainName; |
| 773 await for (ResourceRecord srv in client.lookup(RRType.SRV, domain)) { |
| 774 String target = srv.target; |
| 775 await for (ResourceRecord a in client.lookup(RRType.A, target)) { |
| 776 InternetAddress address = a.address; |
| 777 if (!address.isLinkLocal) { |
| 778 print('Found device $target on address ${address.address}.'); |
| 779 } |
| 780 } |
| 781 } |
| 782 } |
| 783 client.stop(); |
| 784 } |
| 785 |
753 Address parseAddress(String address, {int defaultPort: 0}) { | 786 Address parseAddress(String address, {int defaultPort: 0}) { |
754 String host; | 787 String host; |
755 int port; | 788 int port; |
756 List<String> parts = address.split(":"); | 789 List<String> parts = address.split(":"); |
757 if (parts.length == 1) { | 790 if (parts.length == 1) { |
758 host = InternetAddress.LOOPBACK_IP_V4.address; | 791 host = InternetAddress.LOOPBACK_IP_V4.address; |
759 port = int.parse( | 792 port = int.parse( |
760 parts[0], | 793 parts[0], |
761 onError: (String source) { | 794 onError: (String source) { |
762 host = source; | 795 host = source; |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
967 "packages": packages == null ? null : "$packages", | 1000 "packages": packages == null ? null : "$packages", |
968 "options": options, | 1001 "options": options, |
969 "constants": constants, | 1002 "constants": constants, |
970 "device_address": deviceAddress, | 1003 "device_address": deviceAddress, |
971 "device_type": (deviceType == null) | 1004 "device_type": (deviceType == null) |
972 ? null | 1005 ? null |
973 : unParseDeviceType(deviceType), | 1006 : unParseDeviceType(deviceType), |
974 }; | 1007 }; |
975 } | 1008 } |
976 } | 1009 } |
OLD | NEW |