Skip to content

Commit 913b0c9

Browse files
committed
Updated DarwinCentral.disconnect()
1 parent f71820e commit 913b0c9

File tree

1 file changed

+70
-43
lines changed

1 file changed

+70
-43
lines changed

Sources/DarwinGATT/DarwinCentral.swift

Lines changed: 70 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -98,18 +98,21 @@ public final class DarwinCentral: CentralManager, ObservableObject {
9898
self.log?("Discovered \(self.cache.peripherals.count) peripherals")
9999
}
100100
}) { continuation in
101-
self.async {
101+
self.async { [unowned self] in
102102
self.stopScan()
103-
// disconnect all first
104-
self._disconnectAll()
105-
// queue scan operation
106-
let operation = Operation.Scan(
107-
services: services,
108-
filterDuplicates: filterDuplicates,
109-
continuation: continuation
110-
)
111-
self.continuation.scan = operation
112-
self.execute(operation)
103+
}
104+
Task {
105+
await self.disconnectAll()
106+
self.async { [unowned self] in
107+
// queue scan operation
108+
let operation = Operation.Scan(
109+
services: services,
110+
filterDuplicates: filterDuplicates,
111+
continuation: continuation
112+
)
113+
self.continuation.scan = operation
114+
self.execute(operation)
115+
}
113116
}
114117
}
115118
}
@@ -145,36 +148,22 @@ public final class DarwinCentral: CentralManager, ObservableObject {
145148
}
146149
}
147150

