move feature from meta-sort to meta-core

This commit is contained in:
Pierre
2026-01-25 22:01:25 +01:00
parent 768942d28b
commit 7d9d502912
69 changed files with 12831 additions and 13 deletions
+138
View File
@@ -0,0 +1,138 @@
package watcher
import (
"sync"
"time"
)
// Debouncer delays events to ensure file stability
type Debouncer struct {
delay time.Duration
pending map[string]*PendingEvent
mu sync.Mutex
callback func(FileEvent)
stopped bool
}
// NewDebouncer creates a new debouncer with the specified delay
func NewDebouncer(delay time.Duration) *Debouncer {
return &Debouncer{
delay: delay,
pending: make(map[string]*PendingEvent),
}
}
// SetCallback sets the callback function for debounced events
func (d *Debouncer) SetCallback(cb func(FileEvent)) {
d.mu.Lock()
defer d.mu.Unlock()
d.callback = cb
}
// Add adds or updates an event in the debounce queue
func (d *Debouncer) Add(event FileEvent) {
d.mu.Lock()
defer d.mu.Unlock()
if d.stopped {
return
}
key := event.Path
if existing, ok := d.pending[key]; ok {
// Update existing pending event
existing.LastSeen = time.Now()
existing.Event = event // Update with latest event info
// Reset timer
existing.Timer.Reset(d.delay)
} else {
// Create new pending event
now := time.Now()
pending := &PendingEvent{
Event: event,
FirstSeen: now,
LastSeen: now,
}
// Create timer
pending.Timer = time.AfterFunc(d.delay, func() {
d.flush(key)
})
d.pending[key] = pending
}
}
// flush emits the event and removes it from pending
func (d *Debouncer) flush(key string) {
d.mu.Lock()
pending, ok := d.pending[key]
if !ok {
d.mu.Unlock()
return
}
// Check if enough time has passed since last activity
elapsed := time.Since(pending.LastSeen)
if elapsed < d.delay {
// Reset timer for remaining time
remaining := d.delay - elapsed
pending.Timer.Reset(remaining)
d.mu.Unlock()
return
}
// Remove from pending
delete(d.pending, key)
callback := d.callback
event := pending.Event
d.mu.Unlock()
// Call callback outside of lock
if callback != nil {
callback(event)
}
}
// Stop stops the debouncer and cancels all pending events
func (d *Debouncer) Stop() {
d.mu.Lock()
defer d.mu.Unlock()
d.stopped = true
// Cancel all timers
for _, pending := range d.pending {
pending.Timer.Stop()
}
// Clear pending
d.pending = make(map[string]*PendingEvent)
}
// PendingCount returns the number of pending events
func (d *Debouncer) PendingCount() int {
d.mu.Lock()
defer d.mu.Unlock()
return len(d.pending)
}
// FlushAll immediately flushes all pending events
func (d *Debouncer) FlushAll() {
d.mu.Lock()
keys := make([]string, 0, len(d.pending))
for key := range d.pending {
keys = append(keys, key)
}
d.mu.Unlock()
for _, key := range keys {
d.flush(key)
}
}