Skip to content

Commit 7a58126

Browse files
authored
Watch for connection loss during connect (#668)
Closes #637
1 parent 4a6aabd commit 7a58126

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

core/src/appleMain/kotlin/CBPeripheralCoreBluetoothPeripheral.kt

+24-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
3737
import kotlinx.coroutines.flow.StateFlow
3838
import kotlinx.coroutines.flow.asStateFlow
3939
import kotlinx.coroutines.flow.filter
40+
import kotlinx.coroutines.flow.filterNot
4041
import kotlinx.coroutines.flow.first
4142
import kotlinx.coroutines.flow.launchIn
4243
import 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

Comments
 (0)