Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propagate better BLE state #8

Merged
merged 3 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 35 additions & 12 deletions Sources/WalletSdk/MDoc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ public class BLESessionManager {
secKey = item as! SecKey
// swiftlint:enable force_cast
case errSecItemNotFound:
self.callback.update(state: .error("Key not found"))
self.callback.update(state: .error(.generic("Key not found")))
sbihel marked this conversation as resolved.
Show resolved Hide resolved
self.cancel()
return
case let status:
self.callback.update(state: .error("Keychain read failed: \(status)"))
self.callback.update(state: .error(.generic("Keychain read failed: \(status)")))
self.cancel()
return
}
Expand All @@ -95,15 +95,15 @@ public class BLESessionManager {
.ecdsaSignatureMessageX962SHA256,
payload as CFData,
&error) as Data? else {
self.callback.update(state: .error("Failed to sign message: \(error.debugDescription)"))
self.callback.update(state: .error(.generic("Failed to sign message: \(error.debugDescription)")))
self.cancel()
return
}
let response = try SpruceIDWalletSdkRs.submitSignature(sessionManager: sessionManager!,
derSignature: derSignature)
self.bleManager.writeOutgoingValue(data: response)
} catch {
self.callback.update(state: .error("\(error)"))
self.callback.update(state: .error(.generic("\(error)")))
self.cancel()
}
}
Expand All @@ -115,34 +115,57 @@ extension BLESessionManager: MDocBLEDelegate {
case .done:
self.callback.update(state: .success)
case .connected:
self.callback.update(state: .progress("Connected"))
case .progress(let message):
self.callback.update(state: .progress(message))
self.callback.update(state: .connected)
case .uploadProgress(let value, let total):
self.callback.update(state: .uploadProgress(value, total))
case .message(let data):
do {
let requestData = try SpruceIDWalletSdkRs.handleRequest(state: self.state, request: data)
self.sessionManager = requestData.sessionManager
self.callback.update(state: .selectNamespaces(requestData.itemsRequests))
} catch {
self.callback.update(state: .error("\(error)"))
self.callback.update(state: .error(.generic("\(error)")))
self.cancel()
}
case .error(let error):
self.callback.update(state: .error("\(error)"))
self.callback.update(state: .error(BleSessionError(holderBleError: error)))
self.cancel()
}
}
}

public enum BleSessionError {
/// When discovery or communication with the peripheral fails
case peripheral(String)
/// When Bluetooth is unusable (e.g. unauthorized).
case bluetooth(CBCentralManager)
/// Generic unrecoverable error
case generic(String)

init(holderBleError: MdocHolderBleError) {
switch holderBleError {
case .peripheral(let string):
self = .peripheral(string)
case .bluetooth(let string):
self = .bluetooth(string)
}
}
}