148-
public func disconnect(_ peripheral: Peripheral) {
149-
self.async { [weak self] in
150-
guard let self = self else { return }
151-
if self._disconnect(peripheral) {
152-
self.log?("Will disconnect \(peripheral)")
153-
}
154-
}
155-
}
156-
157-
private func _disconnect(_ peripheral: Peripheral) -> Bool {
158-
guard let peripheralObject = self.cache.peripherals[peripheral] else {
159-
return false
160-
}
161-
self.continuation.peripherals[peripheral]?.didDisconnect()
162-
self.centralManager.cancelPeripheralConnection(peripheralObject)
163-
return true
164-
}
165-
166-
public func disconnectAll() {
167-
self.log?("Will disconnect all")
168-
self.async { [weak self] in
169-
guard let self = self else { return }
170-
self._disconnectAll()
151+
public func disconnect(_ peripheral: Peripheral) async {
152+
try? await queue(for: peripheral) { continuation in
153+
Operation.Disconnect(
154+
peripheral: peripheral,
155+
continuation: continuation
156+
)
171157
}
172158
}
173159

174-
private func _disconnectAll() {
175-
for (peripheral, peripheralObject) in self.cache.peripherals {
176-
self.continuation.peripherals[peripheral]?.didDisconnect()
177-
self.centralManager.cancelPeripheralConnection(peripheralObject)
160+
public func disconnectAll() async {
161+
let connected = await self.peripherals
162+
.filter { $0.value }
163+
.keys
164+
165+
for peripheral in connected {
166+
await disconnect(peripheral)
178167
}
179168
}
180169

@@ -347,7 +336,8 @@ public final class DarwinCentral: CentralManager, ObservableObject {
347336
#endif
348337
return try await withThrowingContinuation(for: peripheral, function: function) { continuation in
349338
let queuedOperation = QueuedOperation(operation: operation(continuation))
350-
self.async {
339+
self.async { [unowned self] in
340+
self.stopScan() // stop scanning
351341
let context = self.continuation(for: peripheral)
352342
context.operations.push(queuedOperation)
353343
}
@@ -537,13 +527,15 @@ private extension DarwinCentral {
537527

538528
fileprivate extension DarwinCentral.PeripheralContinuationContext {
539529

540-
func didDisconnect() {
541-
let error = CentralError.disconnected
530+
func didDisconnect(_ error: Swift.Error? = nil) {
531+
let error = error ?? CentralError.disconnected
532+
// resume all pending operations
542533
while operations.isEmpty == false {
543534
operations.pop {
544535
$0.operation.resume(throwing: error)
545536
}
546537
}
538+
// end all notifications with disconnect error
547539
notificationStream.values.forEach {
548540
$0.finish(throwing: error)
549541
}
@@ -578,6 +570,7 @@ internal extension DarwinCentral {
578570

579571
enum Operation {
580572
case connect(Connect)
573+
case disconnect(Disconnect)
581574
case discoverServices(DiscoverServices)
582575
case discoverIncludedServices(DiscoverIncludedServices)
583576
case discoverCharacteristics(DiscoverCharacteristics)
@@ -598,6 +591,8 @@ internal extension DarwinCentral.Operation {
598591
switch self {
599592
case let .connect(operation):
600593
operation.continuation.resume(throwing: error)
594+
case let .disconnect(operation):
595+
operation.continuation.resume(throwing: error)
601596
case let .discoverServices(operation):
602597
operation.continuation.resume(throwing: error)
603598
case let .discoverIncludedServices(operation):
@@ -657,6 +652,12 @@ internal extension DarwinCentral.Operation {
657652
var operation: DarwinCentral.Operation { .connect(self) }
658653
}
659654

655+
struct Disconnect: DarwinCentralOperation {
656+
let peripheral: DarwinCentral.Peripheral
657+
let continuation: PeripheralContinuation<(), Error>
658+
var operation: DarwinCentral.Operation { .disconnect(self) }
659+
}
660+
660661
struct DiscoverServices: DarwinCentralOperation {
661662
let peripheral: DarwinCentral.Peripheral
662663
let services: Set<BluetoothUUID>
@@ -750,6 +751,8 @@ internal extension DarwinCentral {
750751
switch operation {
751752
case let .connect(operation):
752753
return execute(operation)
754+
case let .disconnect(operation):
755+
return execute(operation)
753756
case let .discoverServices(operation):
754757
return execute(operation)
755758
case let .discoverIncludedServices(operation):
@@ -790,6 +793,21 @@ internal extension DarwinCentral {
790793
return true
791794
}
792795

796+
func execute(_ operation: Operation.Disconnect) -> Bool {
797+
log?("Will disconnect \(operation.peripheral)")
798+
// check power on
799+
guard validateState(.poweredOn, for: operation.continuation) else {
800+
return false
801+
}
802+
// get peripheral
803+
guard let peripheralObject = validatePeripheral(operation.peripheral, for: operation.continuation) else {
804+
return false
805+
}
806+
// connect
807+
self.centralManager.cancelPeripheralConnection(peripheralObject)
808+
return true
809+
}
810+
793811
func execute(_ operation: Operation.DiscoverServices) -> Bool {
794812
log?("Peripheral \(operation.peripheral) will discover services")
795813
// check power on
@@ -1246,7 +1264,7 @@ internal extension DarwinCentral {
12461264

12471265
@objc(centralManager:didDisconnectPeripheral:error:)
12481266
func centralManager(
1249-
_ central: CBCentralManager,
1267+
_ centralManager: CBCentralManager,
12501268
didDisconnectPeripheral corePeripheral: CBPeripheral,
12511269
error: Swift.Error?
12521270
) {
@@ -1261,7 +1279,16 @@ internal extension DarwinCentral {
12611279
assertionFailure("Missing context")
12621280
return
12631281
}
1264-
context.didDisconnect()
1282+
// user requested disconnection
1283+
if error == nil {
1284+
self.central.dequeue(for: peripheral, result: .success(()), filter: { (operation: DarwinCentral.Operation) -> (Operation.Disconnect?) in
1285+
guard case let .disconnect(disconnectOperation) = operation else {
1286+
return nil
1287+
}
1288+
return disconnectOperation
1289+
})
1290+
}
1291+
context.didDisconnect(error)
12651292
self.central.objectWillChange.send()
12661293
}
12671294

0 commit comments

Comments
 (0)