diff --git a/time_test.go b/time_test.go index a6935f3..133b1b5 100644 --- a/time_test.go +++ b/time_test.go @@ -219,7 +219,7 @@ func TestPrepareCron2(t *testing.T) { func TestRun(t *testing.T) { now := time.Now().Add(time.Second * 2) - tmr := NewTimer(time.Now(), WithStaticDate(now), WithRunCountLimit(1)) + tmr, _ := NewTimer(time.Now(), WithStaticDate(now), WithRunCountLimit(1)) c := make(chan int) tmr.AddTask(func() { fmt.Println("hello world") @@ -241,7 +241,7 @@ func TestRun(t *testing.T) { func TestInvalid(t *testing.T) { exp := `[{"repeat":[{"unit":3,"value":19},{"unit":2,"value":8},{"unit":1,"value":15},{"unit":0,"value":0}],"every":false}]` - tmr := NewTimer(time.Now()) + tmr, _ := NewTimer(time.Now()) err := tmr.ImportRepeats(exp) if err != nil { t.Fatal(err) @@ -268,7 +268,7 @@ func TestDate(t *testing.T) { }, Every: false, } - tmr := NewTimer(time.Now(), WithRepeats(&rp)) + tmr, _ := NewTimer(time.Now(), WithRepeats(&rp)) tmr.AddTask(func() { time.Sleep(time.Second * 2) fmt.Println(tmr.NextTimer()) diff --git a/timer.go b/timer.go index e34e8f3..fd016b1 100644 --- a/timer.go +++ b/timer.go @@ -4,12 +4,13 @@ import ( "context" "encoding/json" "errors" + "fmt" "sort" "sync" "time" ) -func NewTimer(baseDate time.Time, opts ...TimerOptions) StarTimer { +func NewTimer(baseDate time.Time, opts ...TimerOptions) (StarTimer, error) { timer := StarTimer{ base: baseDate, nextDate: time.Time{}, @@ -57,6 +58,9 @@ func NewTimer(baseDate time.Time, opts ...TimerOptions) StarTimer { } if op.repeats != nil { + if err := timer.repeatsCheck(op.repeats); err != nil { + return timer, err + } timer.repeat = append(timer.repeat, op.repeats) } if op.tasks != nil { @@ -66,8 +70,43 @@ func NewTimer(baseDate time.Time, opts ...TimerOptions) StarTimer { timer.runLimit = op.runLimit } } - return timer + return timer, nil +} + +func (t *StarTimer) repeatsCheck(rp *Repeats) error { + if rp == nil { + return errors.New("nil point of Repeats") + } + if rp.Every { + return nil + } + for _, r := range rp.Repeat { + switch r.Unit { + case STAR_MINUTE, STAR_SECOND: + if r.Value > 60 || r.Value < 0 { + return fmt.Errorf("invalid value:%d", r.Value) + } + case STAR_HOUR: + if r.Value > 24 || r.Value < 0 { + return fmt.Errorf("invalid value:%d", r.Value) + } + case STAR_MONTH: + if r.Value > 12 || r.Value < 1 { + return fmt.Errorf("invalid value:%d", r.Value) + } + case STAR_DAY: + if r.Value > 31 || r.Value < 1 { + return fmt.Errorf("invalid value:%d", r.Value) + } + case STAR_WEEK: + if r.Value > 7 || r.Value < 0 { + return fmt.Errorf("invalid value:%d", r.Value) + } + } + } + return nil } + func (t *StarTimer) IsRunning() bool { t.mu.RLock() defer t.mu.RUnlock() @@ -105,7 +144,10 @@ func (t *StarTimer) Stop() error { } func (t *StarTimer) NextTimer() time.Time { - return t.parseNextDate(time.Now(), true) + if t.base.Before(time.Now()) { + return t.parseNextDate(time.Now(), true) + } + return t.parseNextDate(t.base, true) } func (t *StarTimer) NextTimerAfterDate(date time.Time) time.Time { @@ -128,7 +170,7 @@ func (t *StarTimer) ImportRepeats(r string) error { t.mu.Lock() defer t.mu.Unlock() if t.running { - return errors.New("coonot import repeats to already running timer") + return errors.New("cannot import repeats to already running timer") } var rep []Repeats err := json.Unmarshal([]byte(r), &rep) @@ -136,6 +178,11 @@ func (t *StarTimer) ImportRepeats(r string) error { return err } t.repeat = make([]*Repeats, 0, len(rep)) + for _, v := range rep { + if err = t.repeatsCheck(&v); err != nil { + return err + } + } for _, v := range rep { t.repeat = append(t.repeat, &v) } @@ -152,6 +199,11 @@ func (t *StarTimer) SetBaseDate(date time.Time) { func (t *StarTimer) ResetWithRepeat(base time.Time, repeat []*Repeats) error { t.Stop() t.base = base + for _, v := range repeat { + if err := t.repeatsCheck(v); err != nil { + return err + } + } t.repeat = repeat return t.Run() } @@ -166,7 +218,16 @@ func (t *StarTimer) Run() error { if t.running { return nil } - t.nextDate = t.parseNextDate(time.Now(), false) + for _, v := range t.repeat { + if err := t.repeatsCheck(v); err != nil { + return err + } + } + base := time.Now() + if t.base.After(base) { + base = t.base + } + t.nextDate = t.parseNextDate(base, false) if t.nextDate.Before(time.Now()) { return errors.New("Invalid Timer Options,Please Check") }