Added examples for advertisers.
Change-Id: If292c9bbc4dca61a2cd8f8dcf7e5532dd1f81206
diff --git a/Makefile b/Makefile
index ed28a23..a985e6d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,8 @@
-PWD := $(shell pwd)
-
include ../shared/mojo.mk
# ANDROID needs to be any positive integer (e.g., 1, 2, 3, 4...)
ifdef ANDROID
- BUILD_DIR := $(PWD)/gen/mojo/android
+ BUILD_DIR := $(CURDIR)/gen/mojo/android
# For some reason we need to set the origin flag when running on Android,
# but setting it on Linux causes errors.
@@ -16,12 +14,14 @@
DEVICE_ID := $(shell adb devices | sed -n $(ANDROID_PLUS_ONE)p | awk '{ print $$1; }')
DEVICE_FLAG := --target-device $(DEVICE_ID)
ANDROID_FLAG := --android
+ DISCOVERY_DIR := $(CURDIR)/../discovery/gen/mojo/android
else
- BUILD_DIR := $(PWD)/gen/mojo/linux_amd64
+ BUILD_DIR := $(CURDIR)/gen/mojo/linux_amd64
+ DISCOVERY_DIR := $(CURDIR)/../discovery/gen/mojo/linux_amd64
endif
# Add the discovery mojom output to the go path.
-export GOPATH := $(PWD)/../discovery/gen/go
+GOPATH := $(GOPATH):$(CURDIR)/../discovery/go
# If this is not the first mojo shell, then you must reuse the devservers
# to avoid a "port in use" error.
@@ -35,7 +35,7 @@
# Build the v23proxy.mojo, client, and associated go examples.
.PHONY: build-go
-build-go: $(BUILD_DIR)/v23proxy.mojo build-go-examples
+build-go: $(BUILD_DIR)/v23proxy.mojo $(BUILD_DIR)/discovery.mojo build-go-examples
# Build the v23proxy client and its associated dart examples.
.PHONY: build-dart
@@ -54,7 +54,7 @@
upgrade-packages:
pub upgrade
-build-go-examples: $(BUILD_DIR)/echo_client.mojo $(BUILD_DIR)/echo_server.mojo $(BUILD_DIR)/fortune_client.mojo $(BUILD_DIR)/fortune_server.mojo
+build-go-examples: $(BUILD_DIR)/echo_client.mojo $(BUILD_DIR)/echo_server.mojo $(BUILD_DIR)/fortune_client.mojo $(BUILD_DIR)/fortune_server.mojo $(BUILD_DIR)/echo_client_discovery.mojo $(BUILD_DIR)/echo_server_discovery.mojo
build-dart-examples: gen/echo.mojom.dart gen/fortune.mojom.dart
@@ -89,6 +89,13 @@
$(BUILD_DIR)/echo_server.mojo: gen/go/src/mojom/examples/echo/echo.mojom.go
$(call MOGO_BUILD,examples/echo/server,$@)
+$(BUILD_DIR)/echo_client_discovery.mojo: gen/go/src/mojom/examples/echo/echo.mojom.go
+ $(call MOGO_BUILD,examples/advertiser/client,$@)
+
+$(BUILD_DIR)/echo_server_discovery.mojo: gen/go/src/mojom/examples/echo/echo.mojom.go
+ $(call MOGO_BUILD,examples/advertiser/server,$@)
+
+
gen/go/src/mojom/examples/echo/echo.mojom.go: mojom/mojom/examples/echo.mojom | mojo-env-check
$(call MOJOM_GEN,$<,mojom,gen,go)
gofmt -w $@
@@ -102,6 +109,10 @@
$(BUILD_DIR)/fortune_server.mojo: gen/go/src/mojom/examples/fortune/fortune.mojom.go
$(call MOGO_BUILD,examples/fortune/server,$@)
+$(BUILD_DIR)/discovery.mojo:
+ make -C ../discovery build
+ cp $(DISCOVERY_DIR)/discovery.mojo $(BUILD_DIR)/discovery.mojo
+
gen/go/src/mojom/examples/fortune/fortune.mojom.go: mojom/mojom/examples/fortune.mojom | mojo-env-check
$(call MOJOM_GEN,$<,mojom,gen,go)
gofmt -w $@
@@ -137,7 +148,7 @@
rm -f lib/gen/mojom/$(notdir $@)
gen-vdl:
- GOPATH=$(PWD)/go VDLPATH=$(PWD)/go vdl generate all
+ GOPATH=$(CURDIR)/go VDLPATH=$(CURDIR)/go vdl generate all
# Run the Mojo shell with map-origin. This is common to Linux and Android since
# the latter cannot accept a config-file.
@@ -157,7 +168,7 @@
$(REUSE_FLAG) \
$(ORIGIN_FLAG) \
--map-origin="https://mojo.v.io/=$(BUILD_DIR)" \
- --map-origin="https://mojodart.v.io/=$(PWD)" \
+ --map-origin="https://mojodart.v.io/=$(CURDIR)" \
--args-for="https://mojo$4.v.io/$2 $3" \
https://mojo$4.v.io/$2
endef
@@ -176,6 +187,11 @@
$(call RUN_MOJO_SHELL,--enable-multiprocess,v23proxy.mojo,,)
+.PHONY: start-advertising-server
+start-advertising-server: build-go
+ $(call RUN_MOJO_SHELL,--enable-multiprocess,echo_server_discovery.mojo,,)
+
+
# Start the echo client. This uses the v23proxy (client-side) to speak Vanadium
# over to the v23proxy (server-side) [OR a 0-authentication Vanadium echo server].
#
@@ -191,6 +207,21 @@
start-echo-client: build-go
$(call RUN_MOJO_SHELL,,echo_client.mojo,${ARGS},)
+# Start the echo client that uses discovery. This uses the v23proxy (client-side) to speak Vanadium
+# over to the v23proxy (server-side) [OR a 0-authentication Vanadium echo server].
+#
+# On Linux, run with
+# HOME={tmpdir} make ARGS="[optional: a string to echo]" start-echo-discovery-client
+#
+# On Android, run with
+# ANDROID={device number} make ARGS="[optional: a string to echo]" start-echo-discovery-client
+#
+# Note1: Does not use --enable-multiprocess since small Go programs can omit it.
+# Note2: Setting HOME ensures that we avoid a db LOCK that is created per mojo shell instance.
+.PHONY: start-echo-discovery-client
+start-echo-discovery-client: build-go
+ $(call RUN_MOJO_SHELL,,echo_client.mojo,${ARGS},)
+
# Like the start-echo-client but using a Dart client instead.
# Note: Uses --enable-multiprocess since it looks like the Dart VM and Go VM
# together are enough to cause a SIGSEGV (Android signal 11 crash) if this flag
diff --git a/go/src/examples/advertiser/client/scanner.go b/go/src/examples/advertiser/client/scanner.go
new file mode 100644
index 0000000..23cc07c
--- /dev/null
+++ b/go/src/examples/advertiser/client/scanner.go
@@ -0,0 +1,132 @@
+// 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.
+
+package main
+
+import (
+ "fmt"
+ "log"
+ "strings"
+
+ "mojo/public/go/application"
+ "mojo/public/go/bindings"
+ "mojo/public/go/system"
+
+ v23 "v.io/x/mojo/client"
+
+ "mojom/examples/echo"
+ "mojom/vanadium/discovery"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+type handler struct {
+ ch chan string
+}
+
+func (h *handler) Found(s discovery.Service) error {
+ log.Println("found ", s)
+ h.ch <- s.Addrs[0]
+ return nil
+}
+
+func (h *handler) Lost(s string) error {
+ log.Println("Lost ", s)
+ return nil
+}
+
+type RemoteEchoClientDelegate struct {
+}
+
+func (delegate *RemoteEchoClientDelegate) findService(ctx application.Context) (string, error) {
+ r, p := discovery.CreateMessagePipeForScanner()
+ ctx.ConnectToApplication("https://mojo.v.io/scanner.mojO").ConnectToService(&r)
+ scanner := discovery.NewScannerProxy(p, bindings.GetAsyncWaiter())
+ scanReq, scanPtr := discovery.CreateMessagePipeForScanHandler()
+ ch := make(chan string)
+ stub := discovery.NewScanHandlerStub(scanReq, &handler{ch: ch}, bindings.GetAsyncWaiter())
+ id, e1, e2 := scanner.Scan(`v.InterfaceName="mojo.examples.echo.RemoteEcho"`, scanPtr)
+ if e1 != nil {
+ return "", fmt.Errorf("%s", e1.Msg)
+ }
+
+ if e2 != nil {
+ return "", e2
+ }
+ go func() {
+ err := stub.ServeRequest()
+ if err != nil {
+ log.Println("failed to get result", err)
+ ch <- ""
+ }
+ scanner.Stop(id)
+ stub.Close()
+ }()
+ res := <-ch
+ return res, nil
+}
+
+// When running echo_client, ctx.Args() should contain:
+// 0: mojo app name
+// 1: remote endpoint
+// 2+: string to echo
+func (delegate *RemoteEchoClientDelegate) Initialize(ctx application.Context) {
+ log.Printf("RemoteEchoClientDelegate.Initialize...")
+
+ remoteEndpoint, err := delegate.findService(ctx)
+ if err != nil {
+ log.Println("Failed to start get address:", err)
+ return
+ }
+
+ // Parse arguments. Note: May panic if not enough args are given.
+ echoString := "Hello, Go world!"
+ if len(ctx.Args()) > 1 {
+ echoString = strings.Join(ctx.Args()[1:], " ")
+ }
+
+ r, p := echo.CreateMessagePipeForRemoteEcho()
+
+ v23.ConnectToRemoteService(ctx, &r, remoteEndpoint)
+ echoProxy := echo.NewRemoteEchoProxy(p, bindings.GetAsyncWaiter())
+
+ log.Printf("RemoteEchoClientDelegate.Initialize calling EchoString...")
+ response, err := echoProxy.EchoString(echoString)
+ if err == nil {
+ fmt.Printf("client: %s\n", response)
+ } else {
+ log.Println(err)
+ }
+
+ log.Printf("RemoteEchoClientDelegate.Initialize calling EchoX...")
+ response2, err := echoProxy.EchoX([]bool{true, false, false, true}, echo.AInArg{"A String"})
+ if err == nil {
+ fmt.Printf("client: %v\n", response2)
+ } else {
+ log.Println("Error: ", err)
+ }
+
+ fmt.Printf("(done)\n")
+ echoProxy.Close_Proxy()
+ ctx.Close()
+}
+
+func (delegate *RemoteEchoClientDelegate) AcceptConnection(connection *application.Connection) {
+ log.Printf("RemoteEchoClientDelegate.AcceptConnection...")
+ connection.Close()
+}
+
+func (delegate *RemoteEchoClientDelegate) Quit() {
+ log.Printf("RemoteEchoClientDelegate.Quit...")
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+ application.Run(&RemoteEchoClientDelegate{}, system.MojoHandle(handle))
+ return C.MOJO_RESULT_OK
+}
+
+func main() {
+}
diff --git a/go/src/examples/advertiser/server/advertiser.go b/go/src/examples/advertiser/server/advertiser.go
new file mode 100644
index 0000000..9bf6f99
--- /dev/null
+++ b/go/src/examples/advertiser/server/advertiser.go
@@ -0,0 +1,106 @@
+// 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.
+
+package main
+
+import (
+ "log"
+
+ "mojo/public/go/application"
+ "mojo/public/go/bindings"
+ "mojo/public/go/system"
+
+ "mojom/examples/echo"
+ "mojom/v23proxy"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+type RemoteEchoImpl struct{}
+
+// Note: This is pretty much identical to echo_server.go, except for the name changes.
+func (re *RemoteEchoImpl) EchoString(inValue string) (outValue string, err error) {
+ log.Printf("server EchoString: %s\n", inValue)
+ return inValue, nil
+}
+
+func (re *RemoteEchoImpl) EchoX(inArg1 []bool, inArg2 echo.AInArg) (out echo.OutArgTypes, err error) {
+ log.Printf("server EchoX: arg1: %v arg2: %v\n", inArg1, inArg2)
+ return &echo.OutArgTypesRes{echo.Result_B}, nil
+}
+
+type RemoteEchoServerDelegate struct {
+ remoteEchoFactory RemoteEchoFactory
+ instanceId *string
+ proxy *v23proxy.Advertiser_Proxy
+}
+
+type RemoteEchoFactory struct {
+ stubs []*bindings.Stub
+}
+
+func (delegate *RemoteEchoServerDelegate) Initialize(context application.Context) {
+ log.Printf("RemoteEchoServerDelegate.Initialize...")
+ req, ptr := v23proxy.CreateMessagePipeForAdvertiser()
+ context.ConnectToApplication("https://mojo.v.io/v23proxy.mojo").ConnectToService(&req)
+ delegate.proxy = v23proxy.NewAdvertiserProxy(ptr, bindings.GetAsyncWaiter())
+ mService := v23proxy.Service{
+ InterfaceName: "mojo.examples.echo.RemoteEcho",
+ Url: "https://mojo.v.io/echo_server_discovery.mojo/mojo::examples::RemoteEcho",
+ }
+ var err1 *string
+ var err error
+ delegate.instanceId, err1, err = delegate.proxy.Advertise(mService, nil)
+ if err != nil || err1 != nil {
+ var errMessage string
+ if err1 != nil {
+ errMessage = *err1
+ }
+ log.Println("Failed to advertise with", errMessage, err)
+ }
+}
+
+func (remoteEchoFactory *RemoteEchoFactory) Create(request echo.RemoteEcho_Request) {
+ log.Printf("RemoteEchoServer's RemoteEchoFactory.Create...")
+ stub := echo.NewRemoteEchoStub(request, &RemoteEchoImpl{}, bindings.GetAsyncWaiter())
+ remoteEchoFactory.stubs = append(remoteEchoFactory.stubs, stub)
+ go func() {
+ for {
+ if err := stub.ServeRequest(); err != nil {
+ connectionError, ok := err.(*bindings.ConnectionError)
+ if !ok || !connectionError.Closed() {
+ log.Println(err)
+ }
+ break
+ }
+ }
+ }()
+}
+
+func (delegate *RemoteEchoServerDelegate) AcceptConnection(connection *application.Connection) {
+ log.Printf("RemoteEchoServerDelegate.AcceptConnection...")
+ connection.ProvideServicesWithDescriber(
+ &echo.RemoteEcho_ServiceFactory{&delegate.remoteEchoFactory},
+ )
+}
+
+func (delegate *RemoteEchoServerDelegate) Quit() {
+ log.Printf("RemoteEchoServerDelegate.Quit...")
+ for _, stub := range delegate.remoteEchoFactory.stubs {
+ stub.Close()
+ }
+ if delegate.instanceId != nil {
+ delegate.proxy.StopAdvertising(*delegate.instanceId)
+ }
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+ application.Run(&RemoteEchoServerDelegate{}, system.MojoHandle(handle))
+ return C.MOJO_RESULT_OK
+}
+
+func main() {
+}
diff --git a/go/src/v.io/x/mojo/proxy/proxy.go b/go/src/v.io/x/mojo/proxy/proxy.go
index bcf27f1..a3e994d 100644
--- a/go/src/v.io/x/mojo/proxy/proxy.go
+++ b/go/src/v.io/x/mojo/proxy/proxy.go
@@ -6,6 +6,7 @@
import (
"fmt"
+ "sync"
"v.io/v23"
"v.io/v23/context"
@@ -227,7 +228,7 @@
advertisementMap map[string]uint32
}
-func (d *advertiser) Advertise(s Service, visibility []string) (*string, *string, error) {
+func (d *advertiser) Advertise(s v23proxy.Service, visibility []string) (*string, *string, error) {
mService := discovery.Service{
InstanceId: s.InstanceId,
InstanceName: s.InstanceName,
@@ -236,9 +237,9 @@
}
mService.Addrs = make([]string, len(d.endpoints))
for i, ep := range d.endpoints {
- mService.Addrs[i] = ep + "//" + s.url
+ mService.Addrs[i] = ep + "//" + s.Url
}
- handle, instance, mErr, err := d.advProxy.Advertise(mService, visibility)
+ handle, instance, mErr, err := d.advProxy.Advertise(mService, &visibility)
if err != nil {
return nil, nil, err
}
@@ -262,9 +263,11 @@
if found {
d.advProxy.Stop(id)
}
+ return nil
}
type discoveryFactory struct {
+ ctx *context.T
appContext application.Context
eps []string
stubs []*bindings.Stub
@@ -274,7 +277,7 @@
req, ptr := discovery.CreateMessagePipeForAdvertiser()
df.appContext.ConnectToApplication("https://mojo.v.io/discovery.mojo").ConnectToService(&req)
d := &advertiser{
- endpoints: eps,
+ endpoints: df.eps,
advProxy: discovery.NewAdvertiserProxy(ptr, bindings.GetAsyncWaiter()),
advertisementMap: map[string]uint32{},
}
@@ -287,7 +290,7 @@
if err := advertiserStub.ServeRequest(); err != nil {
connectionError, ok := err.(*bindings.ConnectionError)
if !ok || !connectionError.Closed() {
- delegate.ctx.Errorf("%v", err)
+ df.ctx.Errorf("%v", err)
}
return
}
@@ -330,6 +333,7 @@
status := s.Status()
fmt.Println("Listening at:", status.Endpoints[0].Name())
delegate.df = &discoveryFactory{
+ ctx: ctx,
appContext: context,
}
delegate.df.eps = make([]string, len(status.Endpoints))
diff --git a/mojom/mojom/v23proxy.mojom b/mojom/mojom/v23proxy.mojom
index 91ff8e0..e703b35 100644
--- a/mojom/mojom/v23proxy.mojom
+++ b/mojom/mojom/v23proxy.mojom
@@ -53,5 +53,5 @@
// E.g., {'resolution': '1024x768'}.
map<string, string>? Attrs;
// The url of the advertising mojo service
- string url;
+ string Url;
};