1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
package watcher
import (
"context"
"fmt"
"os"
"time"
)
// FileWatcher monitors a file for changes based on modification time.
type FileWatcher struct {
filePath string
pollInterval time.Duration
lastModTime time.Time
}
// NewFileWatcher creates a new file watcher.
func NewFileWatcher(filePath string, pollInterval time.Duration) *FileWatcher {
return &FileWatcher{
filePath: filePath,
pollInterval: pollInterval,
}
}
// Watch starts watching the file and returns a channel that signals changes.
// If the file doesn't exist yet, it will wait until it appears.
func (fw *FileWatcher) Watch(ctx context.Context) (<-chan struct{}, error) {
changeChan := make(chan struct{}, 1)
go func() {
defer close(changeChan)
ticker := time.NewTicker(fw.pollInterval)
defer ticker.Stop()
fileExists := false
// Wait for file to exist
for !fileExists {
select {
case <-ctx.Done():
return
case <-ticker.C:
info, err := os.Stat(fw.filePath)
if err != nil {
// File doesn't exist yet, keep waiting
fmt.Printf("Waiting for file to exist: %s\n", fw.filePath)
continue
}
// File now exists!
fileExists = true
fw.lastModTime = info.ModTime()
// Send initial change to process file
changeChan <- struct{}{}
fmt.Printf("File detected, starting watch: %s\n", fw.filePath)
}
}
// Now watch for changes
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
info, err := os.Stat(fw.filePath)
if err != nil {
// File might have been deleted or is temporarily unavailable
continue
}
modTime := info.ModTime()
if modTime.After(fw.lastModTime) {
fw.lastModTime = modTime
changeChan <- struct{}{}
}
}
}
}()
return changeChan, nil
}
// GetLastModTime returns the last known modification time of the file.
func (fw *FileWatcher) GetLastModTime() time.Time {
return fw.lastModTime
}
|