Improve BLE connection stability and message reliability (#318)

* Remove sequence numbers from protocol

- Remove sequenceNumber field from BitchatPacket struct
- Update BinaryProtocol to not encode/decode sequence numbers (header size reduced from 17 to 13 bytes)
- Replace sequence-based duplicate detection with content-based using packet ID hash
- Update packet ID generation to use SHA256(senderID + timestamp + type + payload prefix)
- Remove all sequence tracking variables and methods
- Simplify duplicate detection to rely on timestamp and content hashing

* Fix connection stability issues

- Increase peer availability check interval from 5 to 15 seconds
- Fix availability logic to not mark connected peers as unavailable
- Add BLE connection keepalive timer (20s) to prevent iOS timeouts
- Fix missing delivery ACKs by passing peripheral context through Noise decryption
- Reduce identity announce frequency from 2 to 10 seconds minimum
- Remove unnecessary identity announces on connection
- Debounce identity cache keychain saves (2 second delay)
- Add message retry notification handler in ChatViewModel
- Fix version negotiation redundancy by checking existing negotiations
- Keep Noise sessions for already-connected peers

* Fix build errors in message retry handler

- Fix reference to 'displayedMessages' - should be 'messages'
- Fix sendMessage call signature to use individual parameters instead of message object
- Both iOS and macOS builds now succeed

* Fix remaining connection stability issues

- Fix duplicate identity announces with content-based deduplication
- Simplify peripheral mapping with cleaner temp ID to peer ID transitions
- Improve graceful leave detection across peer ID rotations
- Track previousPeerID from announcements to maintain state
- Add time-based cleanup for gracefully left peers

* Fix connection stability issues

- Add special duplicate detection for identity announces
- Simplify peripheral mapping with dedicated structure
- Improve graceful leave detection with peer ID rotation handling
- Track graceful leave timestamps for cleanup
- Transfer states properly during peer ID rotation

* Improve BLE connection stability and message reliability

- Increase peer availability timeout from 5s to 15s to prevent flapping
- Add BLE keepalive timer with 30s interval to maintain connections
- Fix missing delivery ACKs by passing peripheral context through decryption
- Reduce identity announce frequency from 2s to 10s minimum interval
- Add keychain save debouncing with 2s delay to prevent excessive writes
- Implement message retry system for failed deliveries to favorites
- Fix version negotiation redundancy by checking existing state
- Add special duplicate detection for identity announcements
- Implement graceful leave detection with peer ID rotation support
- Simplify peripheral mapping to reduce complexity
- Fix switch statement structure issues causing build errors

These changes significantly improve connection stability, eliminate peer availability flapping, and ensure reliable message delivery.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
jack
2025-07-25 02:40:51 +02:00
committed by GitHub
co-authored by jack
parent 86726d7033
commit 809e222a31
6 changed files with 344 additions and 188 deletions
+3 -17
View File
@@ -19,12 +19,11 @@ extension Data {
}
// Binary Protocol Format:
// Header (Fixed 17 bytes):
// Header (Fixed 13 bytes):
// - Version: 1 byte
// - Type: 1 byte
// - TTL: 1 byte
// - Timestamp: 8 bytes (UInt64)
// - SequenceNumber: 4 bytes (UInt32)
// - Flags: 1 byte (bit 0: hasRecipient, bit 1: hasSignature)
// - PayloadLength: 2 bytes (UInt16)
//
@@ -35,7 +34,7 @@ extension Data {
// - Signature: 64 bytes (if hasSignature flag set)
struct BinaryProtocol {
static let headerSize = 17
static let headerSize = 13
static let senderIDSize = 8
static let recipientIDSize = 8
static let signatureSize = 64
@@ -78,11 +77,6 @@ struct BinaryProtocol {
data.append(UInt8((packet.timestamp >> (i * 8)) & 0xFF))
}
// Sequence number (4 bytes, big-endian)
for i in (0..<4).reversed() {
data.append(UInt8((packet.sequenceNumber >> (i * 8)) & 0xFF))
}
// Flags
var flags: UInt8 = 0
if packet.recipientID != nil {
@@ -171,13 +165,6 @@ struct BinaryProtocol {
}
offset += 8
// Sequence number
let sequenceData = unpaddedData[offset..<offset+4]
let sequenceNumber = sequenceData.reduce(0) { result, byte in
(result << 8) | UInt32(byte)
}
offset += 4
// Flags
let flags = unpaddedData[offset]; offset += 1
let hasRecipient = (flags & Flags.hasRecipient) != 0
@@ -253,8 +240,7 @@ struct BinaryProtocol {
timestamp: timestamp,
payload: payload,
signature: signature,
ttl: ttl,
sequenceNumber: sequenceNumber
ttl: ttl
)
}
}
+2 -5
View File
@@ -139,9 +139,8 @@ struct BitchatPacket: Codable {
let payload: Data
let signature: Data?
var ttl: UInt8
let sequenceNumber: UInt32 // New field for duplicate detection
init(type: UInt8, senderID: Data, recipientID: Data?, timestamp: UInt64, payload: Data, signature: Data?, ttl: UInt8, sequenceNumber: UInt32 = 0) {
init(type: UInt8, senderID: Data, recipientID: Data?, timestamp: UInt64, payload: Data, signature: Data?, ttl: UInt8) {
self.version = 1
self.type = type
self.senderID = senderID
@@ -150,11 +149,10 @@ struct BitchatPacket: Codable {
self.payload = payload
self.signature = signature
self.ttl = ttl
self.sequenceNumber = sequenceNumber
}
// Convenience initializer for new binary format
init(type: UInt8, ttl: UInt8, senderID: String, payload: Data, sequenceNumber: UInt32 = 0) {
init(type: UInt8, ttl: UInt8, senderID: String, payload: Data) {
self.version = 1
self.type = type
// Convert hex string peer ID to binary data (8 bytes)
@@ -173,7 +171,6 @@ struct BitchatPacket: Codable {
self.payload = payload
self.signature = nil
self.ttl = ttl
self.sequenceNumber = sequenceNumber
}
var data: Data? {