Subsystem to monitor IMAP mailbox for new messages. Introduces: - intake: worker that uses IDLE or polling to detect new emails. - imap: client wrapper for connection management and IMAP commands. - filter: logic for IMAP search and sender allow-list. - tracker: concurrency control to prevent processing the same UID twice. - backoff: for handling connection retries with jitter.
44 lines
1.0 KiB
Go
44 lines
1.0 KiB
Go
// Package tracker prevents duplicate processing of IMAP messages by
|
|
// maintaining a transient set of active, in-flight UIDs.
|
|
package tracker
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/emersion/go-imap/v2"
|
|
)
|
|
|
|
// Tracker ensures unique concurrent processing of messages.
|
|
// This prevents race conditions where a message might be fetched
|
|
// again before its initial processing completes.
|
|
type Tracker struct {
|
|
mu sync.Mutex
|
|
ids map[imap.UID]struct{}
|
|
}
|
|
|
|
// New returns a ready-to-use Tracker.
|
|
func New() *Tracker {
|
|
return &Tracker{
|
|
ids: make(map[imap.UID]struct{}),
|
|
}
|
|
}
|
|
|
|
// TryAcquire attempts to claim exclusive processing rights for a UID.
|
|
// It returns true only if the UID is not currently being tracked.
|
|
func (t *Tracker) TryAcquire(uid imap.UID) bool {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
if _, exists := t.ids[uid]; exists {
|
|
return false
|
|
}
|
|
t.ids[uid] = struct{}{}
|
|
return true
|
|
}
|
|
|
|
// Release relinquishes processing rights for a UID, allowing it to be acquired again.
|
|
func (t *Tracker) Release(uid imap.UID) {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
delete(t.ids, uid)
|
|
}
|