Skip to content

Commit 9196327

Browse files
committed
scan: add --every flag to support periodic scanning
1 parent 344abfa commit 9196327

File tree

6 files changed

+107
-49
lines changed

6 files changed

+107
-49
lines changed

count.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56
"os"
67
"path/filepath"
@@ -13,7 +14,7 @@ type FileCount struct {
1314
Errors []error
1415
}
1516

16-
func FileCounter(root string) *FileCount {
17+
func FileCounter(ctx context.Context, root string) *FileCount {
1718
count := &FileCount{
1819
Chan: make(chan int64),
1920
}
@@ -26,6 +27,10 @@ func FileCounter(root string) *FileCount {
2627
log.Printf("error walking path %s: %v", path, err)
2728
return nil
2829
}
30+
31+
if ctx.Err() != nil {
32+
return ctx.Err()
33+
}
2934
counter++
3035

3136
if info.IsDir() {

internal/cache/cache.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (fc *FileCache) Save() error {
104104
return fmt.Errorf("failed to create cache directory: %v", err)
105105
}
106106

107-
log.Printf("Saving file cache to %s", fc.cachePath)
107+
log.Debugf("Saving file cache to %s", fc.cachePath)
108108
return fc.cache.SaveToFile(fc.cachePath)
109109
}
110110

internal/processors/nats/nats.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ func (np *natsProcessor) Process(path string, msg types.ScannedFile) error {
168168
return fmt.Errorf("failed to encrypt message: %v", err)
169169
}
170170
publishData = encryptedData
171-
log.Debugf("Message encrypted: %d bytes -> %d bytes", len(plainData), len(publishData))
172171
} else {
173172
publishData = plainData
174173
}

internal/scanner/scanner.go

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,13 @@ func (s *DirectoryScanner) incCounter() {
125125
}
126126

127127
func (s *DirectoryScanner) ScanDirectory(ctx context.Context, processor processors.Processor) (int64, error) {
128-
defer s.pool.Stop()
129-
defer s.cache.Save()
128+
defer func() {
129+
s.pool.Stop()
130+
err := s.cache.Save()
131+
if err != nil {
132+
log.Errorf("Error saving cache: %v", err)
133+
}
134+
}()
130135

131136
hostname, err := os.Hostname()
132137
if err != nil {
@@ -140,28 +145,35 @@ func (s *DirectoryScanner) ScanDirectory(ctx context.Context, processor processo
140145
if ctx.Err() != nil {
141146
return ctx.Err()
142147
}
148+
149+
if err != nil {
150+
log.Errorf("Error accessing %q: %v", path, err)
151+
return err
152+
}
153+
154+
count++
143155
s.incCounter()
144156

145157
if s.ignoreHidden && info.IsDir() && len(info.Name()) > 1 && info.Name()[0] == '.' {
146-
log.Printf("ignoring hidden directory: %s", path)
158+
log.Debugf("ignoring hidden directory: %s", path)
147159
return filepath.SkipDir
148160
}
149161

150162
if s.ignoreHidden && info.Name()[0] == '.' {
151-
log.Printf("ignoring hidden file: %s", path)
163+
log.Debugf("ignoring hidden file: %s", path)
152164
return nil
153165
}
154166

155167
// Skip files that cannot be accessed.
156168
absPath, err := filepath.Abs(path)
157169
if err != nil {
158-
log.Printf("Error accessing %q: %v", path, err)
170+
log.Debugf("Error accessing %q: %v", path, err)
159171
return nil
160172
}
161173

162174
// Skip ignored directories
163175
if info.IsDir() && slices.Contains(ignoredDirectories, info.Name()) {
164-
log.Printf("ignoring directory %s", path)
176+
log.Debugf("ignoring directory %s", path)
165177
return filepath.SkipDir
166178
}
167179

@@ -172,21 +184,20 @@ func (s *DirectoryScanner) ScanDirectory(ctx context.Context, processor processo
172184

173185
// return if the file is not a regular file
174186
if !info.Mode().IsRegular() {
175-
//log.Printf("Warn: not a regular file %q", path)
176187
return nil
177188
}
178189

179190
// Skip ignored files
180191
if slices.Contains(ignoredFiles, info.Name()) {
181-
log.Printf("ignoring file %s", path)
192+
log.Debugf("ignoring file %s", path)
182193
return nil
183194
}
184195

185196
// ignoreList is a list of regular expressions to ignore
186197
for _, pattern := range s.ignoreList {
187198
matched, _ := regexp.MatchString(pattern, absPath)
188199
if matched {
189-
log.Printf("ignoring path match %s", path)
200+
log.Debugf("ignoring path match %s", path)
190201
if info.IsDir() {
191202
return filepath.SkipDir
192203
}
@@ -226,18 +237,15 @@ func (s *DirectoryScanner) ScanDirectory(ctx context.Context, processor processo
226237
Hostname: hostname,
227238
}
228239

240+
log.Debugf("Processing file %s\n", absPath)
229241
err = processor.Process(absPath, msg)
230242
if err != nil {
231-
if ctx.Err() != nil {
232-
return ctx.Err()
233-
}
234-
log.Errorf("failed processing %q: %v", path, err)
243+
log.Errorf("failed processing %q: %v", absPath, err)
235244
}
245+
log.Debugf("Marking file %s processed\n", absPath)
236246
s.cache.MarkFileProcessed(absPath, fileHash)
237247
return nil
238248
}
239-
240-
count++
241249
s.pool.Submit(f)
242250
return nil
243251
})

main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,18 @@ func main() {
6868
Name: "ca-cert",
6969
Usage: "TLS CA cert",
7070
},
71+
&cli.StringFlag{
72+
Name: "every",
73+
Usage: "Run the scanner regularly. Interval specified in seconds(s), minutes(m) or hours(h)",
74+
},
7175
},
7276
Action: func(c *cli.Context) error {
7377
if c.Bool("debug") {
7478
os.Setenv("HASHUP_DEBUG", "1")
7579
}
80+
if c.String("every") != "" {
81+
return runEvery(c)
82+
}
7683
return runScanner(c)
7784
},
7885
},

scanner.go

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ import (
66
"fmt"
77
"io"
88
"os"
9-
"os/signal"
109
"path/filepath"
1110
"strings"
12-
"syscall"
1311
"time"
1412

1513
"github.com/rubiojr/hashup/internal/cache"
@@ -20,11 +18,34 @@ import (
2018
"github.com/urfave/cli/v2"
2119
)
2220

21+
func runEvery(c *cli.Context) error {
22+
d, err := time.ParseDuration(c.String("every"))
23+
if err != nil {
24+
return fmt.Errorf("failed to parse duration: %v", err)
25+
}
26+
27+
ticker := time.NewTicker(d)
28+
defer ticker.Stop()
29+
30+
for {
31+
select {
32+
case <-ticker.C:
33+
err := runScanner(c)
34+
if err != nil {
35+
log.Errorf("failed to run scanner: %v", err)
36+
}
37+
case <-c.Context.Done():
38+
return c.Context.Err()
39+
}
40+
}
41+
}
42+
2343
func runScanner(clictx *cli.Context) error {
2444
cfg, err := config.LoadConfigFromCLI(clictx)
2545
if err != nil {
2646
return fmt.Errorf("failed to load config: %v", err)
2747
}
48+
2849
encryptionKey := cfg.Main.EncryptionKey
2950
if encryptionKey == "" {
3051
return fmt.Errorf("encryption key is required")
@@ -44,15 +65,6 @@ func runScanner(clictx *cli.Context) error {
4465
log.SetOutput(io.Discard)
4566
}
4667

47-
var fileCount int64
48-
// Count and print the number of files to be indexed
49-
go func() {
50-
tnow := time.Now()
51-
fileCount = <-FileCounter(rootDir).Chan
52-
elapsed := time.Since(tnow)
53-
log.Printf("Counted %d files in %s\n", fileCount, elapsed)
54-
}()
55-
5668
var ignoreList []string
5769
if clictx.String("ignore-file") != "" {
5870
var err error
@@ -62,6 +74,15 @@ func runScanner(clictx *cli.Context) error {
6274
}
6375
}
6476

77+
var fileCount int64
78+
// Count and print the number of files to be indexed
79+
go func() {
80+
tnow := time.Now()
81+
fileCount = <-FileCounter(clictx.Context, rootDir).Chan
82+
elapsed := time.Since(tnow)
83+
log.Debugf("Counted %d files in %s\n", fileCount, elapsed)
84+
}()
85+
6586
scannerOpts := []scanner.Option{
6687
scanner.WithIgnoreList(ignoreList),
6788
scanner.WithIgnoreHidden(clictx.Bool("ignore-hidden")),
@@ -70,14 +91,20 @@ func runScanner(clictx *cli.Context) error {
7091
scanner := scanner.NewDirectoryScanner(rootDir, scannerOpts...)
7192

7293
var pCounter int64
94+
counterChan := scanner.CounterChan()
7395
go func() {
74-
for range scanner.CounterChan() {
75-
pCounter++
76-
if fileCount != 0 {
77-
percent := float64(pCounter) / float64(fileCount) * 100
78-
fmt.Printf("Scanned [%d/%d] files (%.0f%%)\r", pCounter, fileCount, percent)
79-
} else {
80-
fmt.Printf("Scanned %d files\r", pCounter)
96+
for {
97+
select {
98+
case <-clictx.Done():
99+
return
100+
case <-counterChan:
101+
pCounter++
102+
if fileCount != 0 {
103+
percent := float64(pCounter) / float64(fileCount) * 100
104+
fmt.Printf("Scanned [%d/%d] files (%.0f%%)\r", pCounter, fileCount, percent)
105+
} else {
106+
fmt.Printf("Scanned %d files\r", pCounter)
107+
}
81108
}
82109
}
83110
}()
@@ -102,14 +129,19 @@ func runScanner(clictx *cli.Context) error {
102129
}
103130

104131
go func() {
105-
for stats := range statsChan {
106-
processedFiles++
107-
skippedFiles += int64(stats.SkippedFiles)
108-
queuedFiles += int64(stats.QueuedFiles)
132+
for {
133+
select {
134+
case <-clictx.Done():
135+
return
136+
case stats := <-statsChan:
137+
processedFiles++
138+
skippedFiles += int64(stats.SkippedFiles)
139+
queuedFiles += int64(stats.QueuedFiles)
140+
}
109141
}
110142
}()
111143

112-
ctx, cancel := context.WithCancel(context.Background())
144+
ctx, cancel := context.WithCancel(clictx.Context)
113145
defer cancel()
114146
processor, err := nats.NewNATSProcessor(
115147
ctx,
@@ -124,7 +156,7 @@ func runScanner(clictx *cli.Context) error {
124156
}
125157
defer processor.Close()
126158

127-
signalCh := make(chan os.Signal, 1)
159+
done := make(chan bool)
128160
go func() {
129161
startTime := time.Now()
130162
fmt.Printf("Starting directory scan in %s...\n", rootDir)
@@ -134,21 +166,28 @@ func runScanner(clictx *cli.Context) error {
134166
log.Errorf("error scanning directory: %v", err)
135167
}
136168
elapsed := time.Since(startTime)
137-
fmt.Printf("Completed scanning %d files in %q in %v\r", count, rootDir, elapsed)
138-
cancel()
139-
signalCh <- syscall.SIGINT
169+
fmt.Printf("Completed scanning %d files in %q in %v\r\n", count, rootDir, elapsed)
170+
done <- true
140171
}()
141172

142-
signal.Notify(signalCh, syscall.SIGINT, syscall.SIGTERM)
143-
<-signalCh
144-
log.Printf("Shutting down...")
145-
cancel()
173+
Loop:
174+
for {
175+
select {
176+
case <-done:
177+
log.Printf("Shutting down...")
178+
break Loop
179+
case <-ctx.Done():
180+
log.Printf("Context canceled")
181+
break Loop
182+
}
183+
}
146184
fmt.Printf(
147185
"Processed %d files, skipped %d files, queued %d files\n",
148186
processedFiles,
149187
skippedFiles,
150188
queuedFiles,
151189
)
190+
152191
return nil
153192
}
154193

0 commit comments

Comments
 (0)