package oncalendarfile import ( "context" "os" "time" "github.com/OliveTin/OliveTin/internal/auth" "github.com/OliveTin/OliveTin/internal/config" "github.com/OliveTin/OliveTin/internal/executor" "github.com/OliveTin/OliveTin/internal/filehelper" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" ) func Schedule(cfg *config.Config, ex *executor.Executor) { for _, action := range cfg.Actions { if action.ExecOnCalendarFile != "" { x := func(filename string) { parseCalendarFile(action, cfg, ex, filename) } go filehelper.WatchFileWrite(action.ExecOnCalendarFile, x) x(action.ExecOnCalendarFile) } } } 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 := os.ReadFile(action.ExecOnCalendarFile) if err != nil { log.Errorf("ReadIn: %v", err) return } data := make([]string, 1) err = yaml.Unmarshal(yfile, &data) if err != nil { log.Errorf("Unmarshal: %v", err) } scheduleCalendarActions(data, action, cfg, ex) } func scheduleCalendarActions(entries []string, action *config.Action, cfg *config.Config, ex *executor.Executor) { ctx := context.Background() for _, instant := range entries { if instant == "" { continue } until, _ := time.Parse(time.RFC3339, instant) go sleepUntil(ctx, until, action, cfg, ex) } } func sleepUntil(ctx context.Context, instant time.Time, action *config.Action, cfg *config.Config, ex *executor.Executor) { if time.Now().After(instant) { log.WithFields(log.Fields{ "instant": instant, "actionTitle": action.Title, }).Warnf("Not scheduling stale calendar action") return } log.WithFields(log.Fields{ "instant": instant, "actionTitle": action.Title, }).Infof("Scheduling action on calendar") timer := time.NewTimer(time.Until(instant)) defer timer.Stop() select { case <-timer.C: exec(instant, action, cfg, ex) return case <-ctx.Done(): log.Infof("Cancelled scheduled action") return } } func exec(instant time.Time, action *config.Action, cfg *config.Config, ex *executor.Executor) { log.WithFields(log.Fields{ "instant": instant, "actionTitle": action.Title, }).Infof("Executing action from calendar") req := &executor.ExecutionRequest{ Binding: ex.FindBindingWithNoEntity(action), Cfg: cfg, Tags: []string{}, AuthenticatedUser: auth.UserFromSystem(cfg, "calendar"), } ex.ExecRequest(req) }