From 1d66aed03b0cf4270c57527509c4a09a9abbf603 Mon Sep 17 00:00:00 2001 From: Benjamin Bouachour Date: Tue, 12 Mar 2019 13:25:23 +0100 Subject: [PATCH] emitter.go: - Added a MakeEmitter func that will create an Emitter and initialized its properties. - Added Close func to clean chans of Emitter - Added chan for subscribe and for clean - Subscribe: The On function of Emitter now write on chan Subscribe - Clean: The Close func (just added) write on the clean chan - Updated Init func - There is a Select statement inside the loop. The cases of the select are - event: in order to propagte event received from xpc to user handlers - subscribe(just added): in order to add an handler to the map of handlers - clean(just added): in order to clean up all channels an quit the loop - comment the close at the end of the lopp that maked it panic - removed each break based on result. The bool returned by the handlers are not used anymore (keep for retrocompatibility issues) goble.go - Call ble.Emitter.Init() inside func (ble *BLE) Init() instead of New - sendCBMsg: use the message constructed instead of rebuilted it - HandleXpcEvent: In the read case, use `Get` instead of `Must` because when connected to a peripheral after a connect. Automatically received a read event that does not contained - kCBMsgArgCharacteristicHandle - kCBMsgArgData --- emitter.go | 63 ++++++++++++++++++++++++++++++++++-------------------- goble.go | 11 +++++----- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/emitter.go b/emitter.go index e06b9c1..24db8e7 100644 --- a/emitter.go +++ b/emitter.go @@ -26,40 +26,57 @@ type Event struct { // The event handler function. // Return true to terminate type EventHandlerFunc func(Event) bool +type subscriberFunc struct { + eventName string + fn EventHandlerFunc +} // Emitter is an object to emit and handle Event(s) type Emitter struct { - handlers map[string]EventHandlerFunc - event chan Event - verbose bool + handlers map[string]EventHandlerFunc + event chan Event + subscribe chan subscriberFunc + verbose bool + clean chan bool +} + +func MakeEmitter() Emitter { + return Emitter{handlers: make(map[string]EventHandlerFunc), event: make(chan Event), subscribe: make(chan subscriberFunc), clean: make(chan bool)} } // Init initialize the emitter and start a goroutine to execute the event handlers func (e *Emitter) Init() { - e.handlers = make(map[string]EventHandlerFunc) - e.event = make(chan Event) // event handler go func() { for { - ev := <-e.event - - if fn, ok := e.handlers[ev.Name]; ok { - if fn(ev) { - break + select { + case ev := <-e.event: + if fn, ok := e.handlers[ev.Name]; ok { + fn(ev) + } else if fn, ok := e.handlers[ALL]; ok { + fn(ev) + } else { + if e.verbose { + log.Println("unhandled Emit", ev) + } } - } else if fn, ok := e.handlers[ALL]; ok { - if fn(ev) { - break + case cb := <-e.subscribe: + if cb.fn == nil { + delete(e.handlers, cb.eventName) + } else { + e.handlers[cb.eventName] = cb.fn } - } else { - if e.verbose { - log.Println("unhandled Emit", ev) + case cleaning := <-e.clean: + if cleaning == true { + close(e.event) + close(e.subscribe) + close(e.clean) + return } } } - - close(e.event) // TOFIX: this causes new "emits" to panic. + //close(e.event) // TOFIX: this causes new "emits" to panic. }() } @@ -74,9 +91,9 @@ func (e *Emitter) Emit(ev Event) { // On(event, cb) registers an handler for the specified event func (e *Emitter) On(event string, fn EventHandlerFunc) { - if fn == nil { - delete(e.handlers, event) - } else { - e.handlers[event] = fn - } + e.subscribe <- subscriberFunc{eventName: event, fn: fn} +} + +func (e *Emitter) Close() { + e.clean <- true } diff --git a/goble.go b/goble.go index 165868d..e345c96 100644 --- a/goble.go +++ b/goble.go @@ -147,8 +147,7 @@ type BLE struct { } func New() *BLE { - ble := &BLE{peripherals: map[string]*Peripheral{}, Emitter: Emitter{}} - ble.Emitter.Init() + ble := &BLE{peripherals: map[string]*Peripheral{}, Emitter: MakeEmitter()} ble.conn = xpc.XpcConnect("com.apple.blued", ble) xpc.Uname(&ble.utsname) return ble @@ -434,10 +433,10 @@ func (ble *BLE) HandleXpcEvent(event xpc.Dict, err error) { case 70, 95: // read deviceUuid := args.MustGetUUID("kCBMsgArgDeviceUUID") - characteristicsHandle := args.MustGetInt("kCBMsgArgCharacteristicHandle") + characteristicsHandle := args.GetInt("kCBMsgArgCharacteristicHandle", 0) //result := args.MustGetInt("kCBMsgArgResult") isNotification := args.GetInt("kCBMsgArgIsNotification", 0) != 0 - data := args.MustGetBytes("kCBMsgArgData") + data := args.GetBytes("kCBMsgArgData", []byte{}) if p, ok := ble.peripherals[deviceUuid.String()]; ok { for _, s := range p.Services { @@ -456,12 +455,12 @@ func (ble *BLE) sendCBMsg(id int, args xpc.Dict) { if ble.verbose { log.Printf("sendCBMsg %#v\n", message) } - - ble.conn.Send(xpc.Dict{"kCBMsgId": id, "kCBMsgArgs": args}, ble.verbose) + ble.conn.Send(message, ble.verbose) } // initialize BLE func (ble *BLE) Init() { + ble.Emitter.Init() ble.sendCBMsg(1, xpc.Dict{"kCBMsgArgName": fmt.Sprintf("goble-%v", time.Now().Unix()), "kCBMsgArgOptions": xpc.Dict{"kCBInitOptionShowPowerAlert": 0}, "kCBMsgArgType": 0}) }