discovery: Dart client API for the discovery service.

MultiPart: 1/2

Change-Id: I786db3614cccad593503b3554367b6ec2bad871b
diff --git a/lib/client_impl.dart b/lib/client_impl.dart
new file mode 100644
index 0000000..458ddab
--- /dev/null
+++ b/lib/client_impl.dart
@@ -0,0 +1,85 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+part of discovery;
+
+typedef Future _StopFunction();
+
+class _Client implements Client {
+  final AdvertiserProxy _advertiserProxy = new AdvertiserProxy.unbound();
+  final ScannerProxy _scannerProxy = new ScannerProxy.unbound();
+
+  _Client(ConnectToServiceFunction cts, String url) {
+    cts(url, _advertiserProxy);
+    cts(url, _scannerProxy);
+  }
+
+  Future<Scanner> scan(String query) async {
+    StreamController<Service> onFound = new StreamController<Service>();
+    StreamController<String> onLost = new StreamController<String>();
+    ScanHandlerStub handlerStub = new ScanHandlerStub.unbound();
+    handlerStub.impl = new _ScanHandler(onFound, onLost);
+
+    ScannerScanResponseParams scanResponse =
+        await _scannerProxy.ptr.scan(query, handlerStub);
+    if (scanResponse.err != null) {
+      throw scanResponse.err;
+    }
+
+    Future stop() {
+      return _scannerProxy.ptr.stop(scanResponse.handle);
+    }
+    return new _Scanner(stop, onFound.stream, onLost.stream);
+  }
+
+  Future<Advertiser> advertise(Service service,
+      {List<String> visibility: null}) async {
+    AdvertiserAdvertiseResponseParams advertiseResponse =
+        await _advertiserProxy.ptr.advertise(service, visibility);
+
+    if (advertiseResponse.err != null) {
+      throw advertiseResponse.err;
+    }
+
+    Future stop() {
+      return _advertiserProxy.ptr.stop(advertiseResponse.handle);
+    }
+    return new _Advertiser(stop);
+  }
+}
+
+class _Scanner implements Scanner {
+  final Stream<Service> onFound;
+  final Stream<String> onLost;
+
+  final _StopFunction _stop;
+  _Scanner(this._stop, this.onFound, this.onLost) {}
+
+  Future stop() {
+    return _stop();
+  }
+}
+
+class _Advertiser implements Advertiser {
+  final _StopFunction _stop;
+  _Advertiser(this._stop) {}
+
+  Future stop() {
+    return _stop();
+  }
+}
+
+class _ScanHandler extends ScanHandler {
+  StreamController<Service> _onFound;
+  StreamController<String> _onLost;
+
+  _ScanHandler(this._onFound, this._onLost);
+
+  found(Service s) {
+    _onFound.add(s);
+  }
+
+  lost(String instanceId) {
+    _onLost.add(instanceId);
+  }
+}
diff --git a/lib/discovery.dart b/lib/discovery.dart
index ad37fb7..eb40093 100644
--- a/lib/discovery.dart
+++ b/lib/discovery.dart
@@ -1,8 +1,78 @@
 // Copyright 2015 The Vanadium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
-
 library discovery;
 
-// Export everything from discovery.mojom.
-export 'gen/dart-gen/mojom/lib/discovery/discovery.mojom.dart';
\ No newline at end of file
+import 'dart:async';
+
+import 'package:mojo/bindings.dart' as bindings;
+import 'gen/dart-gen/mojom/lib/discovery/discovery.mojom.dart';
+
+export 'gen/dart-gen/mojom/lib/discovery/discovery.mojom.dart' show Service;
+
+part 'client_impl.dart';
+
+typedef void ConnectToServiceFunction(String url, bindings.ProxyBase proxy);
+
+abstract class Client {
+  factory Client(ConnectToServiceFunction cts, String url) {
+    return new _Client(cts, url);
+  }
+
+  /// Scan scans services that match the query and returns a scanner handle that
+  /// includes streams of found and lost services.
+  /// Scanning will continue until [stop] is called on the [Scanner] handle.
+  ///
+  /// For example, the following code waits until finding the first service that matches the
+  /// query and then stops scanning.
+  ///
+  ///    Scanner scanner = client.scan('v.InterfaceName = "v.io/i" AND v.Attrs["a"] = "v"');
+  ///    Service firstFoundService = await scanner.onFound.first;
+  ///    scanner.stop();
+  ///
+  /// The query is a WHERE expression of a syncQL query against advertised services, where
+  /// keys are InstanceIds and values are Services.
+  ///
+  /// SyncQL tutorial at:
+  ///    https://github.com/vanadium/docs/blob/master/tutorials/syncql-tutorial.md
+  Future<Scanner> scan(String query);
+
+  /// Advertise advertises the [Service] to be discovered by [scan].
+  /// [visibility] is used to limit the principals that can see the advertisement.
+  /// An empty or null [visibility] means that there are no restrictions on visibility.
+  /// Advertising will continue until [stop] is called on the [Advertiser] handle.
+  ///
+  /// If service.InstanceId is not specified, a random unique identifier be
+  /// assigned to it. Any change to service will not be applied after advertising starts.
+  ///
+  /// It is an error to have simultaneously active advertisements for two identical
+  /// instances (service.InstanceId).
+  ///
+  /// For example, the following code advertises a service for 10 seconds.
+  ///
+  ///   Service service = new Service()
+  ///     ..interfaceName = 'v.io/i'
+  ///     ..attrs = {'a', 'v'};
+  ///   Advertiser advertiser = client.advertise(service);
+  ///   new Timer(const Duration(seconds: 10), () => advertiser.stop());
+  Future<Advertiser> advertise(Service service,
+      {List<String> visibility: null});
+}
+
+/// Handle to a scan call.
+abstract class Scanner {
+  /// A stream of [Service] objects as they are discovered by the scanner.
+  Stream<Service> get onFound;
+
+  /// A stream of instanceIds for services that are no longer advertised.
+  Stream<String> get onLost;
+
+  /// Stops scanning.
+  Future stop();
+}
+
+/// Handle to an advertise call.
+abstract class Advertiser {
+  /// Stops the advertisement.
+  Future stop();
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 5e48a2d..079085f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Discovery is a discovery system for developers that makes it easy to advertise apps and scan for them. It works over MDNS and BLE.
 homepage: https://github.com/vanadium/mojo.discovery
 name: v23discovery
-version: 0.0.9
+version: 0.0.10
 dependencies:
   mojo_sdk: 0.2.7
 dev_dependencies: