Merge branch 'master' into ble
diff --git a/.gitignore b/.gitignore
index b7e2fde..afc89b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,6 @@
-/.v23
\ No newline at end of file
+/.v23
+gen/
+out/
+go/.idea/
+.idea/
+*.iml
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2652b3f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+PWD := $(shell pwd)
+DISCOVERY_BUILD_DIR=$(PWD)/out
+
+include ../shared/mojo.mk
+
+# NOTE(nlacasse): Running Go Mojo services requires passing the
+# --enable-multiprocess flag to mojo_shell. This is because the Go runtime is
+# very large, and can interfere with C++ memory if they are in the same
+# process.
+MOJO_SHELL_FLAGS += \
+ --config-alias DISCOVERY_BUILD_DIR=$(DISCOVERY_BUILD_DIR)
+
+echo-go-path:
+ echo $(GOPATH)
+
+run-advertiser-service: $(DISCOVERY_BUILD_DIR)/driver.mojo $(DISCOVERY_BUILD_DIR)/ble.mojo
+ sudo $(MOJO_DIR)/src/mojo/devtools/common/mojo_run --config-file $(PWD)/mojoconfig $(MOJO_SHELL_FLAGS) --args-for="https://mojo.v.io/ble.mojo test" https://mojo.v.io/driver.mojo
+
+run-scanner-service: $(DISCOVERY_BUILD_DIR)/scanner.mojo $(DISCOVERY_BUILD_DIR)/ble.mojo
+ sudo $(MOJO_DIR)/src/mojo/devtools/common/mojo_run --config-file $(PWD)/mojoconfig $(MOJO_SHELL_FLAGS) --args-for="https://mojo.v.io/ble.mojo test" https://mojo.v.io/scanner.mojo
+
+all_mojom: go/src/mojom/v.io/x/ref/services/discovery/ble/mojo/ble.mojom.go go/src/mojom/v.io/x/ref/services/discovery/mojo/discovery.mojom.go
+go/src/mojom/v.io/x/ref/services/discovery/ble/mojo/ble.mojom.go: mojom/v.io/x/ref/services/discovery/ble/ble.mojom
+ $(call MOJOM_GEN,$<,.,go)
+go/src/mojom/v.io/x/ref/services/discovery/mojo/discovery.mojom.go: mojom/v.io/x/ref/services/discovery/discovery.mojom
+ $(call MOJOM_GEN,$<,.,go)
+$(DISCOVERY_BUILD_DIR)/ble.mojo: go/src/mojom/v.io/x/ref/services/discovery/ble/ble/ble.mojom.go go/src/v.io/x/ref/services/discovery/ble/neighborhood.go go/src/v.io/x/ref/services/discovery/ble/service.go $(MOJO_SHARED_LIB)
+ $(call MOGO_BUILD,v.io/x/ref/services/discovery/ble,$@)
+
+$(DISCOVERY_BUILD_DIR)/driver.mojo: go/src/mojom/v.io/x/ref/services/discovery/ble/ble/ble.mojom.go go/src/v.io/x/ref/services/discovery/driver/driver.go $(MOJO_SHARED_LIB)
+ $(call MOGO_BUILD,v.io/x/ref/services/discovery/driver,$@)
+$(DISCOVERY_BUILD_DIR)/scanner.mojo: go/src/mojom/v.io/x/ref/services/discovery/ble/ble/ble.mojom.go go/src/v.io/x/ref/services/discovery/scanner/scanner.go $(MOJO_SHARED_LIB)
+ $(call MOGO_BUILD,v.io/x/ref/services/discovery/scanner,$@)
+
diff --git a/go/src/mojom/v.io/x/ref/services/discovery/ble/ble/ble.mojom.go b/go/src/mojom/v.io/x/ref/services/discovery/ble/ble/ble.mojom.go
new file mode 100644
index 0000000..4276952
--- /dev/null
+++ b/go/src/mojom/v.io/x/ref/services/discovery/ble/ble/ble.mojom.go
@@ -0,0 +1,1393 @@
+// 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.
+
+// This file is autogenerated by:
+// mojo/public/tools/bindings/mojom_bindings_generator.py
+// For:
+// mojom/v.io/x/ref/services/discovery/ble/ble.mojom
+//
+
+package ble
+
+import (
+ "fmt"
+ "mojo/public/go/bindings"
+ "mojo/public/go/system"
+ "sort"
+)
+
+type V23Ble interface {
+ Advertise(inAdv Advertisement) (outHandler PluginStopper_Pointer, err error)
+ Scan(inId *[]uint8, inAttributes map[string]string, inHandler PluginScanHandler_Pointer) (outHandler PluginStopper_Pointer, err error)
+}
+
+var v23BLE_Name = "ble::V23BLE"
+
+type V23Ble_Request bindings.InterfaceRequest
+
+func (r *V23Ble_Request) Name() string {
+ return v23BLE_Name
+}
+
+type V23Ble_Pointer bindings.InterfacePointer
+
+func (p *V23Ble_Pointer) Name() string {
+ return v23BLE_Name
+}
+
+type V23Ble_ServiceFactory struct{
+ Delegate V23Ble_Factory
+}
+
+type V23Ble_Factory interface {
+ Create(request V23Ble_Request)
+}
+
+func (f *V23Ble_ServiceFactory) Name() string {
+ return v23BLE_Name
+}
+
+func (f *V23Ble_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+ request := V23Ble_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+ f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForV23Ble creates a message pipe for use with the
+// V23Ble interface with a V23Ble_Request on one end and a V23Ble_Pointer on the other.
+func CreateMessagePipeForV23Ble() (V23Ble_Request, V23Ble_Pointer) {
+ r, p := bindings.CreateMessagePipeForMojoInterface()
+ return V23Ble_Request(r), V23Ble_Pointer(p)
+}
+
+const v23BLE_Advertise_Name uint32 = 0
+const v23BLE_Scan_Name uint32 = 1
+
+type V23Ble_Proxy struct {
+ router *bindings.Router
+ ids bindings.Counter
+}
+
+func NewV23BleProxy(p V23Ble_Pointer, waiter bindings.AsyncWaiter) *V23Ble_Proxy {
+ return &V23Ble_Proxy{
+ bindings.NewRouter(p.PassMessagePipe(), waiter),
+ bindings.NewCounter(),
+ }
+}
+
+func (p *V23Ble_Proxy) Close_Proxy() {
+ p.router.Close()
+}
+
+type v23Ble_Advertise_Params struct {
+ inAdv Advertisement
+}
+
+func (s *v23Ble_Advertise_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := s.inAdv.Encode(encoder); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var v23Ble_Advertise_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *v23Ble_Advertise_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(v23Ble_Advertise_Params_Versions), func(i int) bool {
+ return v23Ble_Advertise_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(v23Ble_Advertise_Params_Versions) {
+ if v23Ble_Advertise_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := v23Ble_Advertise_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := s.inAdv.Decode(decoder); err != nil {
+ return err
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+type v23Ble_Advertise_ResponseParams struct {
+ outHandler PluginStopper_Pointer
+}
+
+func (s *v23Ble_Advertise_ResponseParams) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WriteInterface(s.outHandler.PassMessagePipe()); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var v23Ble_Advertise_ResponseParams_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *v23Ble_Advertise_ResponseParams) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(v23Ble_Advertise_ResponseParams_Versions), func(i int) bool {
+ return v23Ble_Advertise_ResponseParams_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(v23Ble_Advertise_ResponseParams_Versions) {
+ if v23Ble_Advertise_ResponseParams_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := v23Ble_Advertise_ResponseParams_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ handle0, err := decoder.ReadInterface()
+ if err != nil {
+ return err
+ }
+ if handle0.IsValid() {
+ handleOwner := bindings.NewMessagePipeHandleOwner(handle0)
+ s.outHandler = PluginStopper_Pointer{handleOwner}
+ } else {
+ return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"}
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *V23Ble_Proxy) Advertise(inAdv Advertisement) (outHandler PluginStopper_Pointer, err error) {
+ payload := &v23Ble_Advertise_Params{
+ inAdv,
+ }
+ header := bindings.MessageHeader{
+ Type: v23BLE_Advertise_Name,
+ Flags: bindings.MessageExpectsResponseFlag,
+ RequestId: p.ids.Count(),
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ readResult := <-p.router.AcceptWithResponse(message)
+ if err = readResult.Error; err != nil {
+ p.Close_Proxy()
+ return
+ }
+ if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag {
+ err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags),
+ }
+ return
+ }
+ if got, want := readResult.Message.Header.Type, v23BLE_Advertise_Name; got != want {
+ err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+ }
+ return
+ }
+ var response v23Ble_Advertise_ResponseParams
+ if err = readResult.Message.DecodePayload(&response); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ outHandler = response.outHandler
+ return
+}
+
+type v23Ble_Scan_Params struct {
+ inId *[]uint8
+ inAttributes map[string]string
+ inHandler PluginScanHandler_Pointer
+}
+
+func (s *v23Ble_Scan_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(24, 0)
+ if s.inId == nil {
+ encoder.WriteNullPointer()
+ } else {
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len((*s.inId))), 8)
+ for _, elem0 := range (*s.inId) {
+ if err := encoder.WriteUint8(elem0); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartMap()
+ {
+ var keys0 []string
+ var values0 []string
+ for key0, value0 := range s.inAttributes {
+ keys0 = append(keys0, key0)
+ values0 = append(values0, value0)
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(keys0)), 64)
+ for _, elem1 := range keys0 {
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(elem1); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(values0)), 64)
+ for _, elem1 := range values0 {
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(elem1); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.WriteInterface(s.inHandler.PassMessagePipe()); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var v23Ble_Scan_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{32, 0},
+}
+
+func (s *v23Ble_Scan_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(v23Ble_Scan_Params_Versions), func(i int) bool {
+ return v23Ble_Scan_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(v23Ble_Scan_Params_Versions) {
+ if v23Ble_Scan_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := v23Ble_Scan_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ s.inId = nil
+ } else {
+ s.inId = new([]uint8)
+ len0, err := decoder.StartArray(8)
+ if err != nil {
+ return err
+ }
+ (*s.inId) = make([]uint8, len0)
+ for i0 := uint32(0); i0 < len0; i0++ {
+ value1, err := decoder.ReadUint8()
+ if err != nil {
+ return err
+ }
+ (*s.inId)[i0] = value1
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := decoder.StartMap(); err != nil {
+ return err
+ }
+ var keys0 []string
+ {
+ pointer1, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer1 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len1, err := decoder.StartArray(64)
+ if err != nil {
+ return err
+ }
+ keys0 = make([]string, len1)
+ for i1 := uint32(0); i1 < len1; i1++ {
+ pointer2, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer2 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value2, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ keys0[i1] = value2
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ var values0 []string
+ {
+ pointer1, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer1 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len1, err := decoder.StartArray(64)
+ if err != nil {
+ return err
+ }
+ values0 = make([]string, len1)
+ for i1 := uint32(0); i1 < len1; i1++ {
+ pointer2, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer2 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value2, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ values0[i1] = value2
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ if len(keys0) != len(values0) {
+ return &bindings.ValidationError{bindings.DifferentSizedArraysInMap,
+ fmt.Sprintf("Number of keys %d is different from number of values %d", len(keys0), len(values0)),
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ len0 := len(keys0)
+ map0 := make(map[string]string)
+ for i0 := 0; i0 < len0; i0++ {
+ map0[keys0[i0]] = values0[i0]
+ }
+ s.inAttributes = map0
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ handle0, err := decoder.ReadInterface()
+ if err != nil {
+ return err
+ }
+ if handle0.IsValid() {
+ handleOwner := bindings.NewMessagePipeHandleOwner(handle0)
+ s.inHandler = PluginScanHandler_Pointer{handleOwner}
+ } else {
+ return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"}
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+type v23Ble_Scan_ResponseParams struct {
+ outHandler PluginStopper_Pointer
+}
+
+func (s *v23Ble_Scan_ResponseParams) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WriteInterface(s.outHandler.PassMessagePipe()); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var v23Ble_Scan_ResponseParams_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *v23Ble_Scan_ResponseParams) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(v23Ble_Scan_ResponseParams_Versions), func(i int) bool {
+ return v23Ble_Scan_ResponseParams_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(v23Ble_Scan_ResponseParams_Versions) {
+ if v23Ble_Scan_ResponseParams_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := v23Ble_Scan_ResponseParams_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ handle0, err := decoder.ReadInterface()
+ if err != nil {
+ return err
+ }
+ if handle0.IsValid() {
+ handleOwner := bindings.NewMessagePipeHandleOwner(handle0)
+ s.outHandler = PluginStopper_Pointer{handleOwner}
+ } else {
+ return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"}
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *V23Ble_Proxy) Scan(inId *[]uint8, inAttributes map[string]string, inHandler PluginScanHandler_Pointer) (outHandler PluginStopper_Pointer, err error) {
+ payload := &v23Ble_Scan_Params{
+ inId,
+ inAttributes,
+ inHandler,
+ }
+ header := bindings.MessageHeader{
+ Type: v23BLE_Scan_Name,
+ Flags: bindings.MessageExpectsResponseFlag,
+ RequestId: p.ids.Count(),
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ readResult := <-p.router.AcceptWithResponse(message)
+ if err = readResult.Error; err != nil {
+ p.Close_Proxy()
+ return
+ }
+ if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag {
+ err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags),
+ }
+ return
+ }
+ if got, want := readResult.Message.Header.Type, v23BLE_Scan_Name; got != want {
+ err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+ }
+ return
+ }
+ var response v23Ble_Scan_ResponseParams
+ if err = readResult.Message.DecodePayload(&response); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ outHandler = response.outHandler
+ return
+}
+
+type v23BLE_Stub struct {
+ connector *bindings.Connector
+ impl V23Ble
+}
+
+func NewV23BleStub(r V23Ble_Request, impl V23Ble, waiter bindings.AsyncWaiter) *bindings.Stub {
+ connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+ return bindings.NewStub(connector, &v23BLE_Stub{connector, impl})
+}
+
+func (s *v23BLE_Stub) Accept(message *bindings.Message) (err error) {
+ switch message.Header.Type {
+ case v23BLE_Advertise_Name:
+ if message.Header.Flags != bindings.MessageExpectsResponseFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request v23Ble_Advertise_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ var response v23Ble_Advertise_ResponseParams
+ response.outHandler, err = s.impl.Advertise(request.inAdv)
+ if err != nil {
+ return
+ }
+ header := bindings.MessageHeader{
+ Type: v23BLE_Advertise_Name,
+ Flags: bindings.MessageIsResponseFlag,
+ RequestId: message.Header.RequestId,
+ }
+ message, err = bindings.EncodeMessage(header, &response)
+ if err != nil {
+ return err
+ }
+ return s.connector.WriteMessage(message)
+ case v23BLE_Scan_Name:
+ if message.Header.Flags != bindings.MessageExpectsResponseFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request v23Ble_Scan_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ var response v23Ble_Scan_ResponseParams
+ response.outHandler, err = s.impl.Scan(request.inId, request.inAttributes, request.inHandler)
+ if err != nil {
+ return
+ }
+ header := bindings.MessageHeader{
+ Type: v23BLE_Scan_Name,
+ Flags: bindings.MessageIsResponseFlag,
+ RequestId: message.Header.RequestId,
+ }
+ message, err = bindings.EncodeMessage(header, &response)
+ if err != nil {
+ return err
+ }
+ return s.connector.WriteMessage(message)
+ default:
+ return &bindings.ValidationError{
+ bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("unknown method %v", message.Header.Type),
+ }
+ }
+ return
+}
+
+type PluginScanHandler interface {
+ Found(inS Advertisement) (err error)
+ Lost(inS Advertisement) (err error)
+}
+
+var pluginScanHandler_Name = "ble::PluginScanHandler"
+
+type PluginScanHandler_Request bindings.InterfaceRequest
+
+func (r *PluginScanHandler_Request) Name() string {
+ return pluginScanHandler_Name
+}
+
+type PluginScanHandler_Pointer bindings.InterfacePointer
+
+func (p *PluginScanHandler_Pointer) Name() string {
+ return pluginScanHandler_Name
+}
+
+type PluginScanHandler_ServiceFactory struct{
+ Delegate PluginScanHandler_Factory
+}
+
+type PluginScanHandler_Factory interface {
+ Create(request PluginScanHandler_Request)
+}
+
+func (f *PluginScanHandler_ServiceFactory) Name() string {
+ return pluginScanHandler_Name
+}
+
+func (f *PluginScanHandler_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+ request := PluginScanHandler_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+ f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForPluginScanHandler creates a message pipe for use with the
+// PluginScanHandler interface with a PluginScanHandler_Request on one end and a PluginScanHandler_Pointer on the other.
+func CreateMessagePipeForPluginScanHandler() (PluginScanHandler_Request, PluginScanHandler_Pointer) {
+ r, p := bindings.CreateMessagePipeForMojoInterface()
+ return PluginScanHandler_Request(r), PluginScanHandler_Pointer(p)
+}
+
+const pluginScanHandler_Found_Name uint32 = 0
+const pluginScanHandler_Lost_Name uint32 = 1
+
+type PluginScanHandler_Proxy struct {
+ router *bindings.Router
+ ids bindings.Counter
+}
+
+func NewPluginScanHandlerProxy(p PluginScanHandler_Pointer, waiter bindings.AsyncWaiter) *PluginScanHandler_Proxy {
+ return &PluginScanHandler_Proxy{
+ bindings.NewRouter(p.PassMessagePipe(), waiter),
+ bindings.NewCounter(),
+ }
+}
+
+func (p *PluginScanHandler_Proxy) Close_Proxy() {
+ p.router.Close()
+}
+
+type pluginScanHandler_Found_Params struct {
+ inS Advertisement
+}
+
+func (s *pluginScanHandler_Found_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := s.inS.Encode(encoder); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var pluginScanHandler_Found_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *pluginScanHandler_Found_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(pluginScanHandler_Found_Params_Versions), func(i int) bool {
+ return pluginScanHandler_Found_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(pluginScanHandler_Found_Params_Versions) {
+ if pluginScanHandler_Found_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := pluginScanHandler_Found_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := s.inS.Decode(decoder); err != nil {
+ return err
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *PluginScanHandler_Proxy) Found(inS Advertisement) (err error) {
+ payload := &pluginScanHandler_Found_Params{
+ inS,
+ }
+ header := bindings.MessageHeader{
+ Type: pluginScanHandler_Found_Name,
+ Flags: bindings.MessageNoFlag,
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ if err = p.router.Accept(message); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ return
+}
+
+type pluginScanHandler_Lost_Params struct {
+ inS Advertisement
+}
+
+func (s *pluginScanHandler_Lost_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := s.inS.Encode(encoder); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var pluginScanHandler_Lost_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *pluginScanHandler_Lost_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(pluginScanHandler_Lost_Params_Versions), func(i int) bool {
+ return pluginScanHandler_Lost_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(pluginScanHandler_Lost_Params_Versions) {
+ if pluginScanHandler_Lost_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := pluginScanHandler_Lost_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := s.inS.Decode(decoder); err != nil {
+ return err
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *PluginScanHandler_Proxy) Lost(inS Advertisement) (err error) {
+ payload := &pluginScanHandler_Lost_Params{
+ inS,
+ }
+ header := bindings.MessageHeader{
+ Type: pluginScanHandler_Lost_Name,
+ Flags: bindings.MessageNoFlag,
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ if err = p.router.Accept(message); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ return
+}
+
+type pluginScanHandler_Stub struct {
+ connector *bindings.Connector
+ impl PluginScanHandler
+}
+
+func NewPluginScanHandlerStub(r PluginScanHandler_Request, impl PluginScanHandler, waiter bindings.AsyncWaiter) *bindings.Stub {
+ connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+ return bindings.NewStub(connector, &pluginScanHandler_Stub{connector, impl})
+}
+
+func (s *pluginScanHandler_Stub) Accept(message *bindings.Message) (err error) {
+ switch message.Header.Type {
+ case pluginScanHandler_Found_Name:
+ if message.Header.Flags != bindings.MessageNoFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request pluginScanHandler_Found_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ err = s.impl.Found(request.inS)
+ if err != nil {
+ return
+ }
+ case pluginScanHandler_Lost_Name:
+ if message.Header.Flags != bindings.MessageNoFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request pluginScanHandler_Lost_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ err = s.impl.Lost(request.inS)
+ if err != nil {
+ return
+ }
+ default:
+ return &bindings.ValidationError{
+ bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("unknown method %v", message.Header.Type),
+ }
+ }
+ return
+}
+
+type PluginStopper interface {
+ Stop() (err error)
+}
+
+var pluginStopper_Name = "ble::PluginStopper"
+
+type PluginStopper_Request bindings.InterfaceRequest
+
+func (r *PluginStopper_Request) Name() string {
+ return pluginStopper_Name
+}
+
+type PluginStopper_Pointer bindings.InterfacePointer
+
+func (p *PluginStopper_Pointer) Name() string {
+ return pluginStopper_Name
+}
+
+type PluginStopper_ServiceFactory struct{
+ Delegate PluginStopper_Factory
+}
+
+type PluginStopper_Factory interface {
+ Create(request PluginStopper_Request)
+}
+
+func (f *PluginStopper_ServiceFactory) Name() string {
+ return pluginStopper_Name
+}
+
+func (f *PluginStopper_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+ request := PluginStopper_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+ f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForPluginStopper creates a message pipe for use with the
+// PluginStopper interface with a PluginStopper_Request on one end and a PluginStopper_Pointer on the other.
+func CreateMessagePipeForPluginStopper() (PluginStopper_Request, PluginStopper_Pointer) {
+ r, p := bindings.CreateMessagePipeForMojoInterface()
+ return PluginStopper_Request(r), PluginStopper_Pointer(p)
+}
+
+const pluginStopper_Stop_Name uint32 = 0
+
+type PluginStopper_Proxy struct {
+ router *bindings.Router
+ ids bindings.Counter
+}
+
+func NewPluginStopperProxy(p PluginStopper_Pointer, waiter bindings.AsyncWaiter) *PluginStopper_Proxy {
+ return &PluginStopper_Proxy{
+ bindings.NewRouter(p.PassMessagePipe(), waiter),
+ bindings.NewCounter(),
+ }
+}
+
+func (p *PluginStopper_Proxy) Close_Proxy() {
+ p.router.Close()
+}
+
+type pluginStopper_Stop_Params struct {
+}
+
+func (s *pluginStopper_Stop_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(0, 0)
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var pluginStopper_Stop_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{8, 0},
+}
+
+func (s *pluginStopper_Stop_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(pluginStopper_Stop_Params_Versions), func(i int) bool {
+ return pluginStopper_Stop_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(pluginStopper_Stop_Params_Versions) {
+ if pluginStopper_Stop_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := pluginStopper_Stop_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *PluginStopper_Proxy) Stop() (err error) {
+ payload := &pluginStopper_Stop_Params{
+ }
+ header := bindings.MessageHeader{
+ Type: pluginStopper_Stop_Name,
+ Flags: bindings.MessageNoFlag,
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ if err = p.router.Accept(message); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ return
+}
+
+type pluginStopper_Stub struct {
+ connector *bindings.Connector
+ impl PluginStopper
+}
+
+func NewPluginStopperStub(r PluginStopper_Request, impl PluginStopper, waiter bindings.AsyncWaiter) *bindings.Stub {
+ connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+ return bindings.NewStub(connector, &pluginStopper_Stub{connector, impl})
+}
+
+func (s *pluginStopper_Stub) Accept(message *bindings.Message) (err error) {
+ switch message.Header.Type {
+ case pluginStopper_Stop_Name:
+ if message.Header.Flags != bindings.MessageNoFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request pluginStopper_Stop_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ err = s.impl.Stop()
+ if err != nil {
+ return
+ }
+ default:
+ return &bindings.ValidationError{
+ bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("unknown method %v", message.Header.Type),
+ }
+ }
+ return
+}
+
+type Advertisement struct {
+ ServiceId []uint8
+ Service Service
+}
+
+func (s *Advertisement) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(16, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(s.ServiceId)), 8)
+ for _, elem0 := range s.ServiceId {
+ if err := encoder.WriteUint8(elem0); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := s.Service.Encode(encoder); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var advertisement_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{24, 0},
+}
+
+func (s *Advertisement) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(advertisement_Versions), func(i int) bool {
+ return advertisement_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(advertisement_Versions) {
+ if advertisement_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := advertisement_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len0, err := decoder.StartArray(8)
+ if err != nil {
+ return err
+ }
+ s.ServiceId = make([]uint8, len0)
+ for i0 := uint32(0); i0 < len0; i0++ {
+ value1, err := decoder.ReadUint8()
+ if err != nil {
+ return err
+ }
+ s.ServiceId[i0] = value1
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := s.Service.Decode(decoder); err != nil {
+ return err
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+type Service struct {
+ InstanceId []uint8
+ Attributes map[string]string
+}
+
+func (s *Service) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(16, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(s.InstanceId)), 8)
+ for _, elem0 := range s.InstanceId {
+ if err := encoder.WriteUint8(elem0); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartMap()
+ {
+ var keys0 []string
+ var values0 []string
+ for key0, value0 := range s.Attributes {
+ keys0 = append(keys0, key0)
+ values0 = append(values0, value0)
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(keys0)), 64)
+ for _, elem1 := range keys0 {
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(elem1); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(values0)), 64)
+ for _, elem1 := range values0 {
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(elem1); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var service_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{24, 0},
+}
+
+func (s *Service) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(service_Versions), func(i int) bool {
+ return service_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(service_Versions) {
+ if service_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := service_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len0, err := decoder.StartArray(8)
+ if err != nil {
+ return err
+ }
+ s.InstanceId = make([]uint8, len0)
+ for i0 := uint32(0); i0 < len0; i0++ {
+ value1, err := decoder.ReadUint8()
+ if err != nil {
+ return err
+ }
+ s.InstanceId[i0] = value1
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := decoder.StartMap(); err != nil {
+ return err
+ }
+ var keys0 []string
+ {
+ pointer1, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer1 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len1, err := decoder.StartArray(64)
+ if err != nil {
+ return err
+ }
+ keys0 = make([]string, len1)
+ for i1 := uint32(0); i1 < len1; i1++ {
+ pointer2, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer2 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value2, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ keys0[i1] = value2
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ var values0 []string
+ {
+ pointer1, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer1 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len1, err := decoder.StartArray(64)
+ if err != nil {
+ return err
+ }
+ values0 = make([]string, len1)
+ for i1 := uint32(0); i1 < len1; i1++ {
+ pointer2, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer2 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value2, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ values0[i1] = value2
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ if len(keys0) != len(values0) {
+ return &bindings.ValidationError{bindings.DifferentSizedArraysInMap,
+ fmt.Sprintf("Number of keys %d is different from number of values %d", len(keys0), len(values0)),
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ len0 := len(keys0)
+ map0 := make(map[string]string)
+ for i0 := 0; i0 < len0; i0++ {
+ map0[keys0[i0]] = values0[i0]
+ }
+ s.Attributes = map0
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
diff --git a/go/src/mojom/v.io/x/ref/services/discovery/discovery/discovery.mojom.go b/go/src/mojom/v.io/x/ref/services/discovery/discovery/discovery.mojom.go
new file mode 100644
index 0000000..9ad87c7
--- /dev/null
+++ b/go/src/mojom/v.io/x/ref/services/discovery/discovery/discovery.mojom.go
@@ -0,0 +1,1183 @@
+// 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.
+
+// This file is autogenerated by:
+// mojo/public/tools/bindings/mojom_bindings_generator.py
+// For:
+// mojom/v.io/x/ref/services/discovery/discovery.mojom
+//
+
+package discovery
+
+import (
+ "fmt"
+ "mojo/public/go/bindings"
+ "mojo/public/go/system"
+ "sort"
+)
+
+type Discovery interface {
+ Advertise(inService Service) (outHandle DiscoveryStopper_Pointer, err error)
+ Scan(inQuery string, inHandler DiscoveryHandler_Pointer) (outHandle DiscoveryStopper_Pointer, err error)
+}
+
+var discovery_Name = "discovery::Discovery"
+
+type Discovery_Request bindings.InterfaceRequest
+
+func (r *Discovery_Request) Name() string {
+ return discovery_Name
+}
+
+type Discovery_Pointer bindings.InterfacePointer
+
+func (p *Discovery_Pointer) Name() string {
+ return discovery_Name
+}
+
+type Discovery_ServiceFactory struct{
+ Delegate Discovery_Factory
+}
+
+type Discovery_Factory interface {
+ Create(request Discovery_Request)
+}
+
+func (f *Discovery_ServiceFactory) Name() string {
+ return discovery_Name
+}
+
+func (f *Discovery_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+ request := Discovery_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+ f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForDiscovery creates a message pipe for use with the
+// Discovery interface with a Discovery_Request on one end and a Discovery_Pointer on the other.
+func CreateMessagePipeForDiscovery() (Discovery_Request, Discovery_Pointer) {
+ r, p := bindings.CreateMessagePipeForMojoInterface()
+ return Discovery_Request(r), Discovery_Pointer(p)
+}
+
+const discovery_Advertise_Name uint32 = 0
+const discovery_Scan_Name uint32 = 1
+
+type Discovery_Proxy struct {
+ router *bindings.Router
+ ids bindings.Counter
+}
+
+func NewDiscoveryProxy(p Discovery_Pointer, waiter bindings.AsyncWaiter) *Discovery_Proxy {
+ return &Discovery_Proxy{
+ bindings.NewRouter(p.PassMessagePipe(), waiter),
+ bindings.NewCounter(),
+ }
+}
+
+func (p *Discovery_Proxy) Close_Proxy() {
+ p.router.Close()
+}
+
+type discovery_Advertise_Params struct {
+ inService Service
+}
+
+func (s *discovery_Advertise_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := s.inService.Encode(encoder); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var discovery_Advertise_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *discovery_Advertise_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(discovery_Advertise_Params_Versions), func(i int) bool {
+ return discovery_Advertise_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(discovery_Advertise_Params_Versions) {
+ if discovery_Advertise_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := discovery_Advertise_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := s.inService.Decode(decoder); err != nil {
+ return err
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+type discovery_Advertise_ResponseParams struct {
+ outHandle DiscoveryStopper_Pointer
+}
+
+func (s *discovery_Advertise_ResponseParams) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WriteInterface(s.outHandle.PassMessagePipe()); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var discovery_Advertise_ResponseParams_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *discovery_Advertise_ResponseParams) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(discovery_Advertise_ResponseParams_Versions), func(i int) bool {
+ return discovery_Advertise_ResponseParams_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(discovery_Advertise_ResponseParams_Versions) {
+ if discovery_Advertise_ResponseParams_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := discovery_Advertise_ResponseParams_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ handle0, err := decoder.ReadInterface()
+ if err != nil {
+ return err
+ }
+ if handle0.IsValid() {
+ handleOwner := bindings.NewMessagePipeHandleOwner(handle0)
+ s.outHandle = DiscoveryStopper_Pointer{handleOwner}
+ } else {
+ return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"}
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *Discovery_Proxy) Advertise(inService Service) (outHandle DiscoveryStopper_Pointer, err error) {
+ payload := &discovery_Advertise_Params{
+ inService,
+ }
+ header := bindings.MessageHeader{
+ Type: discovery_Advertise_Name,
+ Flags: bindings.MessageExpectsResponseFlag,
+ RequestId: p.ids.Count(),
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ readResult := <-p.router.AcceptWithResponse(message)
+ if err = readResult.Error; err != nil {
+ p.Close_Proxy()
+ return
+ }
+ if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag {
+ err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags),
+ }
+ return
+ }
+ if got, want := readResult.Message.Header.Type, discovery_Advertise_Name; got != want {
+ err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+ }
+ return
+ }
+ var response discovery_Advertise_ResponseParams
+ if err = readResult.Message.DecodePayload(&response); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ outHandle = response.outHandle
+ return
+}
+
+type discovery_Scan_Params struct {
+ inQuery string
+ inHandler DiscoveryHandler_Pointer
+}
+
+func (s *discovery_Scan_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(16, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(s.inQuery); err != nil {
+ return err
+ }
+ if err := encoder.WriteInterface(s.inHandler.PassMessagePipe()); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var discovery_Scan_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{24, 0},
+}
+
+func (s *discovery_Scan_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(discovery_Scan_Params_Versions), func(i int) bool {
+ return discovery_Scan_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(discovery_Scan_Params_Versions) {
+ if discovery_Scan_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := discovery_Scan_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value0, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ s.inQuery = value0
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ handle0, err := decoder.ReadInterface()
+ if err != nil {
+ return err
+ }
+ if handle0.IsValid() {
+ handleOwner := bindings.NewMessagePipeHandleOwner(handle0)
+ s.inHandler = DiscoveryHandler_Pointer{handleOwner}
+ } else {
+ return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"}
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+type discovery_Scan_ResponseParams struct {
+ outHandle DiscoveryStopper_Pointer
+}
+
+func (s *discovery_Scan_ResponseParams) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WriteInterface(s.outHandle.PassMessagePipe()); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var discovery_Scan_ResponseParams_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *discovery_Scan_ResponseParams) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(discovery_Scan_ResponseParams_Versions), func(i int) bool {
+ return discovery_Scan_ResponseParams_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(discovery_Scan_ResponseParams_Versions) {
+ if discovery_Scan_ResponseParams_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := discovery_Scan_ResponseParams_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ handle0, err := decoder.ReadInterface()
+ if err != nil {
+ return err
+ }
+ if handle0.IsValid() {
+ handleOwner := bindings.NewMessagePipeHandleOwner(handle0)
+ s.outHandle = DiscoveryStopper_Pointer{handleOwner}
+ } else {
+ return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"}
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *Discovery_Proxy) Scan(inQuery string, inHandler DiscoveryHandler_Pointer) (outHandle DiscoveryStopper_Pointer, err error) {
+ payload := &discovery_Scan_Params{
+ inQuery,
+ inHandler,
+ }
+ header := bindings.MessageHeader{
+ Type: discovery_Scan_Name,
+ Flags: bindings.MessageExpectsResponseFlag,
+ RequestId: p.ids.Count(),
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ readResult := <-p.router.AcceptWithResponse(message)
+ if err = readResult.Error; err != nil {
+ p.Close_Proxy()
+ return
+ }
+ if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag {
+ err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags),
+ }
+ return
+ }
+ if got, want := readResult.Message.Header.Type, discovery_Scan_Name; got != want {
+ err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+ }
+ return
+ }
+ var response discovery_Scan_ResponseParams
+ if err = readResult.Message.DecodePayload(&response); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ outHandle = response.outHandle
+ return
+}
+
+type discovery_Stub struct {
+ connector *bindings.Connector
+ impl Discovery
+}
+
+func NewDiscoveryStub(r Discovery_Request, impl Discovery, waiter bindings.AsyncWaiter) *bindings.Stub {
+ connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+ return bindings.NewStub(connector, &discovery_Stub{connector, impl})
+}
+
+func (s *discovery_Stub) Accept(message *bindings.Message) (err error) {
+ switch message.Header.Type {
+ case discovery_Advertise_Name:
+ if message.Header.Flags != bindings.MessageExpectsResponseFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request discovery_Advertise_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ var response discovery_Advertise_ResponseParams
+ response.outHandle, err = s.impl.Advertise(request.inService)
+ if err != nil {
+ return
+ }
+ header := bindings.MessageHeader{
+ Type: discovery_Advertise_Name,
+ Flags: bindings.MessageIsResponseFlag,
+ RequestId: message.Header.RequestId,
+ }
+ message, err = bindings.EncodeMessage(header, &response)
+ if err != nil {
+ return err
+ }
+ return s.connector.WriteMessage(message)
+ case discovery_Scan_Name:
+ if message.Header.Flags != bindings.MessageExpectsResponseFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request discovery_Scan_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ var response discovery_Scan_ResponseParams
+ response.outHandle, err = s.impl.Scan(request.inQuery, request.inHandler)
+ if err != nil {
+ return
+ }
+ header := bindings.MessageHeader{
+ Type: discovery_Scan_Name,
+ Flags: bindings.MessageIsResponseFlag,
+ RequestId: message.Header.RequestId,
+ }
+ message, err = bindings.EncodeMessage(header, &response)
+ if err != nil {
+ return err
+ }
+ return s.connector.WriteMessage(message)
+ default:
+ return &bindings.ValidationError{
+ bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("unknown method %v", message.Header.Type),
+ }
+ }
+ return
+}
+
+type DiscoveryStopper interface {
+ Stop() (err error)
+}
+
+var discoveryStopper_Name = "discovery::DiscoveryStopper"
+
+type DiscoveryStopper_Request bindings.InterfaceRequest
+
+func (r *DiscoveryStopper_Request) Name() string {
+ return discoveryStopper_Name
+}
+
+type DiscoveryStopper_Pointer bindings.InterfacePointer
+
+func (p *DiscoveryStopper_Pointer) Name() string {
+ return discoveryStopper_Name
+}
+
+type DiscoveryStopper_ServiceFactory struct{
+ Delegate DiscoveryStopper_Factory
+}
+
+type DiscoveryStopper_Factory interface {
+ Create(request DiscoveryStopper_Request)
+}
+
+func (f *DiscoveryStopper_ServiceFactory) Name() string {
+ return discoveryStopper_Name
+}
+
+func (f *DiscoveryStopper_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+ request := DiscoveryStopper_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+ f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForDiscoveryStopper creates a message pipe for use with the
+// DiscoveryStopper interface with a DiscoveryStopper_Request on one end and a DiscoveryStopper_Pointer on the other.
+func CreateMessagePipeForDiscoveryStopper() (DiscoveryStopper_Request, DiscoveryStopper_Pointer) {
+ r, p := bindings.CreateMessagePipeForMojoInterface()
+ return DiscoveryStopper_Request(r), DiscoveryStopper_Pointer(p)
+}
+
+const discoveryStopper_Stop_Name uint32 = 0
+
+type DiscoveryStopper_Proxy struct {
+ router *bindings.Router
+ ids bindings.Counter
+}
+
+func NewDiscoveryStopperProxy(p DiscoveryStopper_Pointer, waiter bindings.AsyncWaiter) *DiscoveryStopper_Proxy {
+ return &DiscoveryStopper_Proxy{
+ bindings.NewRouter(p.PassMessagePipe(), waiter),
+ bindings.NewCounter(),
+ }
+}
+
+func (p *DiscoveryStopper_Proxy) Close_Proxy() {
+ p.router.Close()
+}
+
+type discoveryStopper_Stop_Params struct {
+}
+
+func (s *discoveryStopper_Stop_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(0, 0)
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var discoveryStopper_Stop_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{8, 0},
+}
+
+func (s *discoveryStopper_Stop_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(discoveryStopper_Stop_Params_Versions), func(i int) bool {
+ return discoveryStopper_Stop_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(discoveryStopper_Stop_Params_Versions) {
+ if discoveryStopper_Stop_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := discoveryStopper_Stop_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *DiscoveryStopper_Proxy) Stop() (err error) {
+ payload := &discoveryStopper_Stop_Params{
+ }
+ header := bindings.MessageHeader{
+ Type: discoveryStopper_Stop_Name,
+ Flags: bindings.MessageNoFlag,
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ if err = p.router.Accept(message); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ return
+}
+
+type discoveryStopper_Stub struct {
+ connector *bindings.Connector
+ impl DiscoveryStopper
+}
+
+func NewDiscoveryStopperStub(r DiscoveryStopper_Request, impl DiscoveryStopper, waiter bindings.AsyncWaiter) *bindings.Stub {
+ connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+ return bindings.NewStub(connector, &discoveryStopper_Stub{connector, impl})
+}
+
+func (s *discoveryStopper_Stub) Accept(message *bindings.Message) (err error) {
+ switch message.Header.Type {
+ case discoveryStopper_Stop_Name:
+ if message.Header.Flags != bindings.MessageNoFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request discoveryStopper_Stop_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ err = s.impl.Stop()
+ if err != nil {
+ return
+ }
+ default:
+ return &bindings.ValidationError{
+ bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("unknown method %v", message.Header.Type),
+ }
+ }
+ return
+}
+
+type DiscoveryHandler interface {
+ Found(inS Service) (err error)
+ Lost(inId []uint8) (err error)
+}
+
+var discoveryHandler_Name = "discovery::DiscoveryHandler"
+
+type DiscoveryHandler_Request bindings.InterfaceRequest
+
+func (r *DiscoveryHandler_Request) Name() string {
+ return discoveryHandler_Name
+}
+
+type DiscoveryHandler_Pointer bindings.InterfacePointer
+
+func (p *DiscoveryHandler_Pointer) Name() string {
+ return discoveryHandler_Name
+}
+
+type DiscoveryHandler_ServiceFactory struct{
+ Delegate DiscoveryHandler_Factory
+}
+
+type DiscoveryHandler_Factory interface {
+ Create(request DiscoveryHandler_Request)
+}
+
+func (f *DiscoveryHandler_ServiceFactory) Name() string {
+ return discoveryHandler_Name
+}
+
+func (f *DiscoveryHandler_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+ request := DiscoveryHandler_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+ f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForDiscoveryHandler creates a message pipe for use with the
+// DiscoveryHandler interface with a DiscoveryHandler_Request on one end and a DiscoveryHandler_Pointer on the other.
+func CreateMessagePipeForDiscoveryHandler() (DiscoveryHandler_Request, DiscoveryHandler_Pointer) {
+ r, p := bindings.CreateMessagePipeForMojoInterface()
+ return DiscoveryHandler_Request(r), DiscoveryHandler_Pointer(p)
+}
+
+const discoveryHandler_Found_Name uint32 = 0
+const discoveryHandler_Lost_Name uint32 = 1
+
+type DiscoveryHandler_Proxy struct {
+ router *bindings.Router
+ ids bindings.Counter
+}
+
+func NewDiscoveryHandlerProxy(p DiscoveryHandler_Pointer, waiter bindings.AsyncWaiter) *DiscoveryHandler_Proxy {
+ return &DiscoveryHandler_Proxy{
+ bindings.NewRouter(p.PassMessagePipe(), waiter),
+ bindings.NewCounter(),
+ }
+}
+
+func (p *DiscoveryHandler_Proxy) Close_Proxy() {
+ p.router.Close()
+}
+
+type discoveryHandler_Found_Params struct {
+ inS Service
+}
+
+func (s *discoveryHandler_Found_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := s.inS.Encode(encoder); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var discoveryHandler_Found_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *discoveryHandler_Found_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(discoveryHandler_Found_Params_Versions), func(i int) bool {
+ return discoveryHandler_Found_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(discoveryHandler_Found_Params_Versions) {
+ if discoveryHandler_Found_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := discoveryHandler_Found_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := s.inS.Decode(decoder); err != nil {
+ return err
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *DiscoveryHandler_Proxy) Found(inS Service) (err error) {
+ payload := &discoveryHandler_Found_Params{
+ inS,
+ }
+ header := bindings.MessageHeader{
+ Type: discoveryHandler_Found_Name,
+ Flags: bindings.MessageNoFlag,
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ if err = p.router.Accept(message); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ return
+}
+
+type discoveryHandler_Lost_Params struct {
+ inId []uint8
+}
+
+func (s *discoveryHandler_Lost_Params) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(8, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(s.inId)), 8)
+ for _, elem0 := range s.inId {
+ if err := encoder.WriteUint8(elem0); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var discoveryHandler_Lost_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{16, 0},
+}
+
+func (s *discoveryHandler_Lost_Params) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(discoveryHandler_Lost_Params_Versions), func(i int) bool {
+ return discoveryHandler_Lost_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(discoveryHandler_Lost_Params_Versions) {
+ if discoveryHandler_Lost_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := discoveryHandler_Lost_Params_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len0, err := decoder.StartArray(8)
+ if err != nil {
+ return err
+ }
+ s.inId = make([]uint8, len0)
+ for i0 := uint32(0); i0 < len0; i0++ {
+ value1, err := decoder.ReadUint8()
+ if err != nil {
+ return err
+ }
+ s.inId[i0] = value1
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *DiscoveryHandler_Proxy) Lost(inId []uint8) (err error) {
+ payload := &discoveryHandler_Lost_Params{
+ inId,
+ }
+ header := bindings.MessageHeader{
+ Type: discoveryHandler_Lost_Name,
+ Flags: bindings.MessageNoFlag,
+ }
+ var message *bindings.Message
+ if message, err = bindings.EncodeMessage(header, payload); err != nil {
+ err = fmt.Errorf("can't encode request: %v", err.Error())
+ p.Close_Proxy()
+ return
+ }
+ if err = p.router.Accept(message); err != nil {
+ p.Close_Proxy()
+ return
+ }
+ return
+}
+
+type discoveryHandler_Stub struct {
+ connector *bindings.Connector
+ impl DiscoveryHandler
+}
+
+func NewDiscoveryHandlerStub(r DiscoveryHandler_Request, impl DiscoveryHandler, waiter bindings.AsyncWaiter) *bindings.Stub {
+ connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+ return bindings.NewStub(connector, &discoveryHandler_Stub{connector, impl})
+}
+
+func (s *discoveryHandler_Stub) Accept(message *bindings.Message) (err error) {
+ switch message.Header.Type {
+ case discoveryHandler_Found_Name:
+ if message.Header.Flags != bindings.MessageNoFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request discoveryHandler_Found_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ err = s.impl.Found(request.inS)
+ if err != nil {
+ return
+ }
+ case discoveryHandler_Lost_Name:
+ if message.Header.Flags != bindings.MessageNoFlag {
+ return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+ fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+ }
+ }
+ var request discoveryHandler_Lost_Params
+ if err := message.DecodePayload(&request); err != nil {
+ return err
+ }
+ err = s.impl.Lost(request.inId)
+ if err != nil {
+ return
+ }
+ default:
+ return &bindings.ValidationError{
+ bindings.MessageHeaderUnknownMethod,
+ fmt.Sprintf("unknown method %v", message.Header.Type),
+ }
+ }
+ return
+}
+
+type Service struct {
+ InterfaceNames string
+ Attrs map[string]string
+ Addrs []string
+}
+
+func (s *Service) Encode(encoder *bindings.Encoder) error {
+ encoder.StartStruct(24, 0)
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(s.InterfaceNames); err != nil {
+ return err
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartMap()
+ {
+ var keys0 []string
+ var values0 []string
+ for key0, value0 := range s.Attrs {
+ keys0 = append(keys0, key0)
+ values0 = append(values0, value0)
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(keys0)), 64)
+ for _, elem1 := range keys0 {
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(elem1); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(values0)), 64)
+ for _, elem1 := range values0 {
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(elem1); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ encoder.StartArray(uint32(len(s.Addrs)), 64)
+ for _, elem0 := range s.Addrs {
+ if err := encoder.WritePointer(); err != nil {
+ return err
+ }
+ if err := encoder.WriteString(elem0); err != nil {
+ return err
+ }
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ if err := encoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
+var service_Versions []bindings.DataHeader = []bindings.DataHeader{
+ bindings.DataHeader{32, 0},
+}
+
+func (s *Service) Decode(decoder *bindings.Decoder) error {
+ header, err := decoder.StartStruct()
+ if err != nil {
+ return err
+ }
+ index := sort.Search(len(service_Versions), func(i int) bool {
+ return service_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+ })
+ if index < len(service_Versions) {
+ if service_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+ index--
+ }
+ expectedSize := service_Versions[index].Size
+ if expectedSize != header.Size {
+ return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+ fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+ }
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value0, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ s.InterfaceNames = value0
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ if err := decoder.StartMap(); err != nil {
+ return err
+ }
+ var keys0 []string
+ {
+ pointer1, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer1 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len1, err := decoder.StartArray(64)
+ if err != nil {
+ return err
+ }
+ keys0 = make([]string, len1)
+ for i1 := uint32(0); i1 < len1; i1++ {
+ pointer2, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer2 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value2, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ keys0[i1] = value2
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ var values0 []string
+ {
+ pointer1, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer1 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len1, err := decoder.StartArray(64)
+ if err != nil {
+ return err
+ }
+ values0 = make([]string, len1)
+ for i1 := uint32(0); i1 < len1; i1++ {
+ pointer2, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer2 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value2, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ values0[i1] = value2
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ if len(keys0) != len(values0) {
+ return &bindings.ValidationError{bindings.DifferentSizedArraysInMap,
+ fmt.Sprintf("Number of keys %d is different from number of values %d", len(keys0), len(values0)),
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ len0 := len(keys0)
+ map0 := make(map[string]string)
+ for i0 := 0; i0 < len0; i0++ {
+ map0[keys0[i0]] = values0[i0]
+ }
+ s.Attrs = map0
+ }
+ }
+ if header.ElementsOrVersion >= 0 {
+ pointer0, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer0 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ len0, err := decoder.StartArray(64)
+ if err != nil {
+ return err
+ }
+ s.Addrs = make([]string, len0)
+ for i0 := uint32(0); i0 < len0; i0++ {
+ pointer1, err := decoder.ReadPointer()
+ if err != nil {
+ return err
+ }
+ if pointer1 == 0 {
+ return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+ } else {
+ value1, err := decoder.ReadString()
+ if err != nil {
+ return err
+ }
+ s.Addrs[i0] = value1
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ }
+ }
+ if err := decoder.Finish(); err != nil {
+ return err
+ }
+ return nil
+}
+
diff --git a/go/src/v.io/x/ref/services/discovery/ble/neighborhood.go b/go/src/v.io/x/ref/services/discovery/ble/neighborhood.go
new file mode 100644
index 0000000..301316a
--- /dev/null
+++ b/go/src/v.io/x/ref/services/discovery/ble/neighborhood.go
@@ -0,0 +1,525 @@
+// 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 (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "hash/fnv"
+ "log"
+ "sync"
+ "time"
+
+ "mojom/v.io/x/ref/services/discovery/ble/ble"
+
+ "github.com/paypal/gatt"
+ "github.com/paypal/gatt/linux/cmd"
+ "reflect"
+)
+
+func newService(uuid string, serviceId []byte, attributes map[string]string) *gatt.Service {
+ s := gatt.NewService(gatt.MustParseUUID(uuid))
+ for u, v := range attributes {
+ s.AddCharacteristic(gatt.MustParseUUID(u)).SetValue([]byte(v))
+ }
+ s.AddCharacteristic(uniqueServiceId).SetValue(serviceId)
+ return s
+}
+
+var (
+ attrGAPUUID = gatt.UUID16(0x1800)
+
+ attrDeviceNameUUID = gatt.UUID16(0x2A00)
+ attrAppearanceUUID = gatt.UUID16(0x2A01)
+ attrPeripheralPrivacyUUID = gatt.UUID16(0x2A02)
+ attrReconnectionAddrUUID = gatt.UUID16(0x2A03)
+ attrPeferredParamsUUID = gatt.UUID16(0x2A04)
+
+ attrGATTUUID = gatt.UUID16(0x1801)
+ attrServiceChangedUUID = gatt.UUID16(0x2A05)
+)
+
+const (
+ manufacturerId = uint16(1001)
+)
+
+var uniqueServiceId gatt.UUID
+
+func init() {
+ uniqueServiceId = gatt.MustParseUUID("f6445c7f-73fd-4b8d-98d0-c4e02b087844")
+
+}
+
+// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
+var gapCharAppearanceGenericComputer = []byte{0x00, 0x80}
+
+func newGapService(name string) *gatt.Service {
+ s := gatt.NewService(attrGAPUUID)
+ s.AddCharacteristic(attrDeviceNameUUID).SetValue([]byte(name))
+ s.AddCharacteristic(attrAppearanceUUID).SetValue(gapCharAppearanceGenericComputer)
+ s.AddCharacteristic(attrPeripheralPrivacyUUID).SetValue([]byte{0x00})
+ s.AddCharacteristic(attrReconnectionAddrUUID).SetValue([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
+ s.AddCharacteristic(attrPeferredParamsUUID).SetValue([]byte{0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0x07})
+ return s
+}
+
+func newGattService() *gatt.Service {
+ s := gatt.NewService(attrGATTUUID)
+ s.AddCharacteristic(attrServiceChangedUUID).HandleNotifyFunc(
+ func(r gatt.Request, n gatt.Notifier) {})
+ return s
+}
+
+var gattOptions = []gatt.Option{
+ gatt.LnxMaxConnections(1),
+ gatt.LnxDeviceID(-1, true),
+ gatt.LnxSetAdvertisingParameters(&cmd.LESetAdvertisingParameters{
+ // Set an advertising rate of 150ms. This value is multipled by
+ // 0.625ms to get the actual rate.
+ AdvertisingIntervalMin: 0x00f4,
+ AdvertisingIntervalMax: 0x00f4,
+ AdvertisingChannelMap: 0x7,
+ }),
+}
+
+type scanner struct {
+ mu sync.Mutex
+ uuid string
+ attributes map[string]string
+ ch chan *update
+ done bool
+}
+
+func (s *scanner) handleChange(id string, oldService *ble.Service, newService *ble.Service) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.done {
+ return
+ }
+ matches := s.matches(id, newService)
+ oldMatches := s.matches(id, oldService)
+ uuid, err := hex.DecodeString(id)
+ if err != nil {
+ log.Fatal("Failed to decode uuid:",id,",",err)
+ }
+ if oldMatches {
+ s.ch <- &update{
+ found: false,
+ adv: ble.Advertisement{
+ ServiceId: uuid,
+ Service: *oldService,
+ },
+ }
+ }
+
+ if matches {
+ s.ch <- &update{
+ found: true,
+ adv: ble.Advertisement{
+ ServiceId: uuid,
+ Service: *newService,
+ },
+ }
+ }
+}
+
+func (s *scanner) stop() {
+ s.mu.Lock()
+ s.done = true
+ s.mu.Unlock()
+}
+
+func attributeMatch(filter map[string]string, attr map[string]string) bool {
+ for k, v := range filter {
+ if attr[k] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func (s *scanner) matches(id string, service *ble.Service) bool {
+ if service == nil {
+ return false
+ }
+ return (s.uuid == "" || id == s.uuid) && attributeMatch(s.attributes, service.Attributes)
+}
+
+type update struct {
+ found bool
+ adv ble.Advertisement
+}
+
+type bleCacheEntry struct {
+ id string
+ name string
+ services map[string]*ble.Service
+ hash string
+ lastSeen time.Time
+}
+
+type bleNeighborHood struct {
+ mu sync.Mutex
+
+ neighborsHashCache map[string]*bleCacheEntry
+ knownNeighbors map[string]*bleCacheEntry
+ services map[string]*gatt.Service
+ // Scanners out standing calls to Scan that need be serviced. Each time a
+ // new device appears or disappears, the scanner is notified of the event.
+ scanners map[int64]*scanner
+ // If both sides try to connect to each other at the same time, then only
+ // one will succeed and the other hangs forever. This means that the side
+ // that hangs won't ever start scanning or advertising again. To avoid this
+ // we timeout any connections that don't finish in under 4 seconds. This
+ // channel is closed when a connection has been made successfully, to notify
+ // the cancel goroutine that it doesn't need to do anything.
+ timeoutMap map[string]chan struct{}
+ // The hash that we use to avoid multiple connections are stored in the
+ // advertising data, so we need to store somewhere in the bleNeighorhood
+ // until we are ready to save the new device data. This map is
+ // the keeper of the data.
+ pendingHashMap map[string]string
+ name string
+ device gatt.Device
+ isStopped bool
+ nextScanId int64
+}
+
+func newBleNeighborhood(name string) (*bleNeighborHood, error) {
+ b := &bleNeighborHood{
+ neighborsHashCache: make(map[string]*bleCacheEntry),
+ knownNeighbors: make(map[string]*bleCacheEntry),
+ name: name,
+ services: make(map[string]*gatt.Service),
+ scanners: make(map[int64]*scanner),
+ timeoutMap: make(map[string]chan struct{}),
+ pendingHashMap: make(map[string]string),
+ }
+ if err := b.startBLEService(); err != nil {
+ return nil, err
+ }
+ return b, nil
+}
+
+func (b *bleNeighborHood) addService(id string, service ble.Service) {
+ b.mu.Lock()
+ b.services[id] = newService(id, service.InstanceId, service.Attributes)
+ v := make([]*gatt.Service, 0, len(b.services))
+ for _, s := range b.services {
+ v = append(v, s)
+ }
+ b.mu.Unlock()
+ b.device.SetServices(v)
+}
+
+func (b *bleNeighborHood) removeService(id string) {
+ b.mu.Lock()
+ delete(b.services, id)
+ v := make([]*gatt.Service, 0, len(b.services))
+ for _, s := range b.services {
+ v = append(v, s)
+ }
+ b.mu.Unlock()
+ b.device.SetServices(v)
+}
+
+func (b *bleNeighborHood) addScanner(uuid *[]byte, attr map[string]string, ch chan *update) int64 {
+ s := &scanner{
+ attributes: attr,
+ ch: ch,
+ }
+ if uuid != nil {
+ s.uuid = hex.EncodeToString(*uuid)
+ }
+ b.mu.Lock()
+ id := b.nextScanId
+ b.nextScanId++
+ b.scanners[id] = s
+ b.mu.Unlock()
+ return id
+}
+
+func (b *bleNeighborHood) removeScanner(id int64) {
+ b.mu.Lock()
+ scanner, found := b.scanners[id]
+ if found {
+ scanner.stop()
+ }
+ delete(b.scanners, id)
+ b.mu.Unlock()
+}
+
+func (b *bleNeighborHood) Stop() error {
+ b.mu.Lock()
+ b.isStopped = true
+ b.mu.Unlock()
+ b.device.StopAdvertising()
+ b.device.StopScanning()
+ return nil
+}
+
+func (b *bleNeighborHood) advertiseAndScan() {
+ b.mu.Lock()
+ isStopped := b.isStopped
+ b.mu.Unlock()
+ if isStopped {
+ log.Println("Quitting")
+ return
+ }
+ log.Println("starting advertisement and scanning")
+ b.device.Advertise(b.computeAdvertisement())
+ b.device.Scan([]gatt.UUID{}, false)
+}
+
+// seenHash returns
+func (b *bleNeighborHood) seenHash(id string, h string) bool {
+ log.Println("Checking for existence of", h)
+ b.mu.Lock()
+ defer b.mu.Unlock()
+ entry, ok := b.neighborsHashCache[h]
+ if !ok {
+ b.pendingHashMap[id] = h
+ return false
+ }
+
+ if entry.id != id {
+ // This can happen either because two different devices chose the same
+ // endpoint and name, or that one device changed its mac address. It
+ // seems more likely that the latter happened
+ // TODO(bjornick): Deal with the first case.
+ entry.id = id
+ }
+ entry.lastSeen = time.Now()
+ log.Println("Skipping connect because hashes match")
+ return true
+}
+
+// shouldConnect returns true if a connection should be made to p to get an update on the
+// state of the services on that device.
+func (b *bleNeighborHood) shouldConnect(p gatt.Peripheral, a *gatt.Advertisement) bool {
+ md := a.ManufacturerData
+ // The manufuacture data for other vanadium devices have the format:
+ // 0xe9 0x03 <length> <hash>
+ if len(md) < 2 {
+ return false
+ }
+ if md[0] != uint8(0xe9) || md[1] != uint8(0x03) {
+ return false
+ }
+ hash := md[3:]
+ return !b.seenHash(p.ID(), hex.EncodeToString(hash))
+}
+
+func (b *bleNeighborHood) getAllServices(p gatt.Peripheral) {
+ log.Println("Connected to device")
+
+ b.mu.Lock()
+ h := b.pendingHashMap[p.ID()]
+ delete(b.pendingHashMap, p.ID())
+ b.mu.Unlock()
+ defer func() {
+ b.mu.Lock()
+ ch := b.timeoutMap[p.ID()]
+ delete(b.timeoutMap, p.ID())
+ b.mu.Unlock()
+ if ch != nil {
+ log.Println("Closing channel")
+ close(ch)
+ }
+ p.Device().CancelConnection(p)
+ b.advertiseAndScan()
+ }()
+ /*
+ if err := p.SetMTU(500); err != nil {
+ log.Errorf("Failed to set MTU, err: %s", err)
+ return
+ }
+ */
+
+ log.Println("Scanning for services")
+ ss, err := p.DiscoverServices(nil)
+
+ if err != nil {
+ log.Printf("Failed to discover services, err: %s\n", err)
+ return
+ }
+
+ services := map[string]*ble.Service{}
+ var name string
+ for _, s := range ss {
+ if s.UUID().Equal(attrGAPUUID) {
+ continue
+ }
+
+ cs, err := p.DiscoverCharacteristics(nil, s)
+ if err != nil {
+ log.Printf("Failed to discover characteristics: %s\n", err)
+ continue
+ }
+
+ charMap := make(map[string]string)
+ uniqueId := []byte{}
+ for _, c := range cs {
+ if s.UUID().Equal(attrGATTUUID) {
+ if !c.UUID().Equal(attrDeviceNameUUID) {
+ continue
+ }
+ v, err := p.ReadLongCharacteristic(c)
+ if err != nil {
+ log.Printf("Failed to read the name: %v\n", err)
+ continue
+
+ }
+ name = string(v)
+ continue
+ }
+ key := c.UUID().String()
+ v, err := p.ReadLongCharacteristic(c)
+ if err != nil {
+ log.Printf("Failed to read the characteristc (%s): %v\n", key, err)
+ continue
+
+ }
+
+ if c.UUID().Equal(uniqueServiceId) {
+ uniqueId = v
+ continue
+ }
+ charMap[key] = string(v)
+ }
+ services[s.UUID().String()] = &ble.Service{
+ Attributes: charMap,
+ InstanceId: uniqueId,
+ }
+ }
+ b.saveDevice(h, p.ID(), name, services)
+}
+
+func (b *bleNeighborHood) startBLEService() error {
+ d, err := gatt.NewDevice(gattOptions...)
+ if err != nil {
+ return err
+ }
+ onPeriphDiscovered := func(p gatt.Peripheral, a *gatt.Advertisement, rssi int) {
+ log.Printf("Found a device (%s)!\n", p.Name())
+ if b.shouldConnect(p, a) {
+ log.Println("trying to connect to ", p.Name())
+ // We stop the scanning and advertising so we can connect to the new device.
+ // If one device is changing too frequently we might never find all the devices,
+ // since we restart the scan every time we finish connecting, but hopefully
+ // that is rare.
+ p.Device().StopScanning()
+ p.Device().StopAdvertising()
+ p.Device().Connect(p)
+ b.mu.Lock()
+ cancel := make(chan struct{}, 1)
+ b.timeoutMap[p.ID()] = cancel
+ b.mu.Unlock()
+ go func() {
+ select {
+ case <-time.After(4 * time.Second):
+ p.Device().CancelConnection(p)
+ b.advertiseAndScan()
+ case <-cancel:
+ }
+ }()
+ }
+ }
+
+ onPeriphConnected := func(p gatt.Peripheral, err error) {
+ if err != nil {
+ log.Println("Failed to connect:", err)
+ return
+ }
+ b.getAllServices(p)
+ }
+
+ onStateChanged := func(d gatt.Device, s gatt.State) {
+ log.Printf("State: %s\n", s)
+ switch s {
+ case gatt.StatePoweredOn:
+ d.AddService(newGapService(b.name))
+ d.AddService(newGattService())
+
+ b.advertiseAndScan()
+ default:
+ d.StopScanning()
+
+ }
+ }
+
+ d.Handle(
+ gatt.CentralConnected(func(c gatt.Central) { log.Printf("Connect: %v\n", c.ID()) }),
+ gatt.CentralDisconnected(func(c gatt.Central) { log.Printf("Disconnected: %v\n", c.ID()) }),
+ gatt.PeripheralDiscovered(onPeriphDiscovered),
+ gatt.PeripheralConnected(onPeriphConnected),
+ )
+
+ d.Init(onStateChanged)
+ b.device = d
+ return nil
+}
+
+func (b *bleNeighborHood) saveDevice(hash string, id string, name string, services map[string]*ble.Service) {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+ _, found := b.neighborsHashCache[hash]
+ if found {
+ log.Printf("Skipping a new save for the same hash (%s) for %s\n",
+ hash, name)
+ return
+ }
+ oldServices := map[string]*ble.Service{}
+ if oldEntry, ok := b.knownNeighbors[id]; ok {
+ oldServices = oldEntry.services
+ }
+
+ newEntry := &bleCacheEntry{
+ id: id,
+ hash: hash,
+ name: name,
+ services: services,
+ lastSeen: time.Now(),
+ }
+ b.neighborsHashCache[hash] = newEntry
+ b.knownNeighbors[id] = newEntry
+ log.Println("Looking through", len(b.scanners), "scanners *****")
+ for _, s := range b.scanners {
+ for id, oldService := range oldServices {
+ newValue := services[id]
+ if !reflect.DeepEqual(oldService, newValue) {
+ s.handleChange(id, oldService, newValue)
+ }
+ }
+
+ for id, newService := range newEntry.services {
+ if _, ok := oldServices[id]; !ok {
+ s.handleChange(id, nil, newService)
+ }
+ }
+ }
+
+}
+
+func (b *bleNeighborHood) computeAdvertisement() *gatt.AdvPacket {
+ // The hash is:
+ // Hash(Hash(name),Hash(b.endpoints))
+ hasher := fnv.New64()
+ nameHasher := fnv.New64()
+ nameHasher.Write([]byte(b.name))
+ binary.Write(hasher, binary.BigEndian, nameHasher.Sum64())
+ for k, _ := range b.services {
+ innerHash := fnv.New64()
+ innerHash.Write([]byte(k))
+ binary.Write(hasher, binary.BigEndian, innerHash.Sum64())
+ }
+ var buf bytes.Buffer
+ binary.Write(&buf, binary.BigEndian, hasher.Sum64())
+ adv := &gatt.AdvPacket{}
+ adv.AppendManufacturerData(manufacturerId, buf.Bytes())
+ adv.AppendName(b.name)
+ return adv
+}
diff --git a/go/src/v.io/x/ref/services/discovery/ble/service.go b/go/src/v.io/x/ref/services/discovery/ble/service.go
new file mode 100644
index 0000000..bf0a91a
--- /dev/null
+++ b/go/src/v.io/x/ref/services/discovery/ble/service.go
@@ -0,0 +1,145 @@
+package main
+
+import (
+ "encoding/hex"
+ "log"
+ "sync"
+
+ "mojo/public/go/application"
+ "mojo/public/go/bindings"
+ "mojo/public/go/system"
+
+ "mojom/v.io/x/ref/services/discovery/ble/ble"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+type bleImpl struct {
+ n *bleNeighborHood
+ d *delegate
+}
+
+func (b *bleImpl) Advertise(adv ble.Advertisement) (ble.PluginStopper_Pointer, error) {
+ uuid := hex.EncodeToString(adv.ServiceId)
+ b.n.addService(uuid, adv.Service)
+ return b.createHandleFor(&stopAdvertingImpl{uuid: uuid, n: b.n}), nil
+}
+
+func (b *bleImpl) Scan(uuid *[]uint8, attr map[string]string, handler ble.PluginScanHandler_Pointer) (ble.PluginStopper_Pointer, error) {
+ ch := make(chan *update, 10)
+ proxy := ble.NewPluginScanHandlerProxy(handler, bindings.GetAsyncWaiter())
+ go func() {
+ for v := range ch {
+ if v.found {
+ proxy.Found(v.adv)
+ } else {
+ proxy.Lost(v.adv)
+ }
+ }
+ }()
+ id := b.n.addScanner(uuid, attr, ch)
+ return b.createHandleFor(&stopScanImpl{id: id, n: b.n}), nil
+}
+
+func (b *bleImpl) createHandleFor(h ble.PluginStopper) ble.PluginStopper_Pointer {
+ req, ptr := ble.CreateMessagePipeForPluginStopper()
+ stub := ble.NewPluginStopperStub(req, h, bindings.GetAsyncWaiter())
+ b.d.addStub(stub)
+ go func() {
+ for {
+ if err := stub.ServeRequest(); err != nil {
+ connErr, ok := err.(*bindings.ConnectionError)
+ if !ok || !connErr.Closed() {
+ log.Println(err)
+ }
+ break
+ }
+ }
+ }()
+
+ return ptr
+}
+
+type stopAdvertingImpl struct {
+ uuid string
+ n *bleNeighborHood
+}
+
+func (s *stopAdvertingImpl) Stop() error {
+ s.n.removeService(s.uuid)
+ return nil
+}
+
+type stopScanImpl struct {
+ id int64
+ n *bleNeighborHood
+}
+
+func (s *stopScanImpl) Stop() error {
+ s.n.removeScanner(s.id)
+ return nil
+}
+
+type delegate struct {
+ mu sync.Mutex
+ n *bleNeighborHood
+ stubs []*bindings.Stub
+}
+
+func (d *delegate) Initialize(ctx application.Context) {
+ args := ctx.Args()
+ if len(args) < 2 {
+ log.Println("Device name needs to be passed in")
+ ctx.Close()
+ }
+ name := ctx.Args()[1]
+ n, err := newBleNeighborhood(name)
+ if err != nil {
+ log.Println("Failed to start neighborhood", err)
+ ctx.Close()
+ }
+ d.n = n
+}
+
+func (d *delegate) Create(req ble.V23Ble_Request) {
+ stub := ble.NewV23BleStub(req, &bleImpl{n: d.n, d: d}, bindings.GetAsyncWaiter())
+ d.addStub(stub)
+ go func() {
+ for {
+ if err := stub.ServeRequest(); err != nil {
+ connErr, ok := err.(*bindings.ConnectionError)
+ if !ok || !connErr.Closed() {
+ log.Println(err)
+ }
+ break
+ }
+ }
+ }()
+}
+
+func (d *delegate) addStub(s *bindings.Stub) {
+ d.mu.Lock()
+ d.stubs = append(d.stubs, s)
+ d.mu.Unlock()
+}
+func (d *delegate) AcceptConnection(conn *application.Connection) {
+ conn.ProvideServices(&ble.V23Ble_ServiceFactory{d})
+}
+
+func (d *delegate) Quit() {
+ for _, stub := range d.stubs {
+ stub.Close()
+ }
+ if d.n != nil {
+ d.n.Stop()
+ }
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+ application.Run(&delegate{}, system.MojoHandle(handle))
+ return C.MOJO_RESULT_OK
+}
+
+func main() {}
diff --git a/go/src/v.io/x/ref/services/discovery/driver/driver.go b/go/src/v.io/x/ref/services/discovery/driver/driver.go
new file mode 100644
index 0000000..038345b
--- /dev/null
+++ b/go/src/v.io/x/ref/services/discovery/driver/driver.go
@@ -0,0 +1,60 @@
+package main
+
+import (
+ "crypto/sha256"
+ "encoding/hex"
+ "log"
+ "mojo/public/go/application"
+ "mojo/public/go/bindings"
+ "mojo/public/go/system"
+ "mojom/v.io/x/ref/services/discovery/ble/ble"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+type discoveryDelegate struct {
+ bleHandlerProxy *ble.PluginStopper_Proxy
+}
+
+func (d *discoveryDelegate) Initialize(ctx application.Context) {
+ hash := sha256.Sum256([]byte("foobar"))
+ uuid := hash[:16]
+ hash = sha256.Sum256([]byte("key1"))
+ key1 := hex.EncodeToString(hash[:16])
+ bleRequest, blePointer := ble.CreateMessagePipeForV23Ble()
+ ctx.ConnectToApplication("https://mojo.v.io/ble.mojo").ConnectToService(&bleRequest)
+ bleProxy := ble.NewV23BleProxy(blePointer, bindings.GetAsyncWaiter())
+ adv := ble.Advertisement{
+ ServiceId: uuid,
+ Service: ble.Service{
+ Attributes: map[string]string{key1: "value1"},
+ InstanceId: []byte("random-uuid"),
+ },
+ }
+ handlerPtr, err := bleProxy.Advertise(adv)
+ if err != nil {
+ log.Println(err)
+ ctx.Close()
+ return
+ }
+ d.bleHandlerProxy = ble.NewPluginStopperProxy(handlerPtr, bindings.GetAsyncWaiter())
+}
+
+func (d *discoveryDelegate) AcceptConnection(conn *application.Connection) {
+ conn.Close()
+}
+
+func (d *discoveryDelegate) Quit() {
+ if d.bleHandlerProxy != nil {
+ d.bleHandlerProxy.Stop()
+ }
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+ application.Run(&discoveryDelegate{}, system.MojoHandle(handle))
+ return C.MOJO_RESULT_OK
+}
+
+func main() {}
diff --git a/go/src/v.io/x/ref/services/discovery/scanner/scanner.go b/go/src/v.io/x/ref/services/discovery/scanner/scanner.go
new file mode 100644
index 0000000..65745d7
--- /dev/null
+++ b/go/src/v.io/x/ref/services/discovery/scanner/scanner.go
@@ -0,0 +1,84 @@
+package main
+
+import (
+ "crypto/sha256"
+ "log"
+ "mojo/public/go/application"
+ "mojo/public/go/bindings"
+ "mojo/public/go/system"
+ "mojom/v.io/x/ref/services/discovery/ble/ble"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+type responseHandler struct{}
+
+func (r *responseHandler) Found(a ble.Advertisement) error {
+ log.Println("Found:", a)
+ return nil
+}
+
+func (r *responseHandler) Lost(a ble.Advertisement) error {
+ log.Println("Removed:", a)
+ return nil
+}
+
+type scannerDelegate struct {
+ bleHandlerProxy *ble.PluginStopper_Proxy
+ stubs []*bindings.Stub
+}
+
+func (s *scannerDelegate) Initialize(ctx application.Context) {
+ hash := sha256.Sum256([]byte("foobar"))
+ uuid := hash[:16]
+ hash = sha256.Sum256([]byte("key1"))
+ // key1 := hex.EncodeToString(hash[:16])
+ bleRequest, blePointer := ble.CreateMessagePipeForV23Ble()
+ ctx.ConnectToApplication("https://mojo.v.io/ble.mojo").ConnectToService(&bleRequest)
+ bleProxy := ble.NewV23BleProxy(blePointer, bindings.GetAsyncWaiter())
+ cbRequest, cbPointer := ble.CreateMessagePipeForPluginScanHandler()
+ stub := ble.NewPluginScanHandlerStub(cbRequest, &responseHandler{}, bindings.GetAsyncWaiter())
+ s.stubs = append(s.stubs, stub)
+ go func() {
+ for {
+ if err := stub.ServeRequest(); err != nil {
+ connErr, ok := err.(*bindings.ConnectionError)
+ if !ok || !connErr.Closed() {
+ log.Println(err)
+ }
+ break
+ }
+ }
+ }()
+ log.Println("Calling scanner")
+ handlerPtr, err := bleProxy.Scan(&uuid, map[string]string{}, cbPointer)
+ if err != nil {
+ log.Println(err)
+ ctx.Close()
+ return
+ }
+ s.bleHandlerProxy = ble.NewPluginStopperProxy(handlerPtr, bindings.GetAsyncWaiter())
+}
+
+func (*scannerDelegate) AcceptConnection(conn *application.Connection) {
+ conn.Close()
+}
+
+func (s *scannerDelegate) Quit() {
+ if s.bleHandlerProxy != nil {
+ s.bleHandlerProxy.Stop()
+ }
+
+ for _, stub := range s.stubs {
+ stub.Close()
+ }
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+ application.Run(&scannerDelegate{}, system.MojoHandle(handle))
+ return C.MOJO_RESULT_OK
+}
+
+func main() {}
diff --git a/mojoconfig b/mojoconfig
new file mode 100644
index 0000000..47f802a
--- /dev/null
+++ b/mojoconfig
@@ -0,0 +1,15 @@
+# Derived from $MOJO_DIR/mojoconfig.
+
+{
+ 'dev_servers': [
+ {
+ 'host': 'https://mojo.v.io/',
+ 'mappings': [
+ ('', [
+ # For ble.mojo.
+ '@{DISCOVERY_BUILD_DIR}',
+ ]),
+ ],
+ }
+ ],
+}
diff --git a/mojom/v.io/x/ref/services/discovery/ble/ble.mojom b/mojom/v.io/x/ref/services/discovery/ble/ble.mojom
new file mode 100644
index 0000000..62985f7
--- /dev/null
+++ b/mojom/v.io/x/ref/services/discovery/ble/ble.mojom
@@ -0,0 +1,37 @@
+module ble;
+
+interface V23BLE {
+ // Exports the given service id with the attributes specified. The
+ // keys should be string forms of 128-bit uuids. The values can be anything.
+ // Returns a handle to the service that can be used to stop the Advertisement.
+ Advertise(Advertisement adv) => (PluginStopper Handler);
+
+ // Scans for all services which match the given attributes. The key in
+ // the attribute map should be 128-bit uuids in human readable format.
+ // All services that have an exact match for the given attributes are
+ // returned. Attributes not specified in attributes will not be used
+ // in the match. Calls handler with each new service found. Returns
+ // a handle to the Scan operation so it can be canceled when no longer
+ // relevant
+ Scan(array<uint8>? id, map<string, string> attributes, PluginScanHandler handler) => (PluginStopper Handler);
+};
+
+struct Advertisement {
+ array<uint8> ServiceId;
+ Service Service;
+};
+
+struct Service {
+ array<uint8> InstanceId;
+ map<string, string> Attributes;
+};
+
+interface PluginScanHandler {
+ Found(Advertisement s);
+
+ Lost(Advertisement s);
+};
+
+interface PluginStopper {
+ Stop();
+};
diff --git a/mojom/v.io/x/ref/services/discovery/discovery.mojom b/mojom/v.io/x/ref/services/discovery/discovery.mojom
new file mode 100644
index 0000000..17b5146
--- /dev/null
+++ b/mojom/v.io/x/ref/services/discovery/discovery.mojom
@@ -0,0 +1,29 @@
+module discovery;
+
+interface Discovery {
+ // TODO(bjornick): Figure out how to do security in mojo
+ Advertise(Service service) => (DiscoveryStopper Handle);
+
+ Scan(string query, DiscoveryHandler handler) => (DiscoveryStopper Handle);
+};
+
+interface DiscoveryStopper {
+ // Stops the Advertisement/Scanning that is associated with this service
+ Stop();
+};
+
+interface DiscoveryHandler {
+ Found(Service s);
+
+ Lost(array<uint8> id);
+};
+
+struct Service {
+ // The interface name this service implements.
+ // E.g. 'v.io/v23/Display.T
+ string InterfaceNames;
+
+ map<string, string> Attrs;
+
+ array<string> Addrs;
+};