darwin: make Adapter.Connect thread-safe
This change allows multiple concurrent goroutines to call `Adapter.Connect` without racing. Fixes #57
This commit is contained in:
parent
28f9f4e69e
commit
9471cedb5b
@ -2,6 +2,7 @@ package bluetooth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/JuulLabs-OSS/cbgo"
|
"github.com/JuulLabs-OSS/cbgo"
|
||||||
@ -9,6 +10,8 @@ import (
|
|||||||
|
|
||||||
// Adapter is a connection to BLE devices.
|
// Adapter is a connection to BLE devices.
|
||||||
type Adapter struct {
|
type Adapter struct {
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
cmd *centralManagerDelegate
|
cmd *centralManagerDelegate
|
||||||
pmd *peripheralManagerDelegate
|
pmd *peripheralManagerDelegate
|
||||||
|
|
||||||
@ -18,7 +21,7 @@ type Adapter struct {
|
|||||||
peripheralFoundHandler func(*Adapter, ScanResult)
|
peripheralFoundHandler func(*Adapter, ScanResult)
|
||||||
scanChan chan error
|
scanChan chan error
|
||||||
poweredChan chan error
|
poweredChan chan error
|
||||||
connectChan chan cbgo.Peripheral
|
connectChan map[string](chan cbgo.Peripheral)
|
||||||
|
|
||||||
connectHandler func(device Addresser, connected bool)
|
connectHandler func(device Addresser, connected bool)
|
||||||
}
|
}
|
||||||
@ -29,7 +32,8 @@ type Adapter struct {
|
|||||||
var DefaultAdapter = &Adapter{
|
var DefaultAdapter = &Adapter{
|
||||||
cm: cbgo.NewCentralManager(nil),
|
cm: cbgo.NewCentralManager(nil),
|
||||||
pm: cbgo.NewPeripheralManager(nil),
|
pm: cbgo.NewPeripheralManager(nil),
|
||||||
connectChan: make(chan cbgo.Peripheral),
|
connectChan: make(map[string]chan cbgo.Peripheral),
|
||||||
|
|
||||||
connectHandler: func(device Addresser, connected bool) {
|
connectHandler: func(device Addresser, connected bool) {
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
@ -97,8 +101,14 @@ func (cmd *centralManagerDelegate) DidDiscoverPeripheral(cmgr cbgo.CentralManage
|
|||||||
|
|
||||||
// DidConnectPeripheral when peripheral is connected.
|
// DidConnectPeripheral when peripheral is connected.
|
||||||
func (cmd *centralManagerDelegate) DidConnectPeripheral(cmgr cbgo.CentralManager, prph cbgo.Peripheral) {
|
func (cmd *centralManagerDelegate) DidConnectPeripheral(cmgr cbgo.CentralManager, prph cbgo.Peripheral) {
|
||||||
// Unblock now that we're connected.
|
cmd.a.Lock()
|
||||||
cmd.a.connectChan <- prph
|
defer cmd.a.Unlock()
|
||||||
|
|
||||||
|
// Ignore this peripheral if we don't have a chan set up for it.
|
||||||
|
if ch, ok := cmd.a.connectChan[prph.Identifier().String()]; ok {
|
||||||
|
// Unblock now that we're connected.
|
||||||
|
ch <- prph
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeScanResult creates a ScanResult when peripheral is found.
|
// makeScanResult creates a ScanResult when peripheral is found.
|
||||||
|
@ -105,11 +105,25 @@ func (a *Adapter) Connect(address Addresser, params ConnectionParams) (*Device,
|
|||||||
if len(prphs) == 0 {
|
if len(prphs) == 0 {
|
||||||
return nil, fmt.Errorf("Connect failed: no peer with address: %s", adr.UUID.String())
|
return nil, fmt.Errorf("Connect failed: no peer with address: %s", adr.UUID.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prphCh := make(chan cbgo.Peripheral)
|
||||||
|
id := prphs[0].Identifier().String()
|
||||||
|
|
||||||
|
a.Lock()
|
||||||
|
a.connectChan[id] = prphCh
|
||||||
|
a.Unlock()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
a.Lock()
|
||||||
|
defer a.Unlock()
|
||||||
|
delete(a.connectChan, id)
|
||||||
|
}()
|
||||||
|
|
||||||
a.cm.Connect(prphs[0], nil)
|
a.cm.Connect(prphs[0], nil)
|
||||||
|
|
||||||
// wait on channel for connect
|
// wait on channel for connect
|
||||||
select {
|
select {
|
||||||
case p := <-a.connectChan:
|
case p := <-prphCh:
|
||||||
d := &Device{
|
d := &Device{
|
||||||
cm: a.cm,
|
cm: a.cm,
|
||||||
prph: p,
|
prph: p,
|
||||||
|
Loading…
Reference in New Issue
Block a user