Syncbase Discovery: Expose the invites API via JNI / Java.
MultiPart: 1/3
Change-Id: I582735ee27336f05065bc791e68138f6dd71bac7
diff --git a/impl/google/services/syncbase/jni.go b/impl/google/services/syncbase/jni.go
index 92b5a2d..328fd03 100644
--- a/impl/google/services/syncbase/jni.go
+++ b/impl/google/services/syncbase/jni.go
@@ -13,7 +13,9 @@
"v.io/v23"
"v.io/v23/options"
+ wire "v.io/v23/services/syncbase"
"v.io/x/ref/lib/dispatcher"
+ "v.io/x/ref/services/syncbase/discovery"
"v.io/x/ref/services/syncbase/server"
"v.io/x/ref/services/syncbase/vsync"
@@ -31,8 +33,11 @@
contextSign = jutil.ClassSign("io.v.v23.context.VContext")
storageEngineSign = jutil.ClassSign("io.v.impl.google.services.syncbase.SyncbaseServer$StorageEngine")
serverSign = jutil.ClassSign("io.v.v23.rpc.Server")
+ idSign = jutil.ClassSign("io.v.v23.services.syncbase.Id")
+ inviteSign = jutil.ClassSign("io.v.v23.syncbase.Invite")
jVRuntimeImplClass jutil.Class
+ jInviteClass jutil.Class
)
// Init initializes the JNI code with the given Java environment. This method
@@ -44,6 +49,10 @@
if err != nil {
return err
}
+ jInviteClass, err = jutil.JFindClass(env, "io/v/v23/syncbase/Invite")
+ if err != nil {
+ return err
+ }
return nil
}
@@ -145,3 +154,69 @@
}
return C.jobject(unsafe.Pointer(jServerAttCtx))
}
+
+//export Java_io_v_v23_syncbase_DatabaseImpl_nativeListenForInvites
+func Java_io_v_v23_syncbase_DatabaseImpl_nativeListenForInvites(jenv *C.JNIEnv, jDatabase C.jobject, jContext C.jobject, jInviteHandler C.jobject) {
+ env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
+ database := jutil.Object(uintptr(unsafe.Pointer(jDatabase)))
+ handler := jutil.Object(uintptr(unsafe.Pointer(jInviteHandler)))
+
+ ctx, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jContext))))
+ if err != nil {
+ jutil.JThrowV(env, err)
+ return
+ }
+
+ jDbId, err := jutil.CallObjectMethod(env, database, "id", nil, idSign)
+ if err != nil {
+ jutil.JThrowV(env, err)
+ return
+ }
+ dbName, err := jutil.CallStringMethod(env, jDbId, "getName", nil)
+ if err != nil {
+ jutil.JThrowV(env, err)
+ return
+ }
+ dbBlessing, err := jutil.CallStringMethod(env, jDbId, "getBlessing", nil)
+ if err != nil {
+ jutil.JThrowV(env, err)
+ return
+ }
+
+ dbId := wire.Id{Name: dbName, Blessing: dbBlessing}
+ // Note: There is no need to use a buffered channel here. ListenForInvites
+ // spawns a goroutine for this listener that acts as an infinite buffer so we can
+ // process invites at our own pace.
+ ch := make(chan discovery.Invite)
+ if err := discovery.ListenForInvites(ctx, dbId, ch); err != nil {
+ jutil.JThrowV(env, err)
+ return
+ }
+
+ handler = jutil.NewGlobalRef(env, handler)
+ go func() {
+ for invite := range ch {
+ if err := handleInvite(invite, handler); err != nil {
+ // TODO(mattr): We should cancel the stream and return an error to
+ // the user here.
+ ctx.Errorf("couldn't call invite handler: %v", err)
+ }
+ }
+ env, free := jutil.GetEnv()
+ jutil.DeleteGlobalRef(env, handler)
+ free()
+ }()
+}
+
+func handleInvite(invite discovery.Invite, handler jutil.Object) error {
+ env, free := jutil.GetEnv()
+ defer free()
+ jInvite, err := jutil.NewObject(env, jInviteClass,
+ []jutil.Sign{jutil.StringSign, jutil.StringSign},
+ invite.Syncgroup.Blessing, invite.Syncgroup.Name)
+ if err != nil {
+ return err
+ }
+ return jutil.CallVoidMethod(env, handler, "handleInvite",
+ []jutil.Sign{inviteSign}, jInvite)
+}