package curl2info import ( "errors" "fmt" "log" "regexp" "strconv" "strings" "time" "github.com/davecgh/go-spew/spew" ) type timePointer struct { left, right int leftlimit, rightlimit int per int isAll bool } func (tp *timePointer) String() string { return fmt.Sprintf("left: %d, right: %d, leftlimit: %d, rightlimit: %d, per: %d", tp.left, tp.right, tp.leftlimit, tp.rightlimit, tp.per) } // Crontab 的string解析 type Crontab struct { Min []timePointer Hour []timePointer Day []timePointer Month []timePointer Week []timePointer WillPlans []time.Time SkipPlans []time.Time YearPlan *TrieYear } // NewCrontab create 一个crontab func NewCrontab(crontab string) *Crontab { cron := &Crontab{} cron.FromString(crontab) return cron } func (cron *Crontab) String() string { return fmt.Sprintf("min:%s\nhour:%s\nday:%s\nmonth:%s\nweek:%s\n", spew.Sdump(cron.Min), spew.Sdump(cron.Hour), spew.Sdump(cron.Day), spew.Sdump(cron.Month), spew.Sdump(cron.Week)) } // FromString 解析crontab 的 表达式 func (cron *Crontab) FromString(crontab string) error { crontab = strings.TrimSpace(crontab) matches := regexp.MustCompile("[^ ]+").FindAllString(crontab, -1) mlen := len(matches) switch mlen { case 5: cron.Min = createTimePointer(matches[0], 0, 59, true) cron.Hour = createTimePointer(matches[1], 0, 23, true) cron.Day = createTimePointer(matches[2], 1, 31, false) cron.Month = createTimePointer(matches[3], 1, 12, true) cron.Week = createTimePointer(matches[4], 0, 6, true) cron.CreateYearPlan() default: return errors.New("mathches len != want, check crontab string") } return nil } // CreateYearPlan 创建年度计划 func (cron *Crontab) CreateYearPlan() { cron.YearPlan = newTrieYear(time.Now().Year()) cron.YearPlan.FromCrontab(cron) } // TimeUp 是否时间快到 func (cron *Crontab) TimeUp(now time.Time) bool { maxlen := 1000 createlen := 500 plen := len(cron.WillPlans) if plen <= createlen { var lastplan time.Time if plen == 0 { lastplan = now } else { lastplan = cron.WillPlans[plen-1].Add(time.Minute) } if !cron.YearPlan.CheckYear() { cron.CreateYearPlan() } timeplans := cron.YearPlan.GetPlanTime(cron, lastplan, uint(maxlen-plen)) cron.WillPlans = append(cron.WillPlans, timeplans...) } if len(cron.WillPlans) > 0 { istimeup := false for i := 0; i < maxlen; i++ { if now.Unix() >= cron.WillPlans[i].Unix() { istimeup = true } else { if istimeup { if i > 0 { cron.SkipPlans = append(cron.SkipPlans, cron.WillPlans[0:i]...) if len(cron.SkipPlans) >= maxlen+200 { cron.SkipPlans = cron.SkipPlans[200:] } } cron.WillPlans = cron.WillPlans[i+1:] return istimeup } return istimeup } } cron.SkipPlans = cron.WillPlans cron.WillPlans = nil return istimeup } log.Panicln("error willplans range") return false } func createTimePointer(min string, llimit, rlimit int, fixedLeftRight bool) []timePointer { var result []timePointer exelist := strings.Split(min, ",") for _, exe := range exelist { tp := timePointer{} takeper := strings.Split(exe, "/") // per var rangevalue, per string if len(takeper) == 1 { rangevalue = exe per = "1" } else { rangevalue = takeper[0] per = takeper[1] } // takeRange be := strings.Split(rangevalue, "-") var left, rigth string switch len(be) { case 1: left = be[0] rigth = be[0] case 2: left = be[0] rigth = be[1] default: panic(errors.New("range value is > 2")) } if left == "*" { tp.left = llimit } else { ileft, err := strconv.Atoi(strings.Replace(left, "^", "-", -1)) if err != nil { panic(err) } tp.left = ileft } if rigth == "*" { tp.right = rlimit } else { iright, err := strconv.Atoi(strings.Replace(rigth, "^", "-", -1)) if err != nil { panic(err) } tp.right = iright } iper, err := strconv.Atoi(per) if err != nil { panic(err) } tp.per = iper tp.leftlimit = llimit tp.rightlimit = rlimit // 修正左值 leftfixed := tp.left if leftfixed < 0 { leftfixed += tp.rightlimit + 1 if fixedLeftRight { tp.left = leftfixed } } rightfixed := tp.right if rightfixed < 0 { rightfixed += tp.rightlimit + 1 if fixedLeftRight { tp.right = rightfixed } } // 全部符合 当左等于左 且 右等于右最大 并且 per == 1 TODO: 如果加入时间间隔 就需要 加多一个 附加值 if leftfixed == tp.leftlimit && rightfixed == tp.rightlimit && tp.per == 1 { tp.isAll = true } result = append(result, tp) } return result }