101 lines
2.0 KiB
Go
101 lines
2.0 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
|
||
|
"github.com/fsnotify/fsnotify"
|
||
|
)
|
||
|
|
||
|
func WatchDirectory(ctx context.Context, path string, op ...fsnotify.Op) (<-chan string, error) {
|
||
|
watcher, err := fsnotify.NewWatcher()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
ops := fsnotify.Op(0)
|
||
|
for _, op := range op {
|
||
|
ops |= op
|
||
|
}
|
||
|
|
||
|
err = watcher.Add(path)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
files, err := os.ReadDir(path)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
ch := make(chan string, 1000)
|
||
|
|
||
|
// close channel on app shutdown
|
||
|
go func() {
|
||
|
<-ctx.Done()
|
||
|
watcher.Close()
|
||
|
}()
|
||
|
|
||
|
go func(watcher *fsnotify.Watcher, ch chan<- string) {
|
||
|
defer watcher.Close()
|
||
|
defer close(ch)
|
||
|
|
||
|
for _, file := range files {
|
||
|
path := filepath.Join(path, file.Name())
|
||
|
if file.IsDir() {
|
||
|
//fmt.Println("watching directory", path)
|
||
|
watcher.Add(path)
|
||
|
|
||
|
if dirFiles, err := os.ReadDir(path); err == nil {
|
||
|
for _, dirFile := range dirFiles {
|
||
|
ch <- filepath.Join(path, dirFile.Name())
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
ch <- path
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
select {
|
||
|
case event, ok := <-watcher.Events:
|
||
|
if !ok {
|
||
|
close(ch)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if fi, err := os.Stat(event.Name); err == nil && fi.IsDir() {
|
||
|
if event.Op&fsnotify.Create == fsnotify.Create {
|
||
|
//fmt.Println("watching directory", event.Name)
|
||
|
watcher.Add(event.Name)
|
||
|
}
|
||
|
|
||
|
// read dir immediately because directory files could change simultanously with its parent directory
|
||
|
if dirFiles, err := os.ReadDir(event.Name); err == nil {
|
||
|
for _, dirFile := range dirFiles {
|
||
|
ch <- filepath.Join(event.Name, dirFile.Name())
|
||
|
}
|
||
|
}
|
||
|
} else if err != nil && event.Op&fsnotify.Remove == fsnotify.Remove {
|
||
|
//fmt.Println("stopped watching directory", event.Name)
|
||
|
watcher.Remove(event.Name)
|
||
|
}
|
||
|
|
||
|
if event.Op&ops > 0 {
|
||
|
ch <- event.Name
|
||
|
}
|
||
|
case err, ok := <-watcher.Errors:
|
||
|
if ok {
|
||
|
fmt.Println(err, ok)
|
||
|
}
|
||
|
close(ch)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}(watcher, ch)
|
||
|
|
||
|
return ch, nil
|
||
|
}
|