mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 21:25:22 +00:00
Device-test findings: keychain lock access, GeoDM dedup, sync log clarity (#1397)
Three findings from the July 7 locked-phone test sessions:
- Keychain items move from WhenUnlocked to AfterFirstUnlock: the mesh keeps
running while the device is locked (identity-cache saves failed with
-25308 throughout testing), and a wake-on-proximity relaunch via BLE
state restoration must read the noise keys before the user unlocks. A
one-time SecItemUpdate migration upgrades existing items (retried on next
launch if the device is locked); backup semantics unchanged.
- GeoDM inbound messages dedup by message ID at the handler: outbox retries
re-wrap the same message in fresh gift-wrap events, so relay-level
event-ID dedup can't catch them and every copy ran full processing
(3-6x per message observed). DELIVERED acks still go through
markGeoDeliveryAckSent first, so re-sent copies from a lost ack are
still answered.
- Periodic gossip sync logs now name the type group ("message+fragment").
The five per-type schedules log identical lines when several fire in one
maintenance tick, which reads as duplicated sends (misdiagnosed twice
during testing).
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
jack
Claude Fable 5
parent
f79c2e3e9f
commit
963d3a089f
@@ -227,10 +227,29 @@ extension ChatViewModel: ChatPrivateConversationContext {
|
||||
final class ChatPrivateConversationCoordinator {
|
||||
private unowned let context: any ChatPrivateConversationContext
|
||||
|
||||
// Outbox retries re-wrap the same message in fresh gift-wrap events, so
|
||||
// relay-level event-ID dedup can't catch them; track inbound GeoDM
|
||||
// message IDs so each copy past the first costs one (already-deduped)
|
||||
// ack check and nothing else.
|
||||
private var seenInboundGeoDMIDs: Set<String> = []
|
||||
private var seenInboundGeoDMOrder: [String] = []
|
||||
private static let seenInboundGeoDMCap = 512
|
||||
|
||||
init(context: any ChatPrivateConversationContext) {
|
||||
self.context = context
|
||||
}
|
||||
|
||||
/// Returns `false` if this GeoDM message ID was already handled.
|
||||
private func markInboundGeoDMSeen(_ messageId: String) -> Bool {
|
||||
guard !seenInboundGeoDMIDs.contains(messageId) else { return false }
|
||||
seenInboundGeoDMIDs.insert(messageId)
|
||||
seenInboundGeoDMOrder.append(messageId)
|
||||
if seenInboundGeoDMOrder.count > Self.seenInboundGeoDMCap {
|
||||
seenInboundGeoDMIDs.remove(seenInboundGeoDMOrder.removeFirst())
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func sendPrivateMessage(_ content: String, to peerID: PeerID) {
|
||||
guard !content.isEmpty else { return }
|
||||
|
||||
@@ -408,10 +427,15 @@ final class ChatPrivateConversationCoordinator {
|
||||
guard let pm = PrivateMessagePacket.decode(from: payload.data) else { return }
|
||||
let messageId = pm.messageID
|
||||
|
||||
SecureLogger.info("GeoDM: recv PM <- sender=\(senderPubkey.prefix(8))… mid=\(messageId.prefix(8))…", category: .session)
|
||||
|
||||
// Ack before the dedup guard: a re-sent copy means the sender may not
|
||||
// have our DELIVERED yet, and markGeoDeliveryAckSent dedups the
|
||||
// actual sends.
|
||||
sendDeliveryAckIfNeeded(to: messageId, senderPubKey: senderPubkey, from: id)
|
||||
|
||||
guard markInboundGeoDMSeen(messageId) else { return }
|
||||
|
||||
SecureLogger.info("GeoDM: recv PM <- sender=\(senderPubkey.prefix(8))… mid=\(messageId.prefix(8))…", category: .session)
|
||||
|
||||
if context.isNostrBlocked(pubkeyHexLowercased: senderPubkey) {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user