// Copyright 2024 schukai GmbH // SPDX-License-Identifier: proprietary package watch import ( "context" "sync" "time" ) type Watcher struct { cache sync.Map mutex sync.Mutex cancel context.CancelFunc active bool } // NewWatcher creates a new Watcher. // This Function starts a goroutine that checks the cache every hour and removes expired entries. // It is in your responsibility to call Stop() on the Watcher, after you are done with it. func NewWatcher() *Watcher { ctx, cancel := context.WithCancel(context.Background()) w := &Watcher{ cache: sync.Map{}, cancel: cancel, mutex: sync.Mutex{}, active: true, } go w.cacheCleaner(ctx) return w } // Stop stops the cleaner goroutine. func (w *Watcher) Stop() { w.cancel() } // IsActive returns true if the watcher is active, false if not. // An not active watcher can not be used to add, remove or check files. func (w *Watcher) IsActive() bool { w.mutex.Lock() defer w.mutex.Unlock() return w.active } func (w *Watcher) setActive() { w.mutex.Lock() defer w.mutex.Unlock() w.active = true } func (w *Watcher) setInactive() { w.mutex.Lock() defer w.mutex.Unlock() w.active = false } // cacheCleaner is a goroutine that checks the cache every hour and removes expired entries. func (w *Watcher) cacheCleaner(ctx context.Context) { ticker := time.NewTicker(1 * time.Hour) defer ticker.Stop() for { select { case <-ticker.C: now := time.Now() w.cache.Range(func(key, value interface{}) bool { hash := value.(FileHash) if hash.expiresAt.Before(now) { w.cache.Delete(key) } return true }) case <-ctx.Done(): w.setInactive() return } } }