mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 01:05:19 +00:00
Cut public message path over to ConversationStore; delete PublicTimelineStore
Mesh and geohash timelines are now store conversations. All public mutation sites flow through store intents; PublicMessagePipeline keeps its 80ms UI batching but commits batches via store appends with each buffered entry carrying its destination conversation (a mid-batch channel switch now flushes instead of dropping the buffer). ChatViewModel.messages becomes a cached get-only view of the active conversation, invalidated through the change subject. The mesh late-insert threshold is consciously removed: it only ever ordered the non-rendered messages copy, so strict timestamp insertion makes the working set agree with rendered order. PublicTimelineStore and the per-message full-array legacy sync are deleted; the coalescing bridge mirrors public conversations for the remaining legacy readers. pipeline.publicIngest: 6.6k -> 9.5k msg/s (+45%); private steady; store.append 237k/s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -42,16 +42,13 @@ private final class MockChatNostrContext: ChatNostrContext {
|
||||
|
||||
// Public timeline & pipeline
|
||||
var messages: [BitchatMessage] = []
|
||||
private(set) var pipelineResetCount = 0
|
||||
private(set) var pipelineChannelUpdates: [ChannelID] = []
|
||||
private(set) var pipelineFlushCount = 0
|
||||
private(set) var refreshedChannels: [ChannelID?] = []
|
||||
private(set) var publicSystemMessages: [String] = []
|
||||
var pendingGeohashSystemMessages: [String] = []
|
||||
private(set) var appendedGeohashMessages: [(message: BitchatMessage, geohash: String)] = []
|
||||
private(set) var synchronizedGeohashes: [String] = []
|
||||
|
||||
func resetPublicMessagePipeline() { pipelineResetCount += 1 }
|
||||
func updatePublicMessagePipelineChannel(_ channel: ChannelID) { pipelineChannelUpdates.append(channel) }
|
||||
func flushPublicMessagePipeline() { pipelineFlushCount += 1 }
|
||||
func refreshVisibleMessages(from channel: ChannelID?) { refreshedChannels.append(channel) }
|
||||
func addPublicSystemMessage(_ content: String) { publicSystemMessages.append(content) }
|
||||
|
||||
@@ -68,8 +65,6 @@ private final class MockChatNostrContext: ChatNostrContext {
|
||||
return true
|
||||
}
|
||||
|
||||
func synchronizePublicConversationStore(forGeohash geohash: String) { synchronizedGeohashes.append(geohash) }
|
||||
|
||||
// Inbound public messages
|
||||
private(set) var handledPublicMessages: [BitchatMessage] = []
|
||||
private(set) var mentionCheckedMessageIDs: [String] = []
|
||||
@@ -441,9 +436,8 @@ struct ChatNostrCoordinatorContextTests {
|
||||
|
||||
coordinator.subscriptions.switchLocationChannel(to: .mesh)
|
||||
|
||||
#expect(context.pipelineResetCount == 1)
|
||||
#expect(context.pipelineFlushCount == 1)
|
||||
#expect(context.activeChannel == .mesh)
|
||||
#expect(context.pipelineChannelUpdates == [.mesh])
|
||||
#expect(context.clearProcessedNostrEventsCount == 1)
|
||||
#expect(context.refreshedChannels == [.mesh])
|
||||
#expect(context.refreshTimerStopCount == 1)
|
||||
@@ -578,7 +572,6 @@ struct GeoPresenceTrackerTests {
|
||||
await drainMainQueue()
|
||||
#expect(context.appendedGeohashMessages.isEmpty)
|
||||
#expect(context.lastGeoNotificationAt["9q8yy"] == recent)
|
||||
#expect(context.synchronizedGeohashes.isEmpty)
|
||||
}
|
||||
|
||||
@Test @MainActor
|
||||
@@ -605,7 +598,7 @@ struct GeoPresenceTrackerTests {
|
||||
#expect(context.appendGeohashMessageIfAbsent(placeholder, toGeohash: "9q8yy"))
|
||||
|
||||
// Cooldown elapsed: the geohash is re-stamped and the append is
|
||||
// attempted (and rejected as a duplicate, so no store sync either).
|
||||
// attempted (and rejected as a duplicate, so no notification either).
|
||||
let stale = Date().addingTimeInterval(-TransportConfig.uiGeoNotifyCooldownSeconds - 1)
|
||||
context.lastGeoNotificationAt["9q8yy"] = stale
|
||||
tracker.cooldownPerGeohash("9q8yy", content: "sampled activity", event: event)
|
||||
@@ -614,7 +607,6 @@ struct GeoPresenceTrackerTests {
|
||||
let stamped = try #require(context.lastGeoNotificationAt["9q8yy"])
|
||||
#expect(stamped > stale)
|
||||
#expect(context.appendedGeohashMessages.count == 1)
|
||||
#expect(context.synchronizedGeohashes.isEmpty)
|
||||
}
|
||||
@Test @MainActor
|
||||
func handleFavoriteNotification_persistsFavoriteAndPostsLocalNotification() async throws {
|
||||
@@ -661,10 +653,9 @@ struct GeoPresenceTrackerTests {
|
||||
coordinator.presence.cooldownPerGeohash("u4pruyd", content: "hello geohash", event: first)
|
||||
await drainMainQueue()
|
||||
|
||||
// Sampled message recorded, store synced, and notification posted.
|
||||
// Sampled message recorded in the store and notification posted.
|
||||
#expect(context.appendedGeohashMessages.map(\.message.id) == [first.id])
|
||||
#expect(context.appendedGeohashMessages.first?.message.sender == "alice#" + String(first.pubkey.suffix(4)))
|
||||
#expect(context.synchronizedGeohashes == ["u4pruyd"])
|
||||
#expect(context.geohashActivityNotifications.count == 1)
|
||||
#expect(context.geohashActivityNotifications.first?.geohash == "u4pruyd")
|
||||
#expect(context.geohashActivityNotifications.first?.bodyPreview == "hello geohash")
|
||||
|
||||
Reference in New Issue
Block a user