pttodo/pttodo/schedule.go

91 lines
1.7 KiB
Go

package pttodo
import (
"encoding/json"
"math"
"regexp"
"strconv"
"time"
cron "github.com/robfig/cron/v3"
)
type Schedule string
func (schedule Schedule) MarshalJSON() ([]byte, error) {
return json.Marshal(string(schedule))
}
func (schedule *Schedule) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, (*string)(schedule))
}
func (schedule Schedule) Next(t time.Time) (time.Time, error) {
scheduler := schedulerFactory(string(schedule))
return scheduler.next(t)
}
type scheduler interface {
next(time.Time) (time.Time, error)
}
func schedulerFactory(s string) scheduler {
if s == "" {
return scheduleNever{}
} else if scheduleDurationPattern.MatchString(s) {
return scheduleDuration(s)
} else if scheduleDuePattern.MatchString(s) {
n, _ := strconv.Atoi(s)
return scheduleDue(n)
}
return scheduleCron(s)
}
// * * * * *
type scheduleCron string
func (c scheduleCron) next(t time.Time) (time.Time, error) {
schedule, err := cron.ParseStandard(string(c))
if err != nil {
return time.Time{}, err
}
return schedule.Next(t), nil
}
// * * * * *
type scheduleNever struct{}
var never = time.Date(
math.MaxInt32,
1,
1,
1,
1,
1,
1,
time.UTC,
)
func (cron scheduleNever) next(time.Time) (time.Time, error) {
return never, nil
}
// 4h5m
type scheduleDuration string
var scheduleDurationPattern = regexp.MustCompile(`^([0-9]+[a-z])+$`)
func (dur scheduleDuration) next(t time.Time) (time.Time, error) {
d, err := time.ParseDuration(string(dur))
return t.Add(d), err
}
// 123
type scheduleDue int64
var scheduleDuePattern = regexp.MustCompile(`^[0-9]+$`)
func (due scheduleDue) next(time.Time) (time.Time, error) {
return TS(due).time(), nil
}