x/ref: syncbase cgo bridge ListenForAppPeers and ListenForInvites
We use the syncbase/discovery implementations of ListenForAppPeers
and ListenForInvites to surface them in the cgo bridge.
The next steps are to plumb this through in jni (and Swift).
Note: Untested. All I can tell is that it compiles. Other than doing
the JNI + high-level implementation, how can I check?
Note2: I've been hooking this up through JNI and high-level Java.
It compiles there and has approximately the correct format.
Change-Id: I00c6ff045073cc7c3d9b32769cf3f2858b7bd0f3
diff --git a/services/syncbase/bridge/cgo/impl.go b/services/syncbase/bridge/cgo/impl.go
index 2d2faf5..b7c232c 100644
--- a/services/syncbase/bridge/cgo/impl.go
+++ b/services/syncbase/bridge/cgo/impl.go
@@ -46,6 +46,8 @@
"v.io/v23/vom"
_ "v.io/x/ref/runtime/factories/roaming"
"v.io/x/ref/services/syncbase/bridge"
+ "v.io/x/ref/services/syncbase/bridge/cgo/refmap"
+ "v.io/x/ref/services/syncbase/discovery"
"v.io/x/ref/services/syncbase/syncbaselib"
"v.io/x/ref/test/testutil"
)
@@ -66,6 +68,20 @@
static void CallCollectionScanCallbacksOnDone(v23_syncbase_CollectionScanCallbacks cbs, v23_syncbase_VError err) {
cbs.onDone(cbs.handle, err);
}
+
+static void CallDbSyncgroupInvitesOnInvite(v23_syncbase_DbSyncgroupInvitesCallbacks cbs, v23_syncbase_Invite i) {
+ cbs.onInvite(cbs.handle, i);
+}
+static void CallDbSyncgroupInvitesOnDone(v23_syncbase_DbSyncgroupInvitesCallbacks cbs) {
+ cbs.onDone(cbs.handle);
+}
+
+static void CallNeighborhoodScanCallbacksOnPeer(v23_syncbase_NeighborhoodScanCallbacks cbs, v23_syncbase_AppPeer p) {
+ cbs.onPeer(cbs.handle, p);
+}
+static void CallNeighborhoodScanCallbacksOnDone(v23_syncbase_NeighborhoodScanCallbacks cbs) {
+ cbs.onDone(cbs.handle);
+}
*/
import "C"
@@ -82,8 +98,13 @@
// testLogin indicates if the test login mode is used. This is triggered
// by using an empty identity provider.
testLogin bool
+
+ // neighborhoodAdStatus tracks the status of the neighborhood advertisement.
+ neighborhoodAdStatus *adStatus
)
+var globalRefMap = refmap.NewRefMap()
+
// TODO(razvanm): Replace the function arguments with an options struct.
//export v23_syncbase_Init
func v23_syncbase_Init(cClientUnderstandVom C.v23_syncbase_Bool, cRootDir C.v23_syncbase_String, cTestLogin C.v23_syncbase_Bool) {
@@ -104,6 +125,32 @@
}
}
+type adStatus struct {
+ isAdvertising bool
+ cancel context.CancelFunc
+ done <-chan struct{}
+}
+
+func newAdStatus() *adStatus {
+ return &adStatus{}
+}
+
+func (a *adStatus) store(cancel context.CancelFunc, done <-chan struct{}) {
+ a.isAdvertising = true
+ a.cancel = cancel
+ a.done = done
+}
+
+func (a *adStatus) stop() {
+ if a.isAdvertising {
+ a.cancel()
+ <-a.done
+ a.isAdvertising = false
+ a.cancel = nil
+ a.done = nil
+ }
+}
+
//export v23_syncbase_Serve
func v23_syncbase_Serve(cErr *C.v23_syncbase_VError) {
if !isLoggedIn() {
@@ -266,6 +313,77 @@
}
////////////////////////////////////////
+// Service
+
+//export v23_syncbase_NeighborhoodStartAdvertising
+func v23_syncbase_NeighborhoodStartAdvertising(cVisibility C.v23_syncbase_Strings, cErr *C.v23_syncbase_VError) {
+ // Cancel an old ad, if necessary.
+ v23_syncbase_NeighborhoodStopAdvertising()
+
+ // Initialize app advertisement.
+ advCtx, cancel := context.WithCancel(b.Ctx)
+ visibility := cVisibility.extract()
+ visBlessingPatterns := make([]security.BlessingPattern, len(visibility))
+ for i, vis := range visibility {
+ visBlessingPatterns[i] = security.BlessingPattern(vis)
+ }
+ doneAd, err := discovery.AdvertiseApp(advCtx, visBlessingPatterns)
+ if err != nil {
+ cErr.init(err)
+ return
+ }
+
+ // Remember the ad's cancellation information.
+ neighborhoodAdStatus.store(cancel, doneAd)
+}
+
+//export v23_syncbase_NeighborhoodStopAdvertising
+func v23_syncbase_NeighborhoodStopAdvertising() {
+ neighborhoodAdStatus.stop()
+}
+
+//export v23_syncbase_NeighborhoodIsAdvertising
+func v23_syncbase_NeighborhoodIsAdvertising(cBool *C.v23_syncbase_Bool) {
+ cBool.init(neighborhoodAdStatus.isAdvertising)
+}
+
+//export v23_syncbase_NeighborhoodNewScan
+func v23_syncbase_NeighborhoodNewScan(cbs C.v23_syncbase_NeighborhoodScanCallbacks, cUint64 *C.uint64_t, cErr *C.v23_syncbase_VError) {
+ scanCtx, cancel := context.WithCancel(b.Ctx)
+ scanChan := make(chan discovery.AppPeer)
+ err := discovery.ListenForAppPeers(scanCtx, scanChan)
+ if err != nil {
+ cErr.init(err)
+ return
+ }
+
+ // Forward the scan results to the callback.
+ go func() {
+ for {
+ peer, ok := <-scanChan
+ if !ok {
+ C.CallNeighborhoodScanCallbacksOnDone(cbs)
+ break
+ }
+ cPeer := C.v23_syncbase_AppPeer{}
+ cPeer.init(peer)
+ C.CallNeighborhoodScanCallbacksOnPeer(cbs, cPeer)
+ }
+ }()
+
+ // Remember the scan's cancellation information and return the scan's id.
+ x := C.uint64_t(globalRefMap.Add(cancel))
+ cUint64 = &x
+}
+
+//export v23_syncbase_NeighborhoodStopScan
+func v23_syncbase_NeighborhoodStopScan(cUint64 C.uint64_t) {
+ if cancel, ok := globalRefMap.Remove(uint64(cUint64)).(context.CancelFunc); ok && cancel != nil {
+ cancel()
+ }
+}
+
+////////////////////////////////////////
// Database
//export v23_syncbase_DbCreate
@@ -626,6 +744,52 @@
}
////////////////////////////////////////
+// Syncgroup Invites
+
+//export v23_syncbase_DbSyncgroupInvitesNewScan
+func v23_syncbase_DbSyncgroupInvitesNewScan(cName C.v23_syncbase_String, cbs C.v23_syncbase_DbSyncgroupInvitesCallbacks, cUint64 *C.uint64_t, cErr *C.v23_syncbase_VError) {
+ encodedId := cName.extract()
+ dbId, err := util.DecodeId(encodedId)
+ if err != nil {
+ cErr.init(err)
+ return
+ }
+
+ scanCtx, cancel := context.WithCancel(b.Ctx)
+ scanChan := make(chan discovery.Invite)
+ err = discovery.ListenForInvites(scanCtx, dbId, scanChan)
+ if err != nil {
+ cErr.init(err)
+ return
+ }
+
+ // Forward the scan results to the callback.
+ go func() {
+ for {
+ invite, ok := <-scanChan
+ if !ok {
+ C.CallDbSyncgroupInvitesOnDone(cbs)
+ break
+ }
+ cInvite := C.v23_syncbase_Invite{}
+ cInvite.init(invite)
+ C.CallDbSyncgroupInvitesOnInvite(cbs, cInvite)
+ }
+ }()
+
+ // Remember the scan's cancellation information and return the scan's id.
+ x := C.uint64_t(globalRefMap.Add(cancel))
+ cUint64 = &x
+}
+
+//export v23_syncbase_DbSyncgroupInvitesStopScan
+func v23_syncbase_DbSyncgroupInvitesStopScan(cUint64 C.uint64_t) {
+ if cancel, ok := globalRefMap.Remove(uint64(cUint64)).(context.CancelFunc); ok && cancel != nil {
+ cancel()
+ }
+}
+
+////////////////////////////////////////
// Collection
//export v23_syncbase_CollectionCreate
diff --git a/services/syncbase/bridge/cgo/jni.go b/services/syncbase/bridge/cgo/jni.go
index dd7fd2a..eda5486 100644
--- a/services/syncbase/bridge/cgo/jni.go
+++ b/services/syncbase/bridge/cgo/jni.go
@@ -10,7 +10,6 @@
import (
"fmt"
"unsafe"
- "v.io/x/ref/services/syncbase/bridge/cgo/refmap"
)
/*
@@ -63,8 +62,6 @@
watchChangeClass jWatchChange
)
-var globalRefMap = refmap.NewRefMap()
-
// JNI_OnLoad is called when System.loadLibrary is called. We need to cache the
// *JavaVM because that's the only way to get hold of a JNIEnv that is needed
// for any JNI operation.
diff --git a/services/syncbase/bridge/cgo/lib.h b/services/syncbase/bridge/cgo/lib.h
index d216df6..748661d 100644
--- a/services/syncbase/bridge/cgo/lib.h
+++ b/services/syncbase/bridge/cgo/lib.h
@@ -128,6 +128,19 @@
int n;
} v23_syncbase_SyncgroupMemberInfoMap;
+// syncbase.discovery.Invite
+typedef struct {
+ v23_syncbase_Id syncgroup;
+ v23_syncbase_Strings addresses;
+} v23_syncbase_Invite;
+
+// syncbase.discovery.AppPeer
+typedef struct {
+ v23_syncbase_String appName;
+ v23_syncbase_String blessings;
+ bool isLost;
+} v23_syncbase_AppPeer;
+
////////////////////////////////////////
// Functions
@@ -145,4 +158,16 @@
void (*onDone)(v23_syncbase_Handle handle, v23_syncbase_VError);
} v23_syncbase_CollectionScanCallbacks;
+typedef struct {
+ v23_syncbase_Handle handle;
+ void (*onInvite)(v23_syncbase_Handle handle, v23_syncbase_Invite);
+ void (*onDone)(v23_syncbase_Handle handle);
+} v23_syncbase_DbSyncgroupInvitesCallbacks;
+
+typedef struct {
+ v23_syncbase_Handle handle;
+ void (*onPeer)(v23_syncbase_Handle handle, v23_syncbase_AppPeer);
+ void (*onDone)(v23_syncbase_Handle handle);
+} v23_syncbase_NeighborhoodScanCallbacks;
+
#endif // V23_SYNCBASE_LIB_H_
diff --git a/services/syncbase/bridge/cgo/types.go b/services/syncbase/bridge/cgo/types.go
index 26907ab..0188d17 100644
--- a/services/syncbase/bridge/cgo/types.go
+++ b/services/syncbase/bridge/cgo/types.go
@@ -13,6 +13,7 @@
"v.io/v23/syncbase"
"v.io/v23/verror"
"v.io/v23/vom"
+ "v.io/x/ref/services/syncbase/discovery"
)
// All "x.extract" methods return a native Go type and leave x in the same state
@@ -436,3 +437,20 @@
x.continued = C.bool(wc.Continued)
return nil
}
+
+////////////////////////////////////////////////////////////
+// C.v23_syncbase_Invite
+
+func (x *C.v23_syncbase_Invite) init(invite discovery.Invite) {
+ x.syncgroup.init(invite.Syncgroup)
+ x.addresses.init(invite.Addresses)
+}
+
+////////////////////////////////////////////////////////////
+// C.v23_syncbase_AppPeer
+
+func (x *C.v23_syncbase_AppPeer) init(peer discovery.AppPeer) {
+ x.appName.init(peer.AppName)
+ x.blessings.init(peer.Blessings)
+ x.isLost = C.bool(peer.Lost)
+}