listen/listen.go

157 lines
2.7 KiB
Go

package main
import (
"crypto/sha256"
"fmt"
"io"
"log"
"maps"
"os"
"os/exec"
"os/signal"
"slices"
"time"
"github.com/fsnotify/fsnotify"
)
type Listen struct {
FileMap map[string]bool
CksumMap map[string][]byte
Condition string
Cksum bool
Interval string
Command []string
}
func loopFsnotify(l Listen, quit chan bool) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
for key := range l.FileMap {
watcher.Add(key)
fmt.Println(watcher.WatchList())
}
for {
var renameAdd []string = []string{}
hasher := sha256.New()
trigger := false
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
for key := range l.FileMap {
if event.Name == key {
if l.Cksum {
f, err := os.Open(key)
if err != nil {
log.Fatal(err)
}
defer f.Close()
if _, err := io.Copy(hasher, f); err != nil {
log.Fatal(err)
}
if !slices.Equal(l.CksumMap[key], hasher.Sum(nil)) {
if l.Condition == "any" {
trigger = true
break
}
l.FileMap[key] = true
}
} else {
if event.Has(fsnotify.Write) {
if l.Condition == "any" {
trigger = true
break
}
l.FileMap[key] = true
} else if event.Has(fsnotify.Rename) {
// we need to rewatch file
// sleeping small amount to allow CREATE event to propogate
time.Sleep(10 * time.Millisecond)
// ... then adding to a list to allow additional time
renameAdd = append(renameAdd, key)
if l.Condition == "any" {
trigger = true
break
}
l.FileMap[key] = true
}
}
}
} // end for
if l.Condition == "all" {
trigger = true
for value := range maps.Values(l.FileMap) {
if !value {
trigger = false
break
}
}
} // end if condition
// end case event
case _, ok := <-watcher.Errors:
if !ok {
return
}
} // end switch
// end case errors
if trigger {
if len(l.Command) >= 1 {
cmd := exec.Command(l.Command[0], l.Command[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
} else {
quit <- true
}
} // end if trigger
for _, value := range renameAdd {
err := watcher.Add(value)
if err != nil {
fmt.Println(err)
}
}
} // end for
}
func loopInterval(l Listen, quit chan bool) {
for {
fmt.Printf("running")
time.Sleep(1 * time.Second)
}
}
func (l Listen) Run() {
// catch ^C
quit := make(chan bool)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
// main loop
if l.Interval == "" {
go loopFsnotify(l, quit)
} else {
go loopInterval(l, quit)
}
select {
case <-c:
case <-quit:
}
}