Cut private message path over to ConversationStore

All private-message mutations now flow through store intents:
coordinators, PrivateChatManager (its @Published dicts deleted - now
read-only views over the store), outbound sends, delivery status, and
chat migration. The O(1) store dedup replaces the full-scan duplicate
check; insertion order is maintained by the store so sanitizeChat's
re-sort is a documented no-op. Both bootstrapper Combine bridges and
the Task.yield store synchronization are deleted.

ChatViewModel.privateChats/unreadPrivateMessages become get-only derived
views (measured: naive rebuild equals a change-invalidated cache within
noise, so the simpler form stays). Feature models still read the legacy
store, fed by a coalescing LegacyConversationStoreBridge (one mirror
per burst, marked for step-5 deletion).

pipeline.privateIngest: 9.6k -> 14.7k msg/s (+53%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jack
2026-06-11 12:19:11 +02:00
co-authored by Claude Fable 5
parent ac3a2f2d34
commit 879d8cba12
33 changed files with 1293 additions and 545 deletions
+4 -2
View File
@@ -31,7 +31,7 @@ protocol CommandContextProvider: AnyObject {
var activeChannel: ChannelID { get }
var selectedPrivateChatPeer: PeerID? { get }
var blockedUsers: Set<String> { get }
var privateChats: [PeerID: [BitchatMessage]] { get set }
var privateChats: [PeerID: [BitchatMessage]] { get }
var idBridge: NostrIdentityBridge { get }
// MARK: - Peer Lookup
@@ -43,6 +43,8 @@ protocol CommandContextProvider: AnyObject {
func startPrivateChat(with peerID: PeerID)
func sendPrivateMessage(_ content: String, to peerID: PeerID)
func clearCurrentPublicTimeline()
/// Empties the peer's chat (single-writer store intent for `/clear`).
func clearPrivateChat(_ peerID: PeerID)
func sendPublicRaw(_ content: String)
// MARK: - System Messages
@@ -160,7 +162,7 @@ final class CommandProcessor {
private func handleClear() -> CommandResult {
if let peerID = contextProvider?.selectedPrivateChatPeer {
contextProvider?.privateChats[peerID]?.removeAll()
contextProvider?.clearPrivateChat(peerID)
} else {
contextProvider?.clearCurrentPublicTimeline()
}