2026-02-24 11:29:17 +00:00
|
|
|
package wecom
|
|
|
|
|
|
|
|
|
|
import "sync"
|
|
|
|
|
|
|
|
|
|
const wecomMaxProcessedMessages = 1000
|
|
|
|
|
|
2026-02-24 12:56:28 +00:00
|
|
|
// 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 {
|
2026-02-24 11:29:17 +00:00
|
|
|
if maxEntries <= 0 {
|
|
|
|
|
maxEntries = wecomMaxProcessedMessages
|
|
|
|
|
}
|
2026-02-24 12:56:28 +00:00
|
|
|
return &MessageDeduplicator{
|
|
|
|
|
msgs: make(map[string]bool, maxEntries),
|
|
|
|
|
ring: make([]string, maxEntries),
|
|
|
|
|
max: maxEntries,
|
2026-02-24 12:18:54 +00:00
|
|
|
}
|
2026-02-24 12:56:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MarkMessageProcessed marks msgID as processed and returns false for duplicates.
|
|
|
|
|
func (d *MessageDeduplicator) MarkMessageProcessed(msgID string) bool {
|
|
|
|
|
d.mu.Lock()
|
|
|
|
|
defer d.mu.Unlock()
|
2026-02-24 12:18:54 +00:00
|
|
|
|
2026-02-24 12:56:28 +00:00
|
|
|
// 1. Check for duplicate
|
|
|
|
|
if d.msgs[msgID] {
|
2026-02-24 11:29:17 +00:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-24 12:56:28 +00:00
|
|
|
// 2. Evict the oldest message at our current ring position (if any)
|
|
|
|
|
oldestID := d.ring[d.idx]
|
|
|
|
|
if oldestID != "" {
|
|
|
|
|
delete(d.msgs, oldestID)
|
2026-02-24 11:29:17 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-24 12:56:28 +00:00
|
|
|
// 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
|
|
|
|
|
|
2026-02-24 11:29:17 +00:00
|
|
|
return true
|
|
|
|
|
}
|