@@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
3737import kotlinx.coroutines.flow.StateFlow
3838import kotlinx.coroutines.flow.asStateFlow
3939import kotlinx.coroutines.flow.filter
40+ import kotlinx.coroutines.flow.filterNot
4041import kotlinx.coroutines.flow.first
4142import kotlinx.coroutines.flow.launchIn
4243import kotlinx.coroutines.flow.map
@@ -148,6 +149,10 @@ internal class CBPeripheralCoreBluetoothPeripheral(
148149 logger.info { message = " Connecting" }
149150 _state .value = State .Connecting .Bluetooth
150151
152+ val failureWatcher = centralManager.delegate
153+ .connectionState
154+ .watchForConnectionFailureIn(scope)
155+
151156 try {
152157 _connection .value = centralManager.connectPeripheral(
153158 scope,
@@ -156,8 +161,6 @@ internal class CBPeripheralCoreBluetoothPeripheral(
156161 logging,
157162 )
158163
159- // fixme: Handle centralManager:didFailToConnectPeripheral:error:
160- // https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518988-centralmanager
161164 suspendUntilOrThrow<State .Connecting .Services >()
162165 discoverServices()
163166 onServicesDiscovered(ServicesDiscoveredPeripheral (this @CBPeripheralCoreBluetoothPeripheral))
@@ -170,6 +173,8 @@ internal class CBPeripheralCoreBluetoothPeripheral(
170173 val failure = e.unwrapCancellationCause()
171174 logger.error(failure) { message = " Failed to connect" }
172175 throw failure
176+ } finally {
177+ failureWatcher.cancel()
173178 }
174179
175180 logger.info { message = " Connected" }
@@ -199,6 +204,23 @@ internal class CBPeripheralCoreBluetoothPeripheral(
199204 }
200205 .launchIn(scope)
201206
207+ private fun Flow<ConnectionEvent>.watchForConnectionFailureIn (scope : CoroutineScope ) =
208+ filter { identifier -> identifier == cbPeripheral.identifier }
209+ .filterNot { event -> event is DidConnect }
210+ .onEach { event ->
211+ val error = when (event) {
212+ is DidFailToConnect -> event.error
213+ is DidDisconnect -> event.error
214+ else -> null
215+ }
216+ val failure = error
217+ ?.let { " : ${it.toStatus()} (${it.localizedDescription} )" }
218+ .orEmpty()
219+ logger.info { message = " Disconnected$failure " }
220+ throw ConnectionLostException (" $this disconnected$failure " )
221+ }
222+ .launchIn(scope)
223+
202224 override suspend fun disconnect () {
203225 closeConnection()
204226 suspendUntil<State .Disconnected >()
0 commit comments