Mesh robustness optimizations (#463)

* Mesh robustness: link-aware fragmentation, relay jitter, connection budget, adaptive scanning; fix BLE queue deadlock

- Link-aware fragmentation using per-link write/notify limits
- Directed fragments for one-to-one; exclude from relays
- Add relay jitter with cancel-on-duplicate to reduce floods
- Cap central links and rate-limit connect attempts with queue
- Foreground duty-cycled scanning when connected; continuous when isolated
- Fix deadlock by avoiding sync on BLE queue when already on it
- Silence Keychain var->let warnings

* Mesh: add relay jitter; dynamic RSSI threshold; candidate scoring/backoff; fix misplaced lines in BLEService extension

* macOS UI: restore mesh peer list when geohash feature is iOS-only by moving mesh list outside iOS switch (ContentView)

* ContentView: add macOS mesh peer list under #else to fix missing People section on macOS

* Refactor People section: extract MeshPeerList and GeohashPeopleList into separate views to reduce SwiftUI type-checking complexity; integrate in ContentView

* BLE: prevent re-fragmentation loops; UI: darker mesh blue + first-row spacing in peer list

* Mesh flood/battery: probabilistic relays, adaptive TTL caps, fragment pacing + scan pause, assembly cap; enable relayed DMs with direct-first then flood fallback.

* Refactor BLEService broadcast: split pad policy, encrypted/direct-first handler, and link-aware sender; simplify broadcastPacket to delegate by type.

* Extract relay decision into RelayController with RelayDecision; simplify handleReceivedPacket to use it.

* Move RelayController and RelayDecision into their own file under Services; keep BLEService leaner.

* UI: adjust mesh blue to a darker, less purple tone; apply consistently for count and #mesh badge.

* Project: include RelayController.swift in target and sync project file changes.

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
jack
2025-08-20 16:27:49 +02:00
committed by GitHub
co-authored by jack
parent 3074fa0fcb
commit 496972dcc9
8 changed files with 755 additions and 398 deletions
+47
View File
@@ -0,0 +1,47 @@
import Foundation
// RelayDecision encapsulates a single relay scheduling choice.
struct RelayDecision {
let shouldRelay: Bool
let newTTL: UInt8
let delayMs: Int
}
// RelayController centralizes flood control policy for relays.
struct RelayController {
static func decide(ttl: UInt8,
senderIsSelf: Bool,
isEncrypted: Bool,
isDirectedFragment: Bool,
isHandshake: Bool,
degree: Int,
highDegreeThreshold: Int) -> RelayDecision {
// Suppress obvious non-relays
if ttl <= 1 || senderIsSelf { return RelayDecision(shouldRelay: false, newTTL: ttl, delayMs: 0) }
// Degree-aware probability to reduce floods in dense graphs
let baseProb: Double
switch degree {
case 0...2: baseProb = 1.0
case 3...4: baseProb = 0.9
case 5...6: baseProb = 0.7
case 7...9: baseProb = 0.55
default: baseProb = 0.45
}
var prob = baseProb
if isHandshake { prob = max(0.3, baseProb - 0.2) }
// Sample a forwarding decision
let shouldRelay = Double.random(in: 0...1) <= prob
// TTL clamping in dense graphs
let ttlCap: UInt8 = degree >= highDegreeThreshold ? 3 : 5
let clamped = max(1, min(ttl, ttlCap))
let newTTL = clamped &- 1
// Short jitter to desynchronize rebroadcasts
let delayMs = Int.random(in: 20...80)
return RelayDecision(shouldRelay: shouldRelay, newTTL: newTTL, delayMs: delayMs)
}
}