blob: 5c98d76035d7853fae837ba54e24fbc63da16f73 [file] [log] [blame]
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"
"v.io/x/ref/services/discovery/ble/internal/lib"
)
//#include "mojo/public/c/system/types.h"
import "C"
type bleImpl struct {
n *lib.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() {}