Refactor/robustness (#446)

* Refactor BitChat for improved robustness and performance

Major refactoring to simplify architecture and fix critical issues:

Architecture Improvements:
- Replace complex BluetoothMeshService with simplified SimplifiedBluetoothService
- Consolidate message routing and peer management into unified services
- Remove redundant caching layers and optimize performance

Bug Fixes:
- Fix critical BLE peer mapping corruption in mesh networks
- Fix encrypted message routing failures in multi-peer scenarios
- Fix app freezes and Main Thread Checker warnings
- Fix BLE message delivery in dual-role connections
- Fix favorite toggle UI not updating instantly
- Fix Nostr offline messaging with 24-hour message filtering

Features:
- Add command processor for chat commands
- Add autocomplete service for mentions and commands
- Improve private chat management with dedicated service
- Add unified peer service for consistent state management

Performance:
- Optimize BLE reconnection speed
- Reduce excessive logging throughout codebase
- Improve message deduplication efficiency
- Optimize UI updates and state management

* Improvements refactor robust (#441)

* remove unused code

* remove more

* TLV for announcement

* restore

* restore

* restore?

* messages tlv too (#442)

* Fix Nostr notification and read receipt issues, add TLV encoding, cleanup unused code

## Notification & Read Receipt Fixes
- Fixed toolbar notification icon appearing incorrectly on app restart for already-read messages
- Fixed read receipts being incorrectly deleted on startup when privateChats was empty
- Fixed messages not being marked as read when opening chat for first time
- Fixed senderPeerID not being updated during message consolidation
- Added startup phase logic to block old messages (>30s) while allowing recent ones
- Fixed unread status checking across all storage locations (ephemeral, stable Noise keys, temporary Nostr IDs)

## TLV Encoding Implementation
- Implemented Type-Length-Value encoding for private message payloads
- Added PrivateMessagePacket struct with TLV encode/decode methods
- Enhanced message structure for better extensibility and robustness

## Code Cleanup
- Removed unused PeerStateManager class and related dependencies
- Removed dead protocol types (DeliveryAck, ProtocolAck/Nack, NoiseIdentityAnnouncement)
- Cleaned up BitchatDelegate by removing unused methods
- Removed excessive debug logging throughout ChatViewModel
- Added test-only ProtocolNack helper for integration tests

## Technical Details
- Messages stored under three ID types: ephemeral peer IDs, stable Noise key hexes, temporary Nostr IDs
- Fixed cleanupOldReadReceipts() to skip when privateChats is empty or during startup
- Updated message consolidation to properly update senderPeerID
- Restored NIP-17 timestamp randomization (±15 minutes) for privacy

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
This commit is contained in:
jack
2025-08-17 01:51:54 +02:00
committed by GitHub
co-authored by jack callebtc
parent 47b0829685
commit 845ffc601b
38 changed files with 6423 additions and 12246 deletions
+12 -12
View File
@@ -287,7 +287,7 @@ final class IntegrationTests: XCTestCase {
// Track identity announcements
nodes["Bob"]!.packetDeliveryHandler = { packet in
if packet.type == MessageType.noiseIdentityAnnounce.rawValue {
if packet.type == 0x04 { // noiseIdentityAnnounce was removed
bobReceivedIdentityAnnounce = true
if aliceReceivedIdentityAnnounce {
expectation.fulfill()
@@ -296,7 +296,7 @@ final class IntegrationTests: XCTestCase {
}
nodes["Alice"]!.packetDeliveryHandler = { packet in
if packet.type == MessageType.noiseIdentityAnnounce.rawValue {
if packet.type == 0x04 { // noiseIdentityAnnounce was removed
aliceReceivedIdentityAnnounce = true
if bobReceivedIdentityAnnounce {
expectation.fulfill()
@@ -347,7 +347,7 @@ final class IntegrationTests: XCTestCase {
let handshakeExpectation = XCTestExpectation(description: "New handshake completed")
nodes["Bob"]!.packetDeliveryHandler = { packet in
if packet.type == MessageType.noiseHandshakeInit.rawValue {
if packet.type == 0x05 { // noiseHandshakeInit was removed
// Bob initiates new handshake after restart
do {
let response = try self.noiseManagers["Alice"]!.handleIncomingHandshake(
@@ -357,7 +357,7 @@ final class IntegrationTests: XCTestCase {
if let resp = response {
// Send response back to Bob
let responsePacket = TestHelpers.createTestPacket(
type: MessageType.noiseHandshakeResp.rawValue,
type: 0x06, // noiseHandshakeResp was removed
payload: resp
)
self.nodes["Bob"]!.simulateIncomingPacket(responsePacket)
@@ -365,7 +365,7 @@ final class IntegrationTests: XCTestCase {
} catch {
XCTFail("Handshake handling failed: \(error)")
}
} else if packet.type == MessageType.noiseHandshakeResp.rawValue && packet.senderID.hexEncodedString() == TestConstants.testPeerID1 {
} else if packet.type == 0x06 // noiseHandshakeResp was removed && packet.senderID.hexEncodedString() == TestConstants.testPeerID1 {
// Final handshake message (message 3 in XX pattern)
handshakeExpectation.fulfill()
}
@@ -552,7 +552,7 @@ final class IntegrationTests: XCTestCase {
let nackData = nack.toBinaryData()
let nackPacket = TestHelpers.createTestPacket(
type: MessageType.protocolNack.rawValue,
type: 0x08, // protocolNack was removed
payload: nackData
)
self.nodes["Alice"]!.simulateIncomingPacket(nackPacket)
@@ -560,7 +560,7 @@ final class IntegrationTests: XCTestCase {
// Bob clears session
self.noiseManagers["Bob"]!.removeSession(for: TestConstants.testPeerID1)
}
} else if packet.type == MessageType.noiseHandshakeInit.rawValue {
} else if packet.type == 0x05 { // noiseHandshakeInit was removed
// Bob receives handshake init from Alice after NACK
do {
let response = try self.noiseManagers["Bob"]!.handleIncomingHandshake(
@@ -569,7 +569,7 @@ final class IntegrationTests: XCTestCase {
)
if let resp = response {
let responsePacket = TestHelpers.createTestPacket(
type: MessageType.noiseHandshakeResp.rawValue,
type: 0x06, // noiseHandshakeResp was removed
payload: resp
)
self.nodes["Alice"]!.simulateIncomingPacket(responsePacket)
@@ -582,7 +582,7 @@ final class IntegrationTests: XCTestCase {
// Setup Alice's handler to clear session on NACK and initiate handshake
nodes["Alice"]!.packetDeliveryHandler = { packet in
if packet.type == MessageType.protocolNack.rawValue {
if packet.type == 0x08 { // protocolNack was removed
// Alice receives NACK - clear session
self.noiseManagers["Alice"]!.removeSession(for: TestConstants.testPeerID2)
@@ -590,14 +590,14 @@ final class IntegrationTests: XCTestCase {
do {
let handshakeInit = try self.noiseManagers["Alice"]!.initiateHandshake(with: TestConstants.testPeerID2)
let handshakePacket = TestHelpers.createTestPacket(
type: MessageType.noiseHandshakeInit.rawValue,
type: 0x05, // noiseHandshakeInit was removed
payload: handshakeInit
)
self.nodes["Bob"]!.simulateIncomingPacket(handshakePacket)
} catch {
XCTFail("Alice failed to initiate handshake: \(error)")
}
} else if packet.type == MessageType.noiseHandshakeResp.rawValue {
} else if packet.type == 0x06 // noiseHandshakeResp was removed {
// Complete handshake
do {
let final = try self.noiseManagers["Alice"]!.handleIncomingHandshake(
@@ -606,7 +606,7 @@ final class IntegrationTests: XCTestCase {
)
if let finalMsg = final {
let finalPacket = TestHelpers.createTestPacket(
type: MessageType.noiseHandshakeResp.rawValue,
type: 0x06, // noiseHandshakeResp was removed
payload: finalMsg
)
self.nodes["Bob"]!.simulateIncomingPacket(finalPacket)