You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
startimer/cron.go

195 lines
3.7 KiB
Go

package startimer
import (
"errors"
"strconv"
"strings"
"sync"
"time"
)
var rpmonths = map[string]int{
"JAN": 1,
"FEB": 2,
"MAR": 3,
"APR": 4,
"MAY": 5,
"JUN": 6,
"JUL": 7,
"AUG": 8,
"SEP": 9,
"OCT": 10,
"NOV": 11,
"DEC": 12,
}
var rpweekdays = map[string]int{
"SUN": 0,
"MON": 1,
"TUE": 2,
"WED": 3,
"THU": 4,
"FRI": 5,
"SAT": 6,
}
func NewTimerWithCron(cron ...string) (StarTimer, error) {
tmr := StarTimer{
base: time.Now(),
nextDate: time.Time{},
mu: new(sync.RWMutex),
}
for _, c := range cron {
c = "0 " + c
rpt, err := parseCron(c)
if err != nil {
return tmr, err
}
tmr.repeat = append(tmr.repeat, rpt)
}
return tmr, nil
}
func NewTimerWithSecCron(cron ...string) (StarTimer, error) {
tmr := StarTimer{
base: time.Now(),
nextDate: time.Time{},
mu: new(sync.RWMutex),
}
for _, c := range cron {
rpt, err := parseCron(c)
if err != nil {
return tmr, err
}
tmr.repeat = append(tmr.repeat, rpt)
}
return tmr, nil
}
func parseCron(cron string) (*Repeats, error) {
{
cron = strings.ToUpper(cron)
for k, v := range rpmonths {
cron = strings.ReplaceAll(cron, k, strconv.Itoa(v))
}
for k, v := range rpweekdays {
cron = strings.ReplaceAll(cron, k, strconv.Itoa(v))
}
}
for {
oldLen := len(cron)
cron = strings.ReplaceAll(strings.TrimSpace(cron), " ", " ")
if len(cron) == oldLen {
break
}
}
ct := strings.Split(cron, " ")
if len(ct) != 6 {
return nil, errors.New("Invalid cron,argument not enough")
}
foundFirstAll := false
var myMap = make(map[Unit]map[uint32]Repeat)
for idx, c := range ct {
if _, ok := myMap[Unit(idx)]; !ok {
myMap[Unit(idx)] = make(map[uint32]Repeat)
}
var minVal, maxVal int
switch Unit(idx) {
case STAR_MINUTE, STAR_SECOND:
minVal = 0
maxVal = 60
case STAR_HOUR:
minVal = 0
maxVal = 24
case STAR_DAY:
minVal = 1
maxVal = 32
case STAR_MONTH:
minVal = 1
maxVal = 13
case STAR_WEEK:
minVal = 0
maxVal = 7
}
cdt := strings.Split(c, ",")
for _, dtl := range cdt {
dtl = strings.TrimSpace(dtl)
if dtl == "*" {
if !foundFirstAll {
foundFirstAll = true
if maxVal > 0 {
for i := minVal; i < maxVal; i++ {
val := uint32(i)
myMap[Unit(idx)][val] = Repeat{
Unit: Unit(idx),
Value: val,
}
}
}
}
continue
}
if strings.Contains(dtl, "*/") {
num, err := strconv.Atoi(strings.TrimPrefix(dtl, "*/"))
if err != nil {
return nil, err
}
for i := minVal; i < maxVal; i++ {
val := i
if Unit(idx) == STAR_DAY || Unit(idx) == STAR_MONTH {
val--
}
if val%num == 0 {
myMap[Unit(idx)][uint32(val)] = Repeat{
Unit: Unit(idx),
Value: uint32(i),
}
}
}
continue
}
if strings.Contains(dtl, "-") {
numbers := strings.Split(dtl, "-")
if len(numbers) != 2 {
return nil, errors.New("Invalid Cron")
}
startNum, err := strconv.Atoi(numbers[0])
if err != nil {
return nil, err
}
endNum, err := strconv.Atoi(numbers[1])
if err != nil {
return nil, err
}
if startNum < minVal && endNum >= maxVal {
return nil, errors.New("Invalid Cron")
}
for i := startNum; i <= endNum; i++ {
myMap[Unit(idx)][uint32(i)] = Repeat{
Unit: Unit(idx),
Value: uint32(i),
}
}
continue
}
number, err := strconv.Atoi(dtl)
if err != nil {
return nil, err
}
myMap[Unit(idx)][uint32(number)] = Repeat{
Unit: Unit(idx),
Value: uint32(number),
}
}
}
var repeat Repeats
for _, v := range myMap {
for _, rpt := range v {
repeat.Repeat = append(repeat.Repeat, rpt)
}
}
return &repeat, nil
}