mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 10:25:18 +00:00
Centralize PTT and voice audio-session ownership, harden courier/bridge/outbox delivery and recovery, correct location and delivery-state races, add privacy/release metadata, and ship reproducible universal Arti slices with Release CI coverage. Validated by the full iOS suite, repeated audio/fragment/performance regressions, BitFoundation tests, strict lint and dead-code analysis, universal iOS Release builds, and iOS/macOS archives.
111 lines
4.5 KiB
Swift
111 lines
4.5 KiB
Swift
import BitFoundation
|
|
import Foundation
|
|
|
|
struct BLEOutboundLinkPlan: Equatable {
|
|
let directedPeerHint: PeerID?
|
|
let fragmentChunkSize: Int?
|
|
let selectedLinks: BLEFanoutSelection
|
|
let shouldSpoolDirectedPacket: Bool
|
|
}
|
|
|
|
enum BLEOutboundLinkPlanner {
|
|
static func plan(
|
|
packet: BitchatPacket,
|
|
dataCount: Int,
|
|
peripheralIDs: [String],
|
|
peripheralWriteLimits: [Int],
|
|
centralIDs: [String],
|
|
centralNotifyLimits: [Int],
|
|
ingressRecord: BLEIngressLinkRecord?,
|
|
excludedLinks: Set<BLEIngressLinkID>,
|
|
peripheralPeerBindings: [String: PeerID] = [:],
|
|
centralPeerBindings: [String: PeerID] = [:],
|
|
preferredPeripheralPerPeer: [PeerID: String] = [:],
|
|
directAnnounceTTL: UInt8 = TransportConfig.messageTTLDefault,
|
|
directedOnlyPeer: PeerID?,
|
|
requireDirectPeerLink: Bool = false
|
|
) -> BLEOutboundLinkPlan {
|
|
let directedPeerHint = directedPeerHint(for: packet, explicitPeer: directedOnlyPeer)
|
|
// Direct announces bypass the per-peer duplicate-link collapse so
|
|
// every live link gets bound (see BLEFanoutSelector.selectLinks).
|
|
let isDirectAnnounce = packet.type == MessageType.announce.rawValue && packet.ttl == directAnnounceTTL
|
|
let selectedLinks = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: peripheralIDs,
|
|
centralIDs: centralIDs,
|
|
ingressLink: ingressRecord?.link,
|
|
excludedLinks: excludedLinks,
|
|
peripheralPeerBindings: peripheralPeerBindings,
|
|
centralPeerBindings: centralPeerBindings,
|
|
preferredPeripheralPerPeer: preferredPeripheralPerPeer,
|
|
collapseDuplicatePeerLinks: !isDirectAnnounce,
|
|
directedPeerHint: directedPeerHint,
|
|
requireDirectPeerLink: requireDirectPeerLink,
|
|
packetType: packet.type,
|
|
messageID: BLEOutboundPacketPolicy.messageID(for: packet)
|
|
)
|
|
|
|
// Fragment only for links that this packet can actually use. Looking
|
|
// at every connected link before directed-peer selection lets an
|
|
// unrelated peer's MTU make an oversized directed send look routable,
|
|
// even though every resulting fragment will select zero target links.
|
|
let selectedPeripheralLimits = zip(peripheralIDs, peripheralWriteLimits).compactMap { id, limit in
|
|
selectedLinks.peripheralIDs.contains(id) ? limit : nil
|
|
}
|
|
let selectedCentralLimits = zip(centralIDs, centralNotifyLimits).compactMap { id, limit in
|
|
selectedLinks.centralIDs.contains(id) ? limit : nil
|
|
}
|
|
if let minLimit = minimumLinkLimit(
|
|
peripheralWriteLimits: selectedPeripheralLimits,
|
|
centralNotifyLimits: selectedCentralLimits
|
|
), packet.type != MessageType.fragment.rawValue,
|
|
dataCount > minLimit {
|
|
return BLEOutboundLinkPlan(
|
|
directedPeerHint: directedPeerHint,
|
|
fragmentChunkSize: BLEOutboundPacketPolicy.fragmentChunkSize(forLinkLimit: minLimit),
|
|
selectedLinks: selectedLinks,
|
|
shouldSpoolDirectedPacket: false
|
|
)
|
|
}
|
|
|
|
return BLEOutboundLinkPlan(
|
|
directedPeerHint: directedPeerHint,
|
|
fragmentChunkSize: nil,
|
|
selectedLinks: selectedLinks,
|
|
shouldSpoolDirectedPacket: shouldSpoolDirectedPacket(
|
|
directedPeerHint: directedPeerHint,
|
|
selectedLinks: selectedLinks,
|
|
packetType: packet.type
|
|
)
|
|
)
|
|
}
|
|
|
|
static func directedPeerHint(for packet: BitchatPacket, explicitPeer: PeerID?) -> PeerID? {
|
|
if let explicitPeer { return explicitPeer }
|
|
if let recipient = PeerID(str: packet.recipientID?.hexEncodedString()), !recipient.isEmpty {
|
|
return recipient
|
|
}
|
|
return nil
|
|
}
|
|
|
|
static func minimumLinkLimit(peripheralWriteLimits: [Int], centralNotifyLimits: [Int]) -> Int? {
|
|
[peripheralWriteLimits.min(), centralNotifyLimits.min()]
|
|
.compactMap { $0 }
|
|
.min()
|
|
}
|
|
|
|
static func shouldSpoolDirectedPacket(
|
|
directedPeerHint: PeerID?,
|
|
selectedLinks: BLEFanoutSelection,
|
|
packetType: UInt8
|
|
) -> Bool {
|
|
guard directedPeerHint != nil,
|
|
selectedLinks.peripheralIDs.isEmpty,
|
|
selectedLinks.centralIDs.isEmpty else {
|
|
return false
|
|
}
|
|
|
|
return packetType == MessageType.noiseEncrypted.rawValue ||
|
|
packetType == MessageType.noiseHandshake.rawValue
|
|
}
|
|
}
|