package wecom import "sync" const wecomMaxProcessedMessages = 1000 // MessageDeduplicator provides thread-safe message deduplication using a circular queue (ring buffer) // combined with a hash map. This ensures fast O(1) lookups while naturally evicting the oldest // messages without causing "amnesia cliffs" when the limit is reached. type MessageDeduplicator struct { mu sync.Mutex msgs map[string]bool ring []string idx int max int } // NewMessageDeduplicator creates a new deduplicator with the specified capacity. func NewMessageDeduplicator(maxEntries int) *MessageDeduplicator { if maxEntries <= 0 { maxEntries = wecomMaxProcessedMessages } return &MessageDeduplicator{ msgs: make(map[string]bool, maxEntries), ring: make([]string, maxEntries), max: maxEntries, } } // MarkMessageProcessed marks msgID as processed and returns false for duplicates. func (d *MessageDeduplicator) MarkMessageProcessed(msgID string) bool { d.mu.Lock() defer d.mu.Unlock() // 1. Check for duplicate if d.msgs[msgID] { return false } // 2. Evict the oldest message at our current ring position (if any) oldestID := d.ring[d.idx] if oldestID != "" { delete(d.msgs, oldestID) } // 3. Store the new message d.msgs[msgID] = true d.ring[d.idx] = msgID // 4. Advance the circle queue index d.idx = (d.idx + 1) % d.max return true }