* Make location notes robust: durable relay subscriptions, failure decay, auto-recovery
Location notes (and geohash chat / DMs) intermittently stopped showing
events because the Nostr relay layer lost subscriptions and blacklisted
relays:
- Replay active subscriptions on every relay (re)connect. Relays drop
REQs with the socket; previously a drop silently killed the
subscription on that relay for the rest of the session. Durable
subscription intent now also survives disconnect()/resetAllConnections
(background -> foreground).
- Keep failed REQ sends queued instead of dropping them.
- Raise the EOSE fallback from a fixed 2s Timer to a 10s injected
schedule (Tor needs more than 2s), and settle EOSE trackers when a
relay disconnects before answering so initial load doesn't stall.
- Decay "permanently failed" relay markings after a 10-minute cooldown;
previously ~9 minutes of outage (or one DNS hiccup) excluded a relay
until app restart, with nothing resetting it on macOS.
- Make geo relay selection deterministic (distance, then host) so
publishers and subscribers with the same directory agree on relays.
- Post .geoRelayDirectoryDidRefresh after a directory fetch and let
LocationNotesManager auto-resubscribe out of the "no relays" state
instead of requiring a manual retry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Guard subscription activation on connection identity
A REQ send completion from a dead socket could land after
handleDisconnection cleared the relay's subscriptions and re-mark the
subscription active, making the next connection skip the durable replay
and leave that relay silent. Only mark a subscription active if the
completing socket is still the relay's live connection.
Regression test defers send completions in the mock so the stale
completion deterministically interleaves between disconnect and
reconnect.
Addresses Codex review on #1333.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Refactor BLE transport event handling
* Make image output paths unique
* Keep queued Nostr read receipts alive
* Refine BLE ingress fanout
* Rediscover BLE service after invalidation
* Extract BLE notification retry buffer
* Extract BLE inbound write buffer
* Extract BLE fragment assembly buffer
* Tidy secure log handling from device run
* Extract BLE outbound fragment scheduler
* Harden app CI media tests
* Redact BLE message content from logs
* Extract BLE Noise session queues
* Fix BLE read receipt UI updates
* Allow self-authored RSR ingress replies
* Harden read receipt queue test timing
* Extract BLE outbound policy and incoming file storage
* Avoid duplicate BLE link snapshots during send
* Canonicalize Nostr relay URLs
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Run GeoRelay fetch pipeline off main actor
* Capture GeoRelay session before detached fetch
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* Extract Tor into a separate module
* Add Tor package as a dependency for iOS & macOS targets
* Move `tor-nolzma.xcframework` inside Tor
* Remove `libz` from Frameworks as its linked in Tor
* Remove stray `.gitkeep` from macOS target membership
* Fix missing import and access control for modularized Tor
- Add import Tor to NetworkActivationService
- Make TorManager.shutdownCompletely() public for external access
* Fix tor-nolzma.xcframework structure for Xcode builds
- Add missing Info.plist files to all framework slices
- Restructure macOS framework to use deep bundle format (Versions/)
- Keep iOS frameworks as shallow bundles (standard for iOS)
This fixes the Xcode build errors while maintaining SPM compatibility.
* Remove stale xcframework references from Xcode project
Xcode cleaned up old direct references to tor-nolzma.xcframework
since it's now managed internally by the Tor Swift package.
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
* feat(tor): Tor-by-default scaffold and integration
- Add TorManager with static/dlopen start, torrc generation, SOCKS probe
- Add TorURLSession; route Nostr/Web fetches via SOCKS proxy
- Add chat system messages for Tor status; show progress (macOS) and ready
- Disable ControlPort bootstrap monitor on iOS; keep it on macOS
- Make Tor waits non-blocking; avoid main-actor stalls on startup
- Queue & flush Nostr subscriptions on relay connect; skip duplicates
- Always rewrite torrc at launch to fix iOS container path mismatches
- Link libz; add project wiring for tor-nolzma.xcframework
- Minor fixes: SOCKS probe resumeOnce guard, entitlement for network.server (macOS)
* iOS: deterministic Tor recovery + 100% gating; BLE-first; session rebuild
- Restart/wake Tor on foreground via ControlPort (ACTIVE/SHUTDOWN),
avoid restarts during bootstrap; add NWPathMonitor to trigger checks
- Use NWConnection control polling for GETINFO; remove blocking CFStream
readers to avoid QoS inversions; compute readiness from SOCKS + 100%
- Rebuild TorURLSession on resume; reset Nostr connections to rebind
- Gate all internet after full bootstrap; keep BLE mesh startup fast
- Fix Swift 6 capture issues; hop UI updates to @MainActor
- Remove Tor progress spam; persist initial "starting tor..." system message
* UI: show Tor system messages only in geohash channels (not mesh)
- Gate "starting tor..." and readiness/timeout messages to geohash view
- Add helper addGeohashOnlySystemMessage() to avoid posting to mesh timeline
- Persist system messages in geohash backing store via addPublicSystemMessage()
* Relays: treat repeated -1011 handshake failures as permanent; skip reconnects
- Classify NSURLErrorBadServerResponse as permanent and stop retrying
- Filter permanently-failed relays from subscribe/connect attempts
- Avoid reconnect scheduling for permanently failed relays
* Embed Tor via tor_api; deterministic restart + Nostr gating; add Tor notifications
- Run Tor via tor_api in a dedicated thread with OwningControllerFD
- Cleanly stop Tor on background; restart on .active (single instance)
- Avoid fallback to tor_main/dlopen; add is-running check to prevent duplicates
- Fix argv lifetime in C glue to avoid strcmp crash on start
- Gate Nostr connect/subscribe/send until Tor is fully ready
- Rebuild URLSession + reset relays after Tor readiness (scene-based)
- Remove TorDidBecomeReady double-reset and appDidBecomeActive resubscribe
- Add TorWillRestart/TorDidBecomeReady notifications and chat system messages
- Debounce path-change restarts; ACTIVE poke first; coalesce subs; cancel stale reconnect timers
- Project: add CTorHost.c and TorNotifications.swift to targets; fix libz.tbd path
* Defer Nostr setup logs until Tor is ready; fix subscribe coalescing and reconnect generation
- Move "Connecting to Nostr relays" log after awaitReady()
- Log "Queuing subscription" when Tor not ready; only coalesce when handler exists
- Clear coalescer on unsubscribe
- Cancel stale reconnect timers using connectionGeneration
- Remove app-level TorDidBecomeReady reset to avoid duplicate reconnects
- Debounce path-change restarts
* Gate Nostr init/subscription logs until Tor is ready
- ChatViewModel: await Tor readiness before initializing Nostr and logging
- Only log GeoDM subscription when Tor is ready to avoid early noise
* Make Nostr connect single-sourced; defer DM subscription until connected
- Remove duplicate connect call from ChatViewModel; let scene-based flow connect
- Setup DM subscription once on first connection via sink
- Reduce early subscription send/cancel noise after Tor restarts
* On launch, queue Nostr subscriptions without initiating connects; let centralized connect handle it
- In subscribe(), if no connections exist, just list relays and queue subs
- Avoids early send/cancel churn before connect() runs post-Tor-ready
* Always queue subscriptions and flush on connection; avoid immediate sends
- Prevents early send/cancel churn at launch and during reconnects
- If relays are already connected, flush immediately; otherwise pending until connected
* UI: scope Tor restart messages to geohash channels; skip initial foreground restart on cold launch to avoid confusing system message in #mesh
* geo: disable background sampling + notifications\n- Gate sampling to foreground only (beginGeohashSampling, watchers)\n- Suppress geohash activity notifications unless app is active\n- Stop sampling explicitly on background scene phase
* Update BitchatApp.swift
Co-authored-by: asmo <asmogo@protonmail.com>
* Update BitchatApp.swift
Co-authored-by: asmo <asmogo@protonmail.com>
* Update BitchatApp.swift
Co-authored-by: asmo <asmogo@protonmail.com>
* Update bitchat/BitchatApp.swift
Co-authored-by: asmo <asmogo@protonmail.com>
* Update bitchat/BitchatApp.swift
Co-authored-by: asmo <asmogo@protonmail.com>
* fix(iOS App): resolve merge artifacts in scenePhase handler\n- Remove duplicate didEnterBackground state\n- Fix switch/if braces and logic for foreground restart gating
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: asmo <asmogo@protonmail.com>
* feat(georelay): route geohash kind 20000 via nearest relays; add GeoRelayDirectory; target geohash subscriptions; avoid duplicate connections
* feat(georelay): fetch daily from remote CSV with fallback to bundled; cache to app support; prefetch on app load
* fix(georelay): make CSV parser nonisolated and call as Self.parseCSV to satisfy Swift 6 actor isolation
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>