Replace Go echo client with Dart echo client.

Now we have a Dart echo client talking to a Go echo server, which
parallels the way our syncbase client and server will work.

The next step is to set up a test harness that asserts that the client
can talk to the server.

Change-Id: Iaa6887e78c754fd1aea30dd89843bbfa0bd10ad3
diff --git a/.gitignore b/.gitignore
index 8d94b88..e648e97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,7 @@
+# Build artifacts
 /gen
+
+# Dart dependencies
+/dart/.packages
+/dart/pubspec.lock
+/dart/**/packages
diff --git a/Makefile b/Makefile
index 438fc5f..082092b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
 PWD=$(shell pwd)
+DART_FILES = $(shell find $(PWD)/dart -name *.dart ! -name *.part.dart)
 V23_GOPATH=$(shell echo `v23 run env | grep GOPATH | cut -d\= -f2`)
 
 ifndef MOJO_DIR
@@ -6,10 +7,10 @@
 endif
 
 ifdef ANDROID
-	# TODO(nlacasse): Once mojo issue #349 is fixed, start using the
-	# --map-origin flag and refernce .mojo files by an http:// url and not
-	# file:// url, since the latter will never work on android.
-	$(error Android compilation is currently not supported.  Blocked by https://github.com/domokit/mojo/issues/349)
+	# TODO(nlacasse): Serve mojo resources over HTTP so they are accessible to
+	# Android.  Currently everything is served off the local filesystem, which
+	# will not work on Android.  Until then, Android support is disabled.
+	$(error Android is currently not supported.)
 
 	# Configure compiler and linker for Android.
 	GO_BIN=$(MOJO_DIR)/src/third_party/go/tool/android_arm/bin/go
@@ -58,7 +59,7 @@
 	$(MOJOM_BIN) $1 -d . -o $2 -g $3
 endef
 
-all: gen
+all: run-echo-app
 
 # Builds the shared library that Mojo services must be linked with.
 $(MOJO_SHARED_LIB):
@@ -68,10 +69,12 @@
 	mkdir -p $(dir $@)
 	ar rcs $@ $(MOJO_BUILD_DIR)/obj/mojo/public/platform/native/system.system_thunks.o
 
+.PHONY: gen-mojom
 # TODO(nlacasse): The echo_client and echo_server are currently used to test
 # compilation and mojom binding generation.  We should remove them once they
 # are no longer needed.
-gen: gen/mojo gen/dart-pkg/mojom/lib/mojo/syncbase.mojom.dart gen/go/src/mojom/syncbase/syncbase.mojom.go gen/dart-pkg/mojom/lib/mojo/echo.mojom.dart gen/go/src/mojom/echo/echo.mojom.go
+gen-mojom: gen/dart-pkg/mojom/lib/mojo/echo.mojom.dart gen/go/src/mojom/echo/echo.mojom.go
+gen-mojom: gen/dart-pkg/mojom/lib/mojo/syncbase.mojom.dart gen/go/src/mojom/syncbase/syncbase.mojom.go
 
 gen/dart-pkg/mojom/lib/mojo/echo.mojom.dart: mojom/echo.mojom
 	$(call MOJOM_GEN,$<,gen,dart)
@@ -87,18 +90,33 @@
 	$(call MOJOM_GEN,$<,gen,go)
 	gofmt -w $@
 
-gen/mojo: gen/mojo/echo_client.mojo gen/mojo/echo_server.mojo
-
-gen/mojo/echo_client.mojo: go/src/echo_client.go $(MOJO_SHARED_LIB)
-	$(call MOGO_BUILD,$<,$@)
-
 gen/mojo/echo_server.mojo: go/src/echo_server.go $(MOJO_SHARED_LIB)
 	$(call MOGO_BUILD,$<,$@)
 
+# Check that the dart-style is being met. Note: Comments are ignored when
+# checking whitespace.
+.PHONY: check-fmt
+check-fmt:
+	dartfmt -n $(DART_FILES)
+
+# Lint src and test files with dartanalyzer. This takes a few seconds.
+.PHONY: dartanalyzer
+dartanalyzer: dart/packages gen-mojom
+	cd dart && dartanalyzer $(DART_FILES)
+
+# Installs dart dependencies.
+dart/packages: dart/pubspec.yaml
+	cd dart && pub get
+
 .PHONY: run-echo-app
-run-echo-app: gen
-	$(MOJO_DIR)/src/mojo/devtools/common/mojo_run $(MOJO_FLAGS) -v --enable-multiprocess $(PWD)/gen/mojo/echo_client.mojo
+run-echo-app: gen/mojo/echo_server.mojo gen-mojom dart/packages
+	$(MOJO_DIR)/src/mojo/devtools/common/mojo_run $(MOJO_FLAGS) -v --enable-multiprocess $(PWD)/dart/bin/echo_client.dart
+
+# TODO(nlacasse): This should run real tests once we have them.
+.PHONY: test
+test: dartanalyzer
 
 .PHONY: clean
 clean:
 	rm -rf gen
+	rm -rf dart/{packages,.packages,pubspec.lock}
diff --git a/dart/bin/echo_client.dart b/dart/bin/echo_client.dart
new file mode 100644
index 0000000..1a040fa
--- /dev/null
+++ b/dart/bin/echo_client.dart
@@ -0,0 +1,55 @@
+#!mojo mojo:dart_content_handler
+
+import 'dart:async';
+
+// TODO(nlacasse): Use 'show' or 'as' in non-stdlib import statements, per
+// Vanadium Dart convention.
+import 'package:mojo/application.dart';
+import 'package:mojo/core.dart';
+
+import '../../gen/dart-gen/mojom/lib/mojo/echo.mojom.dart' show EchoEchoStringResponseParams, EchoProxy;
+
+class Client extends Application {
+  Client.fromHandle(MojoHandle handle) : super.fromHandle(handle);
+
+  void initialize(List<String> args, String url) {
+    // TODO(nlacasse): This is pretty gross, but there's no good way to get the
+    // current directory from within a Mojo app.  Dart's Directory.current() is
+    // either broken or unsupported.  In any case, this will never work on
+    // Android, so we should switch to serving these files over http rather
+    // than directly from the filesystem.
+    String echoServerUrl = url.replaceFirst('dart/bin/echo_client.dart', 'gen/mojo/echo_server.mojo');
+
+    print('connecting to $echoServerUrl');
+
+    EchoProxy ep = new EchoProxy.unbound();
+    connectToService(echoServerUrl, ep);
+
+    print('connected');
+
+    String input = 'foobee';
+
+    print('calling echoString($input)');
+    ep.ptr.echoString(input).then((EchoEchoStringResponseParams v) {
+      String output = v.value;
+      print('got echo result: $output');
+
+      assert(input == output);
+      print('SUCCESS');
+
+      closeApplication();
+    });
+
+    print('done calling echoString');
+  }
+
+  Future closeApplication() async {
+    await close();
+    assert(MojoHandle.reportLeakedHandles());
+  }
+}
+
+main(List args) {
+  MojoHandle appHandle = new MojoHandle(args[0]);
+  new Client.fromHandle(appHandle);
+}
diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml
new file mode 100644
index 0000000..9f863bd
--- /dev/null
+++ b/dart/pubspec.yaml
@@ -0,0 +1,3 @@
+name: Ether
+dependencies:
+    mojo: any
diff --git a/go/src/echo_client.go b/go/src/echo_client.go
deleted file mode 100644
index 13f0a43..0000000
--- a/go/src/echo_client.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// NOTE(nlacasse): This file was taken from $MOJO_DIR/src/examples/go.  The
-// only changes are the mojom import path, and the location of
-// echo_server.mojo.
-
-package main
-
-import (
-	"fmt"
-	"log"
-	"os"
-
-	"golang.org/x/mobile/app"
-
-	"mojo/public/go/application"
-	"mojo/public/go/bindings"
-	"mojo/public/go/system"
-
-	"mojom/echo"
-)
-
-//#include "mojo/public/c/system/types.h"
-import "C"
-
-type EchoClientDelegate struct{}
-
-func (delegate *EchoClientDelegate) Initialize(ctx application.Context) {
-	// TODO(nlacasse): Using a file:// url for the mojo service will not work
-	// on Android.  We should be using --map-origin flag, but that is not
-	// supported on Linux.  See https://github.com/domokit/mojo/issues/349
-	wd, err := os.Getwd()
-	if err != nil {
-		panic(err)
-	}
-	serverName := "file://" + wd + "/gen/mojo/echo_server.mojo"
-
-	echoRequest, echoPointer := echo.CreateMessagePipeForEcho()
-	ctx.ConnectToApplication(serverName).ConnectToService(&echoRequest)
-	echoProxy := echo.NewEchoProxy(echoPointer, bindings.GetAsyncWaiter())
-	response, err := echoProxy.EchoString(bindings.StringPointer("Hello, Gopher world!"))
-	if response != nil {
-		fmt.Printf("client: %s\n", *response)
-	} else {
-		log.Println(err)
-	}
-	echoProxy.Close_Proxy()
-	ctx.Close()
-}
-
-func (delegate *EchoClientDelegate) AcceptConnection(connection *application.Connection) {
-	connection.Close()
-}
-
-func (delegate *EchoClientDelegate) Quit() {
-}
-
-//export MojoMain
-func MojoMain(handle C.MojoHandle) C.MojoResult {
-	application.Run(&EchoClientDelegate{}, system.MojoHandle(handle))
-	return C.MOJO_RESULT_OK
-}
-
-func main() {
-	app.Run(app.Callbacks{})
-}