@@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
37
37
import kotlinx.coroutines.flow.StateFlow
38
38
import kotlinx.coroutines.flow.asStateFlow
39
39
import kotlinx.coroutines.flow.filter
40
+ import kotlinx.coroutines.flow.filterNot
40
41
import kotlinx.coroutines.flow.first
41
42
import kotlinx.coroutines.flow.launchIn
42
43
import kotlinx.coroutines.flow.map
@@ -148,6 +149,10 @@ internal class CBPeripheralCoreBluetoothPeripheral(
148
149
logger.info { message = " Connecting" }
149
150
_state .value = State .Connecting .Bluetooth
150
151
152
+ val failureWatcher = centralManager.delegate
153
+ .connectionState
154
+ .watchForConnectionFailureIn(scope)
155
+
151
156
try {
152
157
_connection .value = centralManager.connectPeripheral(
153
158
scope,
@@ -156,8 +161,6 @@ internal class CBPeripheralCoreBluetoothPeripheral(
156
161
logging,
157
162
)
158
163
159
- // fixme: Handle centralManager:didFailToConnectPeripheral:error:
160
- // https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518988-centralmanager
161
164
suspendUntilOrThrow<State .Connecting .Services >()
162
165
discoverServices()
163
166
onServicesDiscovered(ServicesDiscoveredPeripheral (this @CBPeripheralCoreBluetoothPeripheral))
@@ -170,6 +173,8 @@ internal class CBPeripheralCoreBluetoothPeripheral(
170
173
val failure = e.unwrapCancellationCause()
171
174
logger.error(failure) { message = " Failed to connect" }
172
175
throw failure
176
+ } finally {
177
+ failureWatcher.cancel()
173
178
}
174
179
175
180
logger.info { message = " Connected" }
@@ -199,6 +204,23 @@ internal class CBPeripheralCoreBluetoothPeripheral(
199
204
}
200
205
.launchIn(scope)
201
206
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
+
202
224
override suspend fun disconnect () {
203
225
closeConnection()
204
226
suspendUntil<State .Disconnected >()
0 commit comments