From 0f8637c9ff978bced146394a3654771338c26853 Mon Sep 17 00:00:00 2001 From: bel Date: Sat, 17 Jul 2021 23:14:54 -0600 Subject: [PATCH] async triggers for either interval or next due, accept cron --- server/ajax/ajax.go | 37 +++++++++++++++++++++++++++++-------- server/ajax/form/cron.go | 17 +++++++++++++++++ server/ajax/task/task.go | 6 +++++- 3 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 server/ajax/form/cron.go diff --git a/server/ajax/ajax.go b/server/ajax/ajax.go index fb0cd0f..5085a23 100755 --- a/server/ajax/ajax.go +++ b/server/ajax/ajax.go @@ -87,37 +87,58 @@ func has(params url.Values, k string) bool { } func (a *Ajax) Async() { + var err error + nextDue := time.Now().Add(config.Loop) c := time.NewTicker(config.Loop) - for range c.C { + for { + select { + case <-c.C: + case <-time.After(time.Until(nextDue)): + } log.Println("loop tasks") - if err := a.loopTasks(); err != nil { + nextDue, err = a.loopTasks() + if err != nil { log.Println("failed to loop tasks", err) } } } -func (a *Ajax) loopTasks() error { +func (a *Ajax) loopTasks() (time.Time, error) { + nextDue := time.Now().Add(time.Hour * 240) lists, err := a.storageListLists() if err != nil { - return err + return nextDue, err } for _, list := range lists { tasks, err := a.storageListTasks(list.UUID, func(t *task.Task) bool { return t.Complete }) if err != nil { - return err + return nextDue, err } for _, task := range tasks { - if !task.Complete || task.Loop == 0 || time.Since(task.Completed) < task.Loop { + if !task.Complete { + continue + } + if task.Loop == 0 && task.Cron == "" { + continue + } + nextLoopTrigger := task.Completed.Add(task.Loop) + if task.Loop == 0 { + nextLoopTrigger = task.Cron.Next() + } + if time.Now().Before(nextLoopTrigger) { + if nextLoopTrigger.Before(nextDue) { + nextDue = nextLoopTrigger + } continue } task.Complete = false task.Completed = time.Time{} if err := a.storageSetTask(list.UUID, task); err != nil { - return err + return nextDue, err } } } - return nil + return nextDue, nil } diff --git a/server/ajax/form/cron.go b/server/ajax/form/cron.go new file mode 100644 index 0000000..cefa9b3 --- /dev/null +++ b/server/ajax/form/cron.go @@ -0,0 +1,17 @@ +package form + +import ( + "time" + + "github.com/robfig/cron/v3" +) + +type Cron string + +func (c Cron) Next() time.Time { + schedule, err := cron.ParseStandard(string(c)) + if err != nil { + return time.Time{} + } + return schedule.Next(time.Now()) +} diff --git a/server/ajax/task/task.go b/server/ajax/task/task.go index eb25a21..e081260 100755 --- a/server/ajax/task/task.go +++ b/server/ajax/task/task.go @@ -24,6 +24,7 @@ type Task struct { Note []string Due time.Time Loop time.Duration + Cron form.Cron Index int } @@ -45,6 +46,7 @@ func New(r *http.Request) (*Task, error) { Edited: time.Now(), Due: form.ToTime(form.Get(r, "duedate")), Loop: form.ToDuration(form.Get(r, "loop")), + Cron: form.Cron(form.Get(r, "cron")), } task.SetNote(form.Get(r, "note")) return task, task.validate() @@ -75,7 +77,8 @@ func (t *Task) MarshalJSON() ([]byte, error) { // "dueStr":"", // "dueInt":33330000, // "dueTitle":"Due ", - // "loop": "1m"} + // "loop": "1m", + // "cron": "* * * * *"} // ]} fullFormat := "02 Jan 2006 03:04 PM" shortFormat := "02 Jan" @@ -112,6 +115,7 @@ func (t *Task) MarshalJSON() ([]byte, error) { "dueInt": t.Due.Unix(), "dueTitle": "Due ", "loop": t.Loop.String(), + "cron": t.Cron, } if t.Due.IsZero() { for k := range m {