Compare commits

...

3 Commits

Author SHA1 Message Date
兔子 3aa431985b update static mode 4 months ago
兔子 3ec2007a7d add more func 12 months ago
兔子 557abef590 bug fix 12 months ago

@ -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")
@ -238,3 +238,46 @@ func TestRun(t *testing.T) {
t.FailNow()
}
}
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())
err := tmr.ImportRepeats(exp)
if err != nil {
t.Fatal(err)
}
fmt.Println(tmr.NextTimer())
}
func TestDate(t *testing.T) {
n := time.Now().Add(time.Minute)
var rp = Repeats{
Repeat: []Repeat{
{
Unit: STAR_HOUR,
Value: uint32(n.Hour()),
},
{
Unit: STAR_MINUTE,
Value: uint32(n.Minute()),
},
{
Unit: STAR_SECOND,
Value: 0,
},
},
Every: false,
}
tmr, _ := NewTimer(time.Now(), WithRepeats(&rp))
tmr.AddTask(func() {
time.Sleep(time.Second * 2)
fmt.Println(tmr.NextTimer())
})
err := tmr.Run()
if err != nil {
t.Fatal(err)
}
fmt.Println(tmr.NextTimer())
fmt.Println(tmr.NextTimerAfterDate(time.Now().Add(time.Hour)))
time.Sleep(time.Hour)
}

@ -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,6 +144,9 @@ func (t *StarTimer) Stop() error {
}
func (t *StarTimer) NextTimer() time.Time {
if t.base.Before(time.Now()) {
return t.parseNextDate(time.Now(), true)
}
return t.parseNextDate(t.base, true)
}
@ -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)
}
@ -149,9 +196,21 @@ func (t *StarTimer) SetBaseDate(date time.Time) {
t.base = date
}
func (t *StarTimer) StaticMode() bool {
return t.staticMode
}
func (t *StarTimer) SetStaticMode(s bool) {
t.staticMode = s
}
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()
}
@ -160,13 +219,74 @@ func (t *StarTimer) Repeats() []*Repeats {
return t.repeat
}
func (t *StarTimer) runAsStaticMode() error {
t.mu.Lock()
defer t.mu.Unlock()
if t.running {
return nil
}
for _, v := range t.repeat {
if err := t.repeatsCheck(v); err != nil {
return err
}
}
t.base = time.Now()
base := t.base
t.nextDate = t.parseNextDate(base, false)
if t.nextDate.Before(time.Now()) {
return errors.New("Invalid Timer Options,Please Check")
}
t.running = true
t.stopCtx, t.stopFn = context.WithCancel(context.Background())
go func() {
for {
if t.runLimit > 0 && t.runCount >= t.runLimit {
t.Stop()
}
now := time.Now()
t.nextDate = t.parseNextDate(now, false)
if t.nextDate.Before(now) || t.runLimit > 0 && t.runCount+1 >= t.runLimit {
t.Stop()
}
t.mu.Lock()
t.timer = time.NewTimer(t.nextDate.Sub(now))
t.mu.Unlock()
select {
case <-t.timer.C:
t.runCount++
for _, fn := range t.tasks {
go fn()
}
if !t.running {
return
}
case <-t.stopCtx.Done():
return
}
}
}()
return nil
}
func (t *StarTimer) Run() error {
if t.staticMode {
return t.runAsStaticMode()
}
t.mu.Lock()
defer t.mu.Unlock()
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")
}

@ -41,6 +41,8 @@ type StarTimer struct {
runLimit int
repeat []*Repeats
tasks []func()
//staticMode 意味永久以当前时间为基准进行动作例如crontab
staticMode bool
}
type TimerOptions func(option *TimerOption)

Loading…
Cancel
Save