This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package watcher
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// FileWatcher periodically checks a file for changes using MD5 hash
|
||||
type FileWatcher struct {
|
||||
path string
|
||||
period time.Duration
|
||||
lastHash string
|
||||
onChange func()
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
// NewFileWatcher creates a new file watcher that polls the file at the given period
|
||||
func NewFileWatcher(path string, period time.Duration, onChange func()) *FileWatcher {
|
||||
return &FileWatcher{
|
||||
path: path,
|
||||
period: period,
|
||||
lastHash: "",
|
||||
onChange: onChange,
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// hashFile computes an MD5 hash of the file contents
|
||||
func (fw *FileWatcher) hashFile() (string, error) {
|
||||
data, err := os.ReadFile(fw.path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read file %s: %w", fw.path, err)
|
||||
}
|
||||
return fmt.Sprintf("%x", md5.Sum(data)), nil
|
||||
}
|
||||
|
||||
// Start begins polling the file for changes in a goroutine
|
||||
func (fw *FileWatcher) Start() {
|
||||
// Compute initial hash
|
||||
hash, err := fw.hashFile()
|
||||
if err != nil {
|
||||
log.Printf("WATCHER: initial hash computation failed for %s: %v", fw.path, err)
|
||||
} else {
|
||||
fw.lastHash = hash
|
||||
}
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(fw.period)
|
||||
defer ticker.Stop()
|
||||
|
||||
log.Printf("WATCHER: started watching %s every %s", fw.path, fw.period)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-fw.stopCh:
|
||||
log.Printf("WATCHER: stopped watching %s", fw.path)
|
||||
return
|
||||
case <-ticker.C:
|
||||
hash, err := fw.hashFile()
|
||||
if err != nil {
|
||||
log.Printf("WATCHER: failed to hash %s: %v", fw.path, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if hash != fw.lastHash {
|
||||
log.Printf("WATCHER: detected change in %s", fw.path)
|
||||
fw.lastHash = hash
|
||||
if fw.onChange != nil {
|
||||
fw.onChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Stop signals the watcher goroutine to stop
|
||||
func (fw *FileWatcher) Stop() {
|
||||
close(fw.stopCh)
|
||||
}
|
||||
Reference in New Issue
Block a user