83 lines
1.8 KiB
Go
83 lines
1.8 KiB
Go
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)
|
|
} |