mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 02:25:20 +00:00
Fix Bluetooth errors and improve store-and-forward
- Add peripheral state checks before all write operations - Fix 'can only accept commands while connected' errors - Check characteristic write properties to avoid ATT errors - Preserve original timestamps in store-and-forward messages - Only log crypto errors once per peer to reduce noise - Store-and-forward now correctly maintains message ordering The timestamp preservation ensures messages appear in the correct chronological order even when delivered later via store-and-forward.
This commit is contained in:
@@ -255,6 +255,7 @@
|
|||||||
DEVELOPMENT_TEAM = L3N5LHJD5Y;
|
DEVELOPMENT_TEAM = L3N5LHJD5Y;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = bitchat/Info.plist;
|
INFOPLIST_FILE = bitchat/Info.plist;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -264,9 +265,12 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat;
|
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat;
|
||||||
PRODUCT_NAME = bitchat;
|
PRODUCT_NAME = bitchat;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
|
SUPPORTS_MACCATALYST = NO;
|
||||||
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
|
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -282,6 +286,7 @@
|
|||||||
DEVELOPMENT_TEAM = L3N5LHJD5Y;
|
DEVELOPMENT_TEAM = L3N5LHJD5Y;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = bitchat/Info.plist;
|
INFOPLIST_FILE = bitchat/Info.plist;
|
||||||
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -291,9 +296,12 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat;
|
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat;
|
||||||
PRODUCT_NAME = bitchat;
|
PRODUCT_NAME = bitchat;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
|
SUPPORTS_MACCATALYST = NO;
|
||||||
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
|
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = 1;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|||||||
+5
-1
@@ -41,9 +41,13 @@
|
|||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class BluetoothMeshService: NSObject {
|
|||||||
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
|
||||||
|
private var loggedCryptoErrors = Set<String>() // Track which peers we've logged crypto errors for
|
||||||
|
|
||||||
weak var delegate: BitchatDelegate?
|
weak var delegate: BitchatDelegate?
|
||||||
private let encryptionService = EncryptionService()
|
private let encryptionService = EncryptionService()
|
||||||
@@ -210,6 +211,7 @@ class BluetoothMeshService: NSObject {
|
|||||||
self.broadcastPacket(messages[0])
|
self.broadcastPacket(messages[0])
|
||||||
} else if let dest = destination,
|
} else if let dest = destination,
|
||||||
let peripheral = self.connectedPeripherals[dest],
|
let peripheral = self.connectedPeripherals[dest],
|
||||||
|
peripheral.state == .connected,
|
||||||
let characteristic = self.peripheralCharacteristics[peripheral] {
|
let characteristic = self.peripheralCharacteristics[peripheral] {
|
||||||
if let data = messages[0].toBinaryData() {
|
if let data = messages[0].toBinaryData() {
|
||||||
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
||||||
@@ -225,6 +227,7 @@ class BluetoothMeshService: NSObject {
|
|||||||
self?.broadcastPacket(message)
|
self?.broadcastPacket(message)
|
||||||
} else if let dest = destination,
|
} else if let dest = destination,
|
||||||
let peripheral = self?.connectedPeripherals[dest],
|
let peripheral = self?.connectedPeripherals[dest],
|
||||||
|
peripheral.state == .connected,
|
||||||
let characteristic = self?.peripheralCharacteristics[peripheral] {
|
let characteristic = self?.peripheralCharacteristics[peripheral] {
|
||||||
if let data = message.toBinaryData() {
|
if let data = message.toBinaryData() {
|
||||||
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
||||||
@@ -627,9 +630,11 @@ class BluetoothMeshService: NSObject {
|
|||||||
|
|
||||||
// Also try targeted send if we have the peripheral
|
// Also try targeted send if we have the peripheral
|
||||||
if let peripheral = connectedPeripherals[peerID],
|
if let peripheral = connectedPeripherals[peerID],
|
||||||
|
peripheral.state == .connected,
|
||||||
let characteristic = peripheral.services?.first(where: { $0.uuid == BluetoothMeshService.serviceUUID })?.characteristics?.first(where: { $0.uuid == BluetoothMeshService.characteristicUUID }) {
|
let characteristic = peripheral.services?.first(where: { $0.uuid == BluetoothMeshService.serviceUUID })?.characteristics?.first(where: { $0.uuid == BluetoothMeshService.characteristicUUID }) {
|
||||||
// Also sending targeted announce
|
// Also sending targeted announce
|
||||||
peripheral.writeValue(data, for: characteristic, type: .withResponse)
|
let writeType: CBCharacteristicWriteType = characteristic.properties.contains(.write) ? .withResponse : .withoutResponse
|
||||||
|
peripheral.writeValue(data, for: characteristic, type: writeType)
|
||||||
} else {
|
} else {
|
||||||
// No peripheral found for targeted send
|
// No peripheral found for targeted send
|
||||||
}
|
}
|
||||||
@@ -768,10 +773,10 @@ class BluetoothMeshService: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create stored message
|
// Create stored message with original packet timestamp preserved
|
||||||
let storedMessage = StoredMessage(
|
let storedMessage = StoredMessage(
|
||||||
packet: packet,
|
packet: packet,
|
||||||
timestamp: Date(),
|
timestamp: Date(timeIntervalSince1970: TimeInterval(packet.timestamp)),
|
||||||
messageID: messageID,
|
messageID: messageID,
|
||||||
isForFavorite: isForFavorite
|
isForFavorite: isForFavorite
|
||||||
)
|
)
|
||||||
@@ -850,21 +855,14 @@ class BluetoothMeshService: NSObject {
|
|||||||
guard let peripheral = peripheral,
|
guard let peripheral = peripheral,
|
||||||
peripheral.state == .connected else { return }
|
peripheral.state == .connected else { return }
|
||||||
|
|
||||||
// Create a new packet with fresh timestamp
|
// Send the original packet with preserved timestamp
|
||||||
let updatedPacket = BitchatPacket(
|
// This maintains message ordering for store-and-forward
|
||||||
type: storedMessage.packet.type,
|
let packetToSend = storedMessage.packet
|
||||||
senderID: storedMessage.packet.senderID,
|
|
||||||
recipientID: storedMessage.packet.recipientID,
|
|
||||||
timestamp: UInt64(Date().timeIntervalSince1970),
|
|
||||||
payload: storedMessage.packet.payload,
|
|
||||||
signature: storedMessage.packet.signature,
|
|
||||||
ttl: storedMessage.packet.ttl
|
|
||||||
)
|
|
||||||
|
|
||||||
if let data = updatedPacket.toBinaryData(),
|
if let data = packetToSend.toBinaryData(),
|
||||||
characteristic.properties.contains(.writeWithoutResponse) {
|
characteristic.properties.contains(.writeWithoutResponse) {
|
||||||
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
||||||
// Sent cached message
|
// Sent cached message with original timestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1020,7 +1018,10 @@ class BluetoothMeshService: NSObject {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
print("[CRYPTO] Failed to verify signature from \(senderID): \(error)")
|
if !loggedCryptoErrors.contains(senderID) {
|
||||||
|
print("[CRYPTO] Failed to verify signature from \(senderID): \(error)")
|
||||||
|
loggedCryptoErrors.insert(senderID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1084,7 +1085,10 @@ class BluetoothMeshService: NSObject {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
print("[CRYPTO] Failed to verify signature from \(senderID): \(error)")
|
if !loggedCryptoErrors.contains(senderID) {
|
||||||
|
print("[CRYPTO] Failed to verify signature from \(senderID): \(error)")
|
||||||
|
loggedCryptoErrors.insert(senderID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user