This document describes the Transport protocol, which defines the abstract interface for all communication backends in BitChat. The protocol enables pluggable networking implementations (Bluetooth mesh and Nostr relays) to be used interchangeably throughout the codebase. This abstraction is the foundation of BitChat's dual-transport architecture.
For the specific implementations of this protocol, see Bluetooth Mesh Network (BLEService) and Nostr Relay Management. For how transports are selected and coordinated, see Message Routing and Transport Selection.
Sources: bitchat/Services/Transport.swift1-87
The Transport protocol provides a unified interface that hides the implementation details of different networking backends. Both BLEService and NostrTransport conform to this protocol, allowing higher-level components like ChatViewModel, MessageRouter, and PrivateChatManager to interact with networking without knowing which transport is handling a particular message.
| Principle | Implementation |
|---|---|
| Protocol-Oriented | All transport-specific code hidden behind Transport protocol bitchat/Services/Transport.swift90-154 |
| Delegate-Based Events | BitchatDelegate for messages, TransportEventDelegate for transport-domain events, TransportPeerEventsDelegate for peer state bitchat/Services/Transport.swift92-96 |
| Synchronous Snapshots | currentPeerSnapshots() provides immediate state access bitchat/Services/Transport.swift99 |
| Optional Extensions | Default implementations for file transfers and verification bitchat/Services/Transport.swift168-180 |
Sources: bitchat/Services/Transport.swift90-180
Sources: bitchat/Services/Transport.swift90-154 bitchat/Services/NostrTransport.swift7-15 bitchatTests/ProtocolContractTests.swift8-14
The TransportPeerSnapshot struct provides a point-in-time view of a peer's state, designed to be lightweight and thread-safe for cross-component communication.
| Field | Type | Purpose |
|---|---|---|
peerID | PeerID | 8-byte ephemeral network identifier bitchat/Services/Transport.swift9 |
nickname | String | Peer's self-reported display name bitchat/Services/Transport.swift10 |
isConnected | Bool | Direct connection exists (BLE) or N/A (Nostr) bitchat/Services/Transport.swift11 |
noisePublicKey | Data? | 32-byte Curve25519 public key (revealed after handshake) bitchat/Services/Transport.swift12 |
lastSeen | Date | Most recent activity timestamp bitchat/Services/Transport.swift13 |
isVerified | Bool | Whether the peer's announce was signature-verified (courier tier gate) bitchat/Services/Transport.swift14-15 |
Key Characteristics:
Sources: bitchat/Services/Transport.swift8-31
The BitchatDelegate protocol receives all message-related events from transports. This is the primary event sink for incoming messages, receipts, and peer lifecycle events.
Sources: bitchatTests/ProtocolContractTests.swift8-14
The TransportEventDelegate protocol provides a more granular, typed event sink for transport-domain events. This is preferred for new code over BitchatDelegate.
The TransportEvent enum encapsulates various events:
.messageReceived(BitchatMessage) bitchat/Services/Transport.swift69.publicMessageReceived(peerID:nickname:content:timestamp:messageID:) bitchat/Services/Transport.swift70.noisePayloadReceived(peerID:type:payload:timestamp:) bitchat/Services/Transport.swift71.groupMessageReceived(payload:timestamp:) bitchat/Services/Transport.swift73-74.publicVoiceFrameReceived(peerID:nickname:payload:timestamp:) bitchat/Services/Transport.swift75-77.peerConnected(PeerID) bitchat/Services/Transport.swift78.peerDisconnected(PeerID) bitchat/Services/Transport.swift79.peerListUpdated([PeerID]) bitchat/Services/Transport.swift80.peerSnapshotsUpdated([TransportPeerSnapshot]) bitchat/Services/Transport.swift81.messageDeliveryStatusUpdated(messageID:status:) bitchat/Services/Transport.swift82.bluetoothStateUpdated(CBManagerState) bitchat/Services/Transport.swift83Sources: bitchat/Services/Transport.swift68-88
TransportPeerEventsDelegate provides reactive peer state updates, primarily consumed by higher-level services for maintaining the global peer list.
Integration Example:
Transport implementation detects peer connection change.peerEventsDelegate?.didUpdatePeerSnapshots(updatedSnapshots) bitchat/Services/Transport.swift96UnifiedPeerService) receives callback on @MainActor.Sources: bitchat/Services/Transport.swift96
| Method | Purpose |
|---|---|
startServices() | Initialize transport (e.g., start Bluetooth advertising/scanning) bitchat/Services/Transport.swift107 |
stopServices() | Graceful shutdown (e.g., disconnect peers, stop advertising) bitchat/Services/Transport.swift108 |
emergencyDisconnectAll() | Immediate termination for panic mode or privacy triggers bitchat/Services/Transport.swift109 |
Sources: bitchat/Services/Transport.swift107-109
Noise Session States:
The LazyHandshakeState enum tracks the lifecycle of an encrypted session:
.none: No session, no handshake attempted bitchat/Services/Transport.swift132.handshaking: Currently in handshake process..established: Session ready for use.Sources: bitchat/Services/Transport.swift102-154
The distinction between "connected", "reachable", "promptly deliverable", and "securely deliverable" is critical for intelligent routing:
| Method | Meaning |
|---|---|
isPeerConnected(_:) | Direct connection active (e.g., BLE peripheral connected) bitchat/Services/Transport.swift112 |
isPeerReachable(_:) | Can route message to peer (e.g., Connected OR recently seen via mesh relay OR reachable via Nostr) bitchat/Services/Transport.swift113 |
canDeliverPromptly(to:) | A send to this peer is likely to leave the device promptly (e.g., active relay connection for Nostr, or direct BLE connection) bitchat/Services/Transport.swift114-118 |
canDeliverSecurely(to:) | A send to this peer can complete an end-to-end encrypted delivery right now (e.g., an established Noise session) bitchat/Services/Transport.swift119-126 |
Sources: bitchat/Services/Transport.swift112-126
The protocol supports both broadcast-style public messages and E2E encrypted private messages.
Sources: bitchat/Services/Transport.swift157-159
| Method | Purpose |
|---|---|
sendReadReceipt(_:to:) | Notify sender message was read bitchat/Services/Transport.swift160 |
sendDeliveryAck(for:to:) | Confirm message delivery bitchat/Services/Transport.swift163 |
sendFavoriteNotification(to:isFavorite:) | Notify peer of favorite status change bitchat/Services/Transport.swift161 |
sendBroadcastAnnounce() | Send presence announcement to the network bitchat/Services/Transport.swift162 |
Sources: bitchat/Services/Transport.swift160-164
The Transport protocol provides default implementations for features not supported by all backends (e.g., a Nostr transport might not support local file transfers or QR challenges).
BitChat implements a "hold-in-memory" pattern for file transfers (BCH-01-002), where files are only written to disk after user acceptance.
Sources: bitchat/Services/Transport.swift164-166 bitchat/Services/Transport.swift177-180
Used by VerificationService to bind ephemeral mesh identities to cryptographic fingerprints during a physical handshake.
Sources: bitchat/Services/Transport.swift171-172
These methods are for sending encoded voice burst packets, typically used by mesh transports for real-time audio communication.
Sources: bitchat/Services/Transport.swift174-175
This method is used to clear public messages associated with a specific peer from the archive.
Sources: bitchat/Services/Transport.swift176
BLEService is the primary implementation for local mesh networking. It handles CoreBluetooth state, mesh topology, and fragmentation. It uses BitchatDelegate and TransportEventDelegate to emit events for UI consumption bitchat/Services/Transport.swift92-94
NostrTransport provides global reachability by wrapping messages into Nostr events bitchat/Services/NostrTransport.swift7-15 It uses a reachability cache (synced with favorites) to determine if a peer is accessible via relays bitchat/Services/NostrTransport.swift134-141 NostrTransport also implements an AckPacer to throttle outbound acknowledgements (read receipts, delivered acks) to avoid relay rate limits bitchat/Services/NostrTransport.swift93-128 This pacer is shared across NostrTransport instances to ensure global throttling bitchat/Services/NostrTransport.swift130
Components like PrivateChatManager use the Transport abstraction (via messageRouter) to send acks and receipts without implementation coupling bitchat/Services/PrivateChatManager.swift33-35 The MessageRouter queries transport capabilities like isPeerReachable and canDeliverPromptly to select the best path bitchat/Services/MessageRouter.swift79-81
Transports are governed by TransportConfig, which defines timing and buffer limits such as nostrReadAckInterval bitchat/Services/NostrTransport.swift99
Sources: bitchat/Services/NostrTransport.swift7-15 bitchat/Services/NostrTransport.swift93-128 bitchat/Services/NostrTransport.swift99 bitchat/Services/NostrTransport.swift130 bitchat/Services/NostrTransport.swift134-141 bitchat/Services/PrivateChatManager.swift33-35 bitchat/Services/Transport.swift92-94 bitchat/Services/MessageRouter.swift79-81
Refresh this wiki
This wiki was recently refreshed. Please wait 6 days to refresh again.