Refactor/ble nostr boundaries (#449)

* Refactor: move Nostr embedding and TLVs out of BLE; add NostrEmbeddedBitChat, Packets, PeerIDUtils; centralize MessageDeduplicator; update ChatViewModel to use new helpers; remove AI_CONTEXT.md and CLAUDE.md

* Rename class to BLEService with compatibility alias; move mention parsing out of BLE; emit low-level BLE events to delegate; unify hex helpers; accept 64-hex in isPeerConnected; add PeerIDResolver

* Project: rename file to BLEService.swift and update Xcode project; keep typealias SimplifiedBluetoothService = BLEService for compatibility

* Remove SimplifiedBluetoothService alias; update app code to use BLEService explicitly

* Tests: rename MockSimplifiedBluetoothService to MockBLEService; update typealiases and Xcode project

* Docs: update comments to refer to BLEService (tests, protocol, noise service)

* Tests: rename SimplifiedBluetoothServiceTests to BLEServiceTests; update project references and class names

* Introduce Transport protocol; BLEService conforms; document delegate-only event pattern in BLEService; keep publishers internal for UnifiedPeerService

* Adopt Transport end-to-end: add TransportPeerSnapshot + publishers; BLEService maps to Transport snapshots; UnifiedPeerService consumes Transport; ChatViewModel holds Transport

* Fix Transport integration: replace getPeerFingerprint with getFingerprint(for:); update PrivateChatManager and CommandProcessor to use Transport; add BLEService.getFingerprint(for:); update PeerManager to use Transport

* Refactor transport and BLE/Nostr layers; unify UI events; fix MainActor isolation

- Rename SimplifiedBluetoothService to BLEService and slim responsibilities
- Introduce Transport protocol and peerEventsDelegate for UI updates
- Add NostrTransport and MessageRouter to route PM/read/favorite via BLE or Nostr
- Centralize TLVs, PeerID utils, and MessageDeduplicator outside BLE
- Update UnifiedPeerService and ChatViewModel to use Transport and delegate events
- Fix MainActor isolation: route delegate calls via Task on MainActor; update notifyUI helper
- Adjust related files and tests accordingly

* BLEService: remove internal publishers; switch to delegate-only events

- Drop legacy messages/peers/fullPeers publishers
- Provide lightweight peerSnapshotSubject only to satisfy Transport
- Rework publishFullPeerData to build snapshots from internal state and notify delegate + subject
- Remove all peersPublisher.send call sites
- Keep UnifiedPeerService on delegate updates exclusively

* Remove inlined Nostr send helpers from ChatViewModel; route via MessageRouter

- Replace direct Nostr sends (PM, ACKs, favorites) with MessageRouter
- Add router method for delivery ACKs and implement NostrTransport.sendDeliveryAck
- Simplify ChatViewModel favorite notification path to use router
- Keep Nostr receive handling intact; reduce duplication

* Fix ReadReceipt initializer usage in ChatViewModel (readerID + readerNickname)

* Fix unused variable warning: replace shadowed 'nostrPubkey' bind with boolean check in ChatViewModel

* Fix queued PM format: use TLV for pending messages after Noise handshake

- Pending messages (including first-time favorite notifications) now use the same TLV encoding as normal sends
- Ensures ChatViewModel can decode on first send, even if handshake completes after queuing

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
jack
2025-08-17 15:17:04 +02:00
committed by GitHub
co-authored by jack
parent 3ebfa85e90
commit 6fbf7eee25
25 changed files with 873 additions and 1647 deletions
@@ -1,5 +1,5 @@
//
// SimplifiedBluetoothServiceTests.swift
// BLEServiceTests.swift
// bitchatTests
//
// This is free and unencumbered software released into the public domain.
@@ -10,13 +10,13 @@ import XCTest
import CoreBluetooth
@testable import bitchat
final class SimplifiedBluetoothServiceTests: XCTestCase {
final class BLEServiceTests: XCTestCase {
var service: MockSimplifiedBluetoothService!
var service: MockBLEService!
override func setUp() {
super.setUp()
service = MockSimplifiedBluetoothService()
service = MockBLEService()
service.myPeerID = "TEST1234"
service.mockNickname = "TestUser"
}
@@ -24,7 +24,7 @@ final class PrivateChatE2ETests: XCTestCase {
bob = createMockService(peerID: TestConstants.testPeerID2, nickname: TestConstants.testNickname2)
charlie = createMockService(peerID: TestConstants.testPeerID3, nickname: TestConstants.testNickname3)
// Delivery tracking is now handled internally by SimplifiedBluetoothService
// Delivery tracking is now handled internally by BLEService
}
override func tearDown() {
@@ -92,13 +92,13 @@ final class PrivateChatE2ETests: XCTestCase {
// MARK: - Delivery Acknowledgment Tests
// NOTE: DeliveryTracker has been removed in SimplifiedBluetoothService.
// NOTE: DeliveryTracker has been removed in BLEService.
// Delivery tracking is now handled internally.
// MARK: - Message Retry Tests
// NOTE: MessageRetryService has been removed in SimplifiedBluetoothService.
// NOTE: MessageRetryService has been removed in BLEService.
// Retry logic is now handled internally.
@@ -337,4 +337,4 @@ final class PrivateChatE2ETests: XCTestCase {
peer1.simulateConnectedPeer(peer2.peerID)
peer2.simulateConnectedPeer(peer1.peerID)
}
}
}
@@ -1,5 +1,5 @@
//
// MockSimplifiedBluetoothService.swift
// MockBLEService.swift
// bitchatTests
//
// This is free and unencumbered software released into the public domain.
@@ -10,10 +10,10 @@ import Foundation
import CoreBluetooth
@testable import bitchat
// Mock implementation that mimics SimplifiedBluetoothService behavior
class MockSimplifiedBluetoothService: NSObject {
// Mock implementation that mimics BLEService behavior
class MockBLEService: NSObject {
// MARK: - Properties matching SimplifiedBluetoothService
// MARK: - Properties matching BLEService
weak var delegate: BitchatDelegate?
var myPeerID: String = "MOCK1234"
@@ -46,7 +46,7 @@ class MockSimplifiedBluetoothService: NSObject {
super.init()
}
// MARK: - Methods matching SimplifiedBluetoothService
// MARK: - Methods matching BLEService
func setNickname(_ nickname: String) {
self.myNickname = nickname
@@ -224,4 +224,7 @@ class MockSimplifiedBluetoothService: NSObject {
func sendPrivateMessage(_ content: String, to recipientPeerID: String, recipientNickname: String, messageID: String? = nil) {
sendPrivateMessage(content, to: recipientPeerID, recipientNickname: recipientNickname, messageID: messageID ?? UUID().uuidString)
}
}
}
// Backward compatibility for older tests
typealias MockSimplifiedBluetoothService = MockBLEService
@@ -10,5 +10,5 @@ import Foundation
import CoreBluetooth
@testable import bitchat
// Compatibility wrapper for old tests - please use MockSimplifiedBluetoothService directly
typealias MockBluetoothMeshService = MockSimplifiedBluetoothService
// Compatibility wrapper for old tests - please use MockBLEService directly
typealias MockBluetoothMeshService = MockBLEService