diff --git a/internal/entityfiles/entityfiles.go b/internal/entityfiles/entityfiles.go index fd56c13..ebb5e39 100644 --- a/internal/entityfiles/entityfiles.go +++ b/internal/entityfiles/entityfiles.go @@ -5,10 +5,9 @@ import ( "encoding/json" "fmt" config "github.com/OliveTin/OliveTin/internal/config" + "github.com/OliveTin/OliveTin/internal/filehelper" sv "github.com/OliveTin/OliveTin/internal/stringvariables" - "github.com/fsnotify/fsnotify" log "github.com/sirupsen/logrus" - "github.com/spf13/viper" "gopkg.in/yaml.v3" "io/ioutil" "os" @@ -17,7 +16,7 @@ import ( ) func SetupEntityFileWatchers(cfg *config.Config) { - configDir := filepath.Dir(viper.ConfigFileUsed()) + configDir := cfg.GetDir() configDirVar := filepath.Join(configDir, "var") // for development purposes @@ -36,71 +35,9 @@ func SetupEntityFileWatchers(cfg *config.Config) { }).Debugf("Adding config dir to entity file path") } - go watch(p, ef.Name) - - loadEntityFile(p, ef.Name) - } -} - -func watch(file string, entityname string) { - log.WithFields(log.Fields{ - "file": file, - "name": entityname, - }).Infof("Watching entity file") - - watcher, err := fsnotify.NewWatcher() - - if err != nil { - log.Errorf("Could not watch entity file: %v", err) - return - } - - defer watcher.Close() - - done := make(chan bool) - - go func() { - for { - processEvent(watcher, file, entityname) - } - }() - - err = watcher.Add(file) - - if err != nil { - log.WithFields(log.Fields{ - "file": file, - }).Errorf("Could not create entity watcher: %v", err) - } - - <-done -} - -func processEvent(watcher *fsnotify.Watcher, filename string, entityname string) { - select { - case event, ok := <-watcher.Events: - if !ok { - return - } - - loadEntityFileIfWritten(&event, filename, entityname) - - return - case err := <-watcher.Errors: - log.Errorf("Error in fsnotify: %v", err) - return - } -} - -func loadEntityFileIfWritten(event *fsnotify.Event, filename string, entityname string) { - if event.Has(fsnotify.Remove) { - log.WithFields(log.Fields{ - "file": filename, - }).Warnf("Entity file deleted! Will no longer be able to watch for changes!") - } - - if event.Has(fsnotify.Write) { - loadEntityFile(filename, entityname) + filehelper.WatchFileWrite(p, func(filename string) { + loadEntityFile(p, ef.Name) + }) } } diff --git a/internal/executor/executor.go b/internal/executor/executor.go index d2653aa..c86b4d4 100644 --- a/internal/executor/executor.go +++ b/internal/executor/executor.go @@ -305,6 +305,7 @@ func stepRequestAction(req *ExecutionRequest) bool { log.WithFields(log.Fields{ "actionTitle": req.logEntry.ActionTitle, + "tags": req.Tags, }).Infof("Action requested") return true diff --git a/internal/filehelper/file_change_notify.go b/internal/filehelper/file_change_notify.go index 06e940f..317084e 100644 --- a/internal/filehelper/file_change_notify.go +++ b/internal/filehelper/file_change_notify.go @@ -6,7 +6,44 @@ import ( "path/filepath" ) -func WatchFile(fullpath string, callback func()) { +type watchContext struct { + filename string + filedir string + callback func(filename string) + interestedEvent fsnotify.Op +} + +func WatchDirectoryCreate(fullpath string, callback func(filename string)) { + watchPath(&watchContext{ + filedir: fullpath, + filename: "", + callback: callback, + interestedEvent: fsnotify.Create, + }) +} + +func WatchDirectoryWrite(fullpath string, callback func(filename string)) { + watchPath(&watchContext{ + filedir: fullpath, + filename: "", + callback: callback, + interestedEvent: fsnotify.Write, + }) +} + +func WatchFileWrite(fullpath string, callback func(filename string)) { + filename := filepath.Base(fullpath) + filedir := filepath.Dir(fullpath) + + watchPath(&watchContext{ + filedir: filedir, + filename: filename, + callback: callback, + interestedEvent: fsnotify.Write, + }) +} + +func watchPath(ctx *watchContext) { watcher, err := fsnotify.NewWatcher() if err != nil { @@ -18,16 +55,13 @@ func WatchFile(fullpath string, callback func()) { done := make(chan bool) - filename := filepath.Base(fullpath) - filedir := filepath.Dir(fullpath) - go func() { for { - processEvent(filename, watcher, fsnotify.Write, callback) + processEvent(ctx, watcher) } }() - err = watcher.Add(filedir) + err = watcher.Add(ctx.filedir) if err != nil { log.Errorf("Could not create watcher: %v", err) @@ -36,10 +70,10 @@ func WatchFile(fullpath string, callback func()) { <-done } -func processEvent(filename string, watcher *fsnotify.Watcher, eventType fsnotify.Op, callback func()) { +func processEvent(ctx *watchContext, watcher *fsnotify.Watcher) { select { case event, ok := <-watcher.Events: - if !consumeEvent(ok, filename, &event, callback) { + if !consumeEvent(ok, ctx, &event) { return } @@ -50,25 +84,25 @@ func processEvent(filename string, watcher *fsnotify.Watcher, eventType fsnotify } } -func consumeEvent(ok bool, filename string, event *fsnotify.Event, callback func()) bool { +func consumeEvent(ok bool, ctx *watchContext, event *fsnotify.Event) bool { if !ok { return false } - if filepath.Base(event.Name) != filename { + if ctx.filename != "" && filepath.Base(event.Name) != ctx.filename { log.Tracef("fsnotify irreleventa event different file %+v", event) return true } - consumeWriteEvents(event, callback) + consumeRelevantEvents(ctx, event) return true } -func consumeWriteEvents(event *fsnotify.Event, callback func()) { - if event.Has(fsnotify.Write) { +func consumeRelevantEvents(ctx *watchContext, event *fsnotify.Event) { + if event.Has(ctx.interestedEvent) { log.Debugf("fsnotify write event: %v", event) - callback() + ctx.callback(event.Name) } else { log.Debugf("fsnotify irrelevant event on file %v", event) } diff --git a/internal/oncalendarfile/calendar.go b/internal/oncalendarfile/calendar.go index e522a30..37ce466 100644 --- a/internal/oncalendarfile/calendar.go +++ b/internal/oncalendarfile/calendar.go @@ -19,22 +19,23 @@ func Schedule(cfg *config.Config, ex *executor.Executor) { for _, action := range cfg.Actions { if action.ExecOnCalendarFile != "" { - x := func() { - parseCalendarFile(action, cfg, ex) + x := func(filename string) { + parseCalendarFile(action, cfg, ex, filename) } - go filehelper.WatchFile(action.ExecOnCalendarFile, x) + go filehelper.WatchFileWrite(action.ExecOnCalendarFile, x) - x() + x(action.ExecOnCalendarFile) } } } -func parseCalendarFile(action *config.Action, cfg *config.Config, ex *executor.Executor) { +func parseCalendarFile(action *config.Action, cfg *config.Config, ex *executor.Executor, filename string) { filehelper.Touch(action.ExecOnCalendarFile, "calendar file") log.WithFields(log.Fields{ "actionTitle": action.Title, + "filename": filename, }).Infof("Parsing calendar file") yfile, err := ioutil.ReadFile(action.ExecOnCalendarFile) diff --git a/internal/onfileindir/fileindir.go b/internal/onfileindir/fileindir.go index 482994c..ccbefac 100644 --- a/internal/onfileindir/fileindir.go +++ b/internal/onfileindir/fileindir.go @@ -4,83 +4,37 @@ import ( "github.com/OliveTin/OliveTin/internal/acl" "github.com/OliveTin/OliveTin/internal/config" "github.com/OliveTin/OliveTin/internal/executor" - "github.com/fsnotify/fsnotify" - log "github.com/sirupsen/logrus" + "github.com/OliveTin/OliveTin/internal/filehelper" ) func WatchFilesInDirectory(cfg *config.Config, ex *executor.Executor) { for _, action := range cfg.Actions { for _, dirname := range action.ExecOnFileChangedInDir { - watch(dirname, action, cfg, ex, fsnotify.Write) + filehelper.WatchDirectoryWrite(dirname, func(filename string) { + scheduleExec(action, cfg, ex, filename) + }) } for _, dirname := range action.ExecOnFileCreatedInDir { - watch(dirname, action, cfg, ex, fsnotify.Create) + filehelper.WatchDirectoryCreate(dirname, func(filename string) { + scheduleExec(action, cfg, ex, filename) + }) } } } -func watch(directory string, action *config.Action, cfg *config.Config, ex *executor.Executor, eventType fsnotify.Op) { - log.WithFields(log.Fields{ - "dir": directory, - "eventType": eventType, - }).Infof("Watching dir") - - watcher, err := fsnotify.NewWatcher() - - if err != nil { - log.Errorf("Could not watch for files being created: %v", err) - return +func scheduleExec(action *config.Action, cfg *config.Config, ex *executor.Executor, filename string) { + req := &executor.ExecutionRequest{ + ActionTitle: action.Title, + Cfg: cfg, + Tags: []string{"fileindir"}, + Arguments: map[string]string{ + "filename": filename, + }, + AuthenticatedUser: &acl.AuthenticatedUser{ + Username: "fileindir", + }, } - defer watcher.Close() - - done := make(chan bool) - - go func() { - for { - processEvent(watcher, action, cfg, ex, eventType) - } - }() - - err = watcher.Add("/tmp") - - if err != nil { - log.Errorf("Could not create watcher: %v", err) - } - - <-done -} - -func processEvent(watcher *fsnotify.Watcher, action *config.Action, cfg *config.Config, ex *executor.Executor, eventType fsnotify.Op) { - select { - case event, ok := <-watcher.Events: - if !ok { - return - } - - checkEvent(&event, action, cfg, ex, eventType) - break - case err := <-watcher.Errors: - log.Errorf("Error in fsnotify: %v", err) - return - } -} - -func checkEvent(event *fsnotify.Event, action *config.Action, cfg *config.Config, ex *executor.Executor, eventType fsnotify.Op) { - if event.Has(eventType) { - req := &executor.ExecutionRequest{ - ActionTitle: action.Title, - Cfg: cfg, - Tags: []string{"fileindir"}, - Arguments: map[string]string{ - "filename": event.Name, - }, - AuthenticatedUser: &acl.AuthenticatedUser{ - Username: "fileindir", - }, - } - - ex.ExecRequest(req) - } + ex.ExecRequest(req) }