diff --git a/adapter_darwin.go b/adapter_darwin.go index 7ceb096..db09d9c 100644 --- a/adapter_darwin.go +++ b/adapter_darwin.go @@ -10,8 +10,6 @@ import ( // Adapter is a connection to BLE devices. type Adapter struct { - sync.Mutex - cmd *centralManagerDelegate pmd *peripheralManagerDelegate @@ -21,7 +19,10 @@ type Adapter struct { peripheralFoundHandler func(*Adapter, ScanResult) scanChan chan error poweredChan chan error - connectChan map[string](chan cbgo.Peripheral) + + // connectChan is a mapping of peripheralId -> chan cbgo.Peripheral, + // used to allow multiple callers to call Connect concurrently. + connectChan sync.Map connectHandler func(device Addresser, connected bool) } @@ -32,7 +33,7 @@ type Adapter struct { var DefaultAdapter = &Adapter{ cm: cbgo.NewCentralManager(nil), pm: cbgo.NewPeripheralManager(nil), - connectChan: make(map[string]chan cbgo.Peripheral), + connectChan: sync.Map{}, connectHandler: func(device Addresser, connected bool) { return @@ -101,13 +102,17 @@ func (cmd *centralManagerDelegate) DidDiscoverPeripheral(cmgr cbgo.CentralManage // DidConnectPeripheral when peripheral is connected. func (cmd *centralManagerDelegate) DidConnectPeripheral(cmgr cbgo.CentralManager, prph cbgo.Peripheral) { - cmd.a.Lock() - defer cmd.a.Unlock() + id := prph.Identifier().String() - // Ignore this peripheral if we don't have a chan set up for it. - if ch, ok := cmd.a.connectChan[prph.Identifier().String()]; ok { + // Check if we have a chan allocated for this peripheral, and remove it + // from the map if so (it's single-use, will be garbage collected after + // receiver receives the peripheral). + // + // If we don't have a chan allocated, the receiving side timed out, so + // ignore this connection. + if ch, ok := cmd.a.connectChan.LoadAndDelete(id); ok { // Unblock now that we're connected. - ch <- prph + ch.(chan cbgo.Peripheral) <- prph } } diff --git a/gap_darwin.go b/gap_darwin.go index daebcf5..ddf5ea3 100644 --- a/gap_darwin.go +++ b/gap_darwin.go @@ -106,18 +106,11 @@ func (a *Adapter) Connect(address Addresser, params ConnectionParams) (*Device, return nil, fmt.Errorf("Connect failed: no peer with address: %s", adr.UUID.String()) } - prphCh := make(chan cbgo.Peripheral) id := prphs[0].Identifier().String() + prphCh := make(chan cbgo.Peripheral) - a.Lock() - a.connectChan[id] = prphCh - a.Unlock() - - defer func() { - a.Lock() - defer a.Unlock() - delete(a.connectChan, id) - }() + a.connectChan.Store(id, prphCh) + defer a.connectChan.Delete(id) a.cm.Connect(prphs[0], nil)