public enum BLESessionState {
/// App should display the error message
case error(String)
case error(BleSessionError)
/// App should display the QR code
case engagingQRCode(Data)
/// App should indicate to the user that progress is being made
case progress(String)
/// App should indicate to the user that BLE connection has been made
case connected
/// App should display an interactive page for the user to chose which values to reveal
case selectNamespaces([ItemsRequest])
/// App should display the fact that a certain percentage of data has been sent
/// - Parameters:
/// - 0: The number of chunks sent to far
/// - 1: The total number of chunks to be sent
case uploadProgress(Int, Int)
/// App should display a success message and offer to close the page
case success
}
12 changes: 10 additions & 2 deletions Sources/WalletSdk/MDocBLEUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@ let readerServer2ClientCharacteristicId = CBUUID(string: "00000007-A123-48CE-896
let readerIdentCharacteristicId = CBUUID(string: "00000008-A123-48CE-896B-4C76973373E6")
let readerL2CAPCharacteristicId = CBUUID(string: "0000000B-A123-48CE-896B-4C76973373E6")

enum MdocHolderBleError {
/// When discovery or communication with the peripheral fails
case peripheral(String)
/// When Bluetooth is unusable (e.g. unauthorized).
case bluetooth(CBCentralManager)
}

enum MDocBLECallback {
case done
case connected
case message(Data)
case error(String)
case progress(String)
case error(MdocHolderBleError)
/// Chunks sent so far and total number of chunks to be sent
case uploadProgress(Int, Int)
}

protocol MDocBLEDelegate: AnyObject {
Expand Down
57 changes: 9 additions & 48 deletions Sources/WalletSdk/MDocHolderBLECentral.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,12 @@ class MDocHolderBLECentral: NSObject {
chunk.reverse()
chunk.append(firstByte)
chunk.reverse()
let percentage = 100 * writingQueueChunkIndex / writingQueueTotalChunks
self.callback.callback(message: .progress("Sending chunks: \(percentage)%"))
self.callback.callback(message: .uploadProgress(writingQueueChunkIndex, writingQueueTotalChunks))
peripheral?.writeValue(_: chunk,
for: writeCharacteristic!,
type: CBCharacteristicWriteType.withoutResponse)
} else {
self.callback.callback(message: .progress("Sending chunks: 100%"))
self.callback.callback(message: .uploadProgress(writingQueueTotalChunks, writingQueueTotalChunks))
writingQueue = nil
}
}
Expand Down Expand Up @@ -210,48 +209,10 @@ class MDocHolderBLECentral: NSObject {

extension MDocHolderBLECentral: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOff:
print("Is Powered Off.")
case .poweredOn:
print("Is Powered On.")
if central.state == .poweredOn {
startScanning()
case .unsupported:
print("Is Unsupported.")
case .unauthorized:
if #available(iOS 13.1, *) {
switch CBManager.authorization {
case .denied:
print("Authorization denied")
case .restricted:
print("Authorization restricted")
case .allowedAlways:
print("Authorized")
case .notDetermined:
print("Authorization not determined")
@unknown default:
print("Unknown authorization error")
}
} else {
switch central.authorization {
case .denied:
print("Authorization denied")
case .restricted:
print("Authorization restricted")
case .allowedAlways:
print("Authorized")
case .notDetermined:
print("Authorization not determined")
@unknown default:
print("Unknown authorization error")
}
}
case .unknown:
print("Unknown")
case .resetting:
print("Resetting")
@unknown default:
print("Error")
} else {
self.callback.callback(message: .error(.bluetooth(central)))
}
}
func centralManager(_ central: CBCentralManager,
Expand All @@ -275,7 +236,7 @@ extension MDocHolderBLECentral: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if (error) != nil {
self.callback.callback(
message: MDocBLECallback.error("Error discovering services: \(error!.localizedDescription)")
message: .error(.peripheral("Error discovering services: \(error!.localizedDescription)"))
)
return
}
Expand All @@ -290,7 +251,7 @@ extension MDocHolderBLECentral: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if (error) != nil {
self.callback.callback(
message: MDocBLECallback.error("Error discovering characteristics: \(error!.localizedDescription)")
message: .error(.peripheral("Error discovering characteristics: \(error!.localizedDescription)"))
)
return
}
Expand All @@ -299,7 +260,7 @@ extension MDocHolderBLECentral: CBPeripheralDelegate {
do {
try self.processCharacteristics(peripheral: peripheral, characteristics: characteristics)
} catch {
self.callback.callback(message: MDocBLECallback.error("\(error)"))
self.callback.callback(message: .error(.peripheral("\(error)")))
centralManager?.cancelPeripheralConnection(peripheral)
}
}
Expand All @@ -310,7 +271,7 @@ extension MDocHolderBLECentral: CBPeripheralDelegate {
print("Processing data")
try self.processData(peripheral: peripheral, characteristic: characteristic)
} catch {
self.callback.callback(message: MDocBLECallback.error("\(error)"))
self.callback.callback(message: .error(.peripheral("\(error)")))
centralManager?.cancelPeripheralConnection(peripheral)
}
}
Expand Down
Loading