Get syncgroup working cross-device.
Change-Id: Id1764d0a95ba0f5ae393a0d419f8334162e9a493
diff --git a/Makefile b/Makefile
index 4a29353..79eb5c9 100644
--- a/Makefile
+++ b/Makefile
@@ -5,12 +5,13 @@
include ../shared/mojo.mk
# Flags for Syncbase service running as Mojo service.
-SYNCBASED_ADDR := 127.0.0.1:4002
-V23_MOJO_FLAGS := --v=0 --v23.tcp.address=$(SYNCBASED_ADDR) --v23.permissions.literal={\"Admin\":{\"In\":[\"...\"]},\"Write\":{\"In\":[\"...\"]},\"Read\":{\"In\":[\"...\"]},\"Resolve\":{\"In\":[\"...\"]},\"Debug\":{\"In\":[\"...\"]}}
+V23_MOJO_FLAGS := --v=0
# MOUNTTABLE_ADDR := 127.0.0.1:4001
ifdef MOUNTTABLE_ADDR
- V23_MOJO_FLAGS += --name=syncbase_mojo --v23.namespace.root=/$(MOUNTTABLE_ADDR)
+ # TODO(nlacasse): Get your email address out of here!
+ MOUNT_NAME := users/nlacasse@google.com/syncbase_mojo
+ V23_MOJO_FLAGS += --name=$(MOUNT_NAME) --v23.proxy=proxy --v23.namespace.root=$(MOUNTTABLE_ADDR)
endif
ifdef ANDROID
@@ -25,13 +26,15 @@
# directory inside APP_HOME_DIR.) We set syncbase root-dir inside
# APP_HOME_DIR for the same reason.
APP_HOME_DIR = /data/data/org.chromium.mojo.shell/app_home
- V23_MOJO_FLAGS += --logtostderr=true --root-dir=$(APP_HOME_DIR)/syncbase_data
+ ANDROID_CREDS_DIR := /sdcard/v23creds
+ V23_MOJO_FLAGS += --logtostderr=true --root-dir=$(APP_HOME_DIR)/syncbase_data --v23.credentials=$(ANDROID_CREDS_DIR)
else
ETHER_BUILD_DIR := $(PWD)/gen/mojo/linux_amd64
THIRD_PARTY_LIBS := $(JIRI_ROOT)/third_party/cout/linux_amd64
- V23_MOJO_FLAGS += --root-dir=$(PWD)/tmp/syncbase_data
+ SYNCBASE_ROOT_DIR := $(PWD)/tmp/syncbase_data
+ V23_MOJO_FLAGS += --root-dir=$(SYNCBASE_ROOT_DIR) --v23.credentials=$(PWD)/creds
endif
# NOTE(nlacasse): Running Go Mojo services requires passing the
@@ -58,7 +61,7 @@
touch $@
# Mints credentials.
-creds: bin
+creds: | bin
./bin/principal seekblessings --v23.credentials creds
touch $@
@@ -106,8 +109,11 @@
cd dart && pub upgrade
.PHONY: run-syncbase-example
-run-syncbase-example: $(ETHER_BUILD_DIR)/syncbase_server.mojo dart/packages dart/lib/gen/dart-gen/mojom/lib/mojo/syncbase.mojom.dart | syncbase-env-check
- $(call MOJO_RUN,https://mojo.v.io/syncbase_example.dart)
+run-syncbase-example: $(ETHER_BUILD_DIR)/syncbase_server.mojo dart/packages dart/lib/gen/dart-gen/mojom/lib/mojo/syncbase.mojom.dart | syncbase-env-check creds
+ifdef ANDROID
+ adb push -p $(PWD)/creds $(ANDROID_CREDS_DIR)
+endif
+ $(call MOJO_RUN,"https://mojo.v.io/syncbase_example.dart $(MOUNTTABLE_ADDR)")
.PHONY: test
test: test-unit test-integration
@@ -118,6 +124,14 @@
.PHONY: test-integration
test-integration: dart/packages $(ETHER_BUILD_DIR)/syncbase_server.mojo gen-mojom | syncbase-env-check
+ifdef MOUNTTABLE_ADDR
+ $(error please unset MOUNTTABLE_ADDR before running the tests)
+endif
+ # Delete the 'creds' dir to make sure we are running with in-memory
+ # credentials. Otherwise tests time out.
+ # TODO(nlacasse): Figure out why tests time out with dev.v.io credentials.
+ # Maybe caveat validation?
+ rm -rf $(PWD)/creds
# NOTE(nlacasse): The "tests" argument must come before the "MOJO_SHELL_FLAGS" flags,
# otherwise mojo_test's argument parser gets confused and exits with an error.
$(MOJO_DIR)/src/mojo/devtools/common/mojo_test tests --config-file $(PWD)/mojoconfig --shell-path $(MOJO_SHELL_PATH) $(MOJO_ANDROID_FLAGS) $(MOJO_SHELL_FLAGS)
@@ -135,7 +149,7 @@
# TODO(aghassemi): Why does mojo generate dart-pkg and mojom dirs?
.PHONY: clean
clean:
- rm -rf bin gen tmp
+ rm -rf bin creds gen tmp
rm -rf dart/lib/gen/dart-pkg
rm -rf dart/lib/gen/mojom
diff --git a/dart/bin/syncbase_example.dart b/dart/bin/syncbase_example.dart
index 02886a5..03bde77 100644
--- a/dart/bin/syncbase_example.dart
+++ b/dart/bin/syncbase_example.dart
@@ -3,19 +3,158 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+import 'dart:async';
+import 'dart:math' show Random;
+import 'dart:convert' show UTF8;
+
import 'package:ether/initialized_application.dart' show InitializedApplication;
-import 'package:ether/syncbase_client.dart' show SyncbaseClient;
+import 'package:ether/src/naming/util.dart' as naming;
+import 'package:ether/syncbase_client.dart' as sb;
main(List args) async {
- InitializedApplication app = new InitializedApplication.fromHandle(args[0]);
- await app.initialized;
+ // mojo_shell does not print a stack trace when the dart program crashes.
+ // Hence, we must wrap everything in a try/catch if we want to see the
+ // errors. :(
+ try {
+ InitializedApplication app = new InitializedApplication.fromHandle(args[0]);
+ await app.initialized;
- SyncbaseClient c = new SyncbaseClient(
- app.connectToService, 'https://mojo.v.io/syncbase_server.mojo');
+ // Application arguments are in app.args.
+ // app.args[0] = url of this service. Rest of arguments follow.
+ if (app.args.length < 2 || app.args[1] == null || app.args[1] == '') {
+ throw 'mount table address must be first argument';
+ }
- bool exists = await c.app('foo').exists();
- print('app(foo).exists(): $exists');
+ String mtAddr = app.args[1];
- await c.close();
- await app.close();
+ sb.SyncbaseClient c = new sb.SyncbaseClient(
+ app.connectToService, 'https://mojo.v.io/syncbase_server.mojo');
+
+ sb.SyncbaseApp sbApp = await createApp(c, 'testapp');
+ sb.SyncbaseNoSqlDatabase sbDb = await createDb(sbApp, 'testdb');
+ sb.SyncbaseTable sbTable = await createTable(sbDb, 'testtable');
+ await joinOrCreateSyncGroup(sbDb, mtAddr, sbTable.name, 'testsg');
+
+ startWatch(sbDb, sbTable);
+ startPuts(sbTable);
+
+ // Wait forever.
+ await new Completer().future;
+
+ // Looks like forever came and went. Might as well clean up after
+ // ourselves...
+ await c.close();
+ await app.close();
+ } catch (e) {
+ print('ERROR in main()');
+ print(e);
+ }
+}
+
+startWatch(db, table) async {
+ try {
+ var s = db.watch(table.name, '', await db.getResumeMarker());
+ s.forEach((change) {
+ print('GOT CHANGE: ${change.rowName} - ${UTF8.decode(change.valueBytes)} - ${change.fromSync}');
+ });
+ } catch (e) {
+ print('ERROR in startWatch()');
+ print(e);
+ }
+}
+
+var r = new Random();
+
+startPuts(table) async {
+ try {
+ var key = r.nextInt(100000000);
+ var val = r.nextInt(100000000);
+
+ var row = table.row('k$key');
+ print('PUTTING k$key');
+ await row.put(UTF8.encode('$val'));
+ } catch (e) {
+ print('ERROR in startPuts()');
+ print(e);
+ }
+
+ await new Future.delayed(new Duration(seconds:5));
+ startPuts(table);
+}
+
+String openPermsJson =
+ '{"Admin":{"In":["..."]},"Write":{"In":["..."]},"Read":{"In":["..."]},"Resolve":{"In":["..."]},"Debug":{"In":["..."]}}';
+sb.Perms openPerms = sb.SyncbaseClient.perms(openPermsJson);
+
+Future<sb.SyncbaseApp> createApp(sb.SyncbaseClient c, String name) async {
+ var app = c.app(name);
+ var exists = await app.exists();
+ if (exists) {
+ print('app exists, rolling with it');
+ return app;
+ }
+ print('app does not exist, creating it');
+ await app.create(openPerms);
+ return app;
+}
+
+Future<sb.SyncbaseNoSqlDatabase> createDb(sb.SyncbaseApp app, String name) async {
+ var db = app.noSqlDatabase(name);
+ var exists = await db.exists();
+ if (exists) {
+ print('db exists, rolling with it');
+ return db;
+ }
+ print('db does not exist, creating it');
+ await db.create(openPerms);
+ return db;
+}
+
+Future<sb.SyncbaseTable> createTable(sb.SyncbaseNoSqlDatabase db, String name) async {
+ var table = db.table(name);
+ var exists = await table.exists();
+ if (exists) {
+ print('table exists, rolling with it');
+ return table;
+ }
+ print('table does not exist, creating it');
+ await table.create(openPerms);
+ return table;
+}
+
+Future<sb.SyncbaseSyncGroup> joinOrCreateSyncGroup(sb.SyncbaseNoSqlDatabase db, String mtAddr, String tableName, String name) async {
+ // TODO(nlacasse): Get your email address out of here! Figure out a way to
+ // get the mounttable name and path to this part of the code.
+ var mtName = naming.join(mtAddr, 'users/nlacasse@google.com');
+ // TODO(nlacasse): Make this %%sync thing a constant.
+ var sgPrefix = naming.join(mtName, 'syncbase_mojo/%%sync');
+ var sgName = naming.join(sgPrefix, 'testsg');
+ var sg = db.syncGroup(sgName);
+
+ print('SGNAME = $sgName');
+
+ var myInfo = sb.SyncbaseClient.syncGroupMemberInfo(syncPriority: 3);
+
+ try {
+ print('trying to join syncgroup');
+ await sg.join(myInfo);
+ print('syncgroup join success');
+ } catch (e) {
+ // Syncgroup does not exist.
+ print('syncgroup does not exist, creating it');
+
+ var sgSpec = sb.SyncbaseClient.syncGroupSpec(
+ description: 'test sync group',
+ perms: openPerms,
+ // Sync the entire table.
+ prefixes: ['$tableName:'],
+ mountTables: [mtName]
+ );
+
+ print('SGSPEC = $sgSpec');
+
+ await sg.create(sgSpec, myInfo);
+ }
+
+ return sg;
}
diff --git a/dart/lib/initialized_application.dart b/dart/lib/initialized_application.dart
index 7d4b32d..797de2d 100644
--- a/dart/lib/initialized_application.dart
+++ b/dart/lib/initialized_application.dart
@@ -12,13 +12,17 @@
// InitializedApplication is an Application with a future 'initialized' that is
// resolved after the 'initialize' method finishes.
class InitializedApplication extends Application {
- final _initializeCompleter = new Completer();
+ final Completer _initializeCompleter = new Completer();
Future get initialized => _initializeCompleter.future;
+ List<String> _args;
+ List<String> get args => _args;
+
InitializedApplication.fromHandle(int handle)
: super.fromHandle(new MojoHandle(handle));
void initialize(List<String> args, String url) {
+ _args = args;
_initializeCompleter.complete();
}
}