mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 02:45:19 +00:00
Fix macOS crash and Bluetooth errors
- Fix NSInvalidArgumentException crash by adding thread-safe access to peerNicknames - Fix 'can only accept commands while connected' by checking peripheral state - Add safety checks for characteristic write properties - Clean up disconnected peripherals from tracking - Prevent type confusion in getAllConnectedPeerIDs These fixes address the crash when accessing peerNicknames dictionary which could be corrupted by concurrent access from multiple threads.
This commit is contained in:
@@ -30,7 +30,15 @@ class BluetoothMeshService: NSObject {
|
|||||||
private var peripheralCharacteristics: [CBPeripheral: CBCharacteristic] = [:]
|
private var peripheralCharacteristics: [CBPeripheral: CBCharacteristic] = [:]
|
||||||
private var characteristic: CBMutableCharacteristic!
|
private var characteristic: CBMutableCharacteristic!
|
||||||
private var subscribedCentrals: [CBCentral] = []
|
private var subscribedCentrals: [CBCentral] = []
|
||||||
private var peerNicknames: [String: String] = [:]
|
private var _peerNicknames: [String: String] = [:]
|
||||||
|
private var peerNicknames: [String: String] {
|
||||||
|
get {
|
||||||
|
messageQueue.sync { _peerNicknames }
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
messageQueue.async(flags: .barrier) { self._peerNicknames = newValue }
|
||||||
|
}
|
||||||
|
}
|
||||||
private var activePeers: Set<String> = [] // Track all active peers
|
private var activePeers: Set<String> = [] // Track all active peers
|
||||||
private var peerRSSI: [String: NSNumber] = [:] // Track RSSI values for peers
|
private var peerRSSI: [String: NSNumber] = [:] // Track RSSI values for peers
|
||||||
private var peripheralRSSI: [String: NSNumber] = [:] // Track RSSI by peripheral ID during discovery
|
private var peripheralRSSI: [String: NSNumber] = [:] // Track RSSI by peripheral ID during discovery
|
||||||
@@ -717,11 +725,17 @@ class BluetoothMeshService: NSObject {
|
|||||||
guard !peerID.isEmpty,
|
guard !peerID.isEmpty,
|
||||||
peerID != "unknown",
|
peerID != "unknown",
|
||||||
peerID != myPeerID,
|
peerID != myPeerID,
|
||||||
peerID.count <= 8, // Filter out temp IDs
|
peerID.count <= 8 else { // Filter out temp IDs
|
||||||
peerNicknames[peerID] != nil else { // Only include peers who have announced
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safely check if peer has a nickname (thread-safe)
|
||||||
|
let hasNickname = self._peerNicknames[peerID] != nil
|
||||||
|
if hasNickname {
|
||||||
return peerID
|
return peerID
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
// Active peers: \(announcedPeers.count)
|
// Active peers: \(announcedPeers.count)
|
||||||
return Array(announcedPeers).sorted()
|
return Array(announcedPeers).sorted()
|
||||||
@@ -848,7 +862,8 @@ class BluetoothMeshService: NSObject {
|
|||||||
ttl: storedMessage.packet.ttl
|
ttl: storedMessage.packet.ttl
|
||||||
)
|
)
|
||||||
|
|
||||||
if let data = updatedPacket.toBinaryData() {
|
if let data = updatedPacket.toBinaryData(),
|
||||||
|
characteristic.properties.contains(.writeWithoutResponse) {
|
||||||
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
||||||
// Sent cached message
|
// Sent cached message
|
||||||
}
|
}
|
||||||
@@ -887,10 +902,19 @@ class BluetoothMeshService: NSObject {
|
|||||||
// Use withoutResponse for faster transmission when possible
|
// Use withoutResponse for faster transmission when possible
|
||||||
// Only use withResponse for critical messages or when MTU negotiation needed
|
// Only use withResponse for critical messages or when MTU negotiation needed
|
||||||
let writeType: CBCharacteristicWriteType = data.count > 512 ? .withResponse : .withoutResponse
|
let writeType: CBCharacteristicWriteType = data.count > 512 ? .withResponse : .withoutResponse
|
||||||
|
|
||||||
|
// Additional safety check for characteristic properties
|
||||||
|
if characteristic.properties.contains(.write) ||
|
||||||
|
characteristic.properties.contains(.writeWithoutResponse) {
|
||||||
peripheral.writeValue(data, for: characteristic, type: writeType)
|
peripheral.writeValue(data, for: characteristic, type: writeType)
|
||||||
sentToPeripherals += 1
|
sentToPeripherals += 1
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Peripheral not connected
|
// Peripheral not connected - remove from our tracking
|
||||||
|
if let peerID = connectedPeripherals.first(where: { $0.value == peripheral })?.key {
|
||||||
|
connectedPeripherals.removeValue(forKey: peerID)
|
||||||
|
peripheralCharacteristics.removeValue(forKey: peripheral)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No characteristic for peripheral
|
// No characteristic for peripheral
|
||||||
|
|||||||
Reference in New Issue
Block a user