diff --git a/base.go b/base.go new file mode 100644 index 0000000..fdcc283 --- /dev/null +++ b/base.go @@ -0,0 +1,86 @@ +package crontab + +import ( + "strconv" + "strings" + + "474420502.top/eson/structure/priority_list" + randomdata "github.com/Pallinder/go-randomdata" +) + +type randLR struct { + left, right int +} + +// NodeCount 用于priority_list +type NodeCount struct { + plist.Node + randLR +} + +// Compare NodeCount比较函数 +func (rlr *NodeCount) Compare(v plist.INode) bool { + return rlr.GetValue().(int) > v.GetValue().(int) +} + +func parseRandLR(lrvalue string) randLR { + vlen := len(lrvalue) + lastchar := lrvalue[vlen-1] + + lr := strings.Split(lrvalue, "-") + switch len(lr) { + case 1: + lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[0], lastchar)} + return lr + case 2: + + lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[1], lastchar)} + return lr + default: + panic("lr is error") + } +} + +// intervalPriorityListISecond 获取优先链表比较的值 +func intervalPriorityListISecond(planlist *plist.PriorityList, count int) int { + + if planlist.Size() > 0 { + node := new(NodeCount) + node.SetValue(count) + + iwantNode := planlist.GetCompare(node) + if iwantNode != nil { + wantNode := iwantNode.(*NodeCount) + lr := wantNode.randLR + return randomdata.Number(lr.left, lr.right+1) + } + } + + return -1 +} + +func getInt(v string) int { + vint, err := strconv.Atoi(v) + if err != nil { + panic(err) + } + return vint +} + +func parseTimeValue(v string, lastchar byte) int { + + vlen := len(v) + + switch lastchar { + case 's': + return getInt(v[:vlen-1]) + case 'm': + return getInt(v[:vlen-1]) * 60 + case 'h': + return getInt(v[:vlen-1]) * 3600 + case 'd': + return getInt(v[:vlen-1]) * 3600 * 24 + default: + return getInt(v) + } +} diff --git a/crontab.go b/crontab.go index 4c22415..c8c04c0 100644 --- a/crontab.go +++ b/crontab.go @@ -10,23 +10,15 @@ import ( "time" "474420502.top/eson/structure/circular_linked" + "474420502.top/eson/structure/priority_list" "github.com/Pallinder/go-randomdata" "github.com/davecgh/go-spew/spew" ) -type randLR struct { - left, right int -} - -type randLRC struct { - randLR - count int -} - type hInterval struct { - PlanFailCount []randLRC - PlanTrueCount []randLRC + PlanFailCount plist.PriorityList + PlanTrueCount plist.PriorityList PlanFail []randLR PlanTrue []randLR @@ -107,7 +99,7 @@ func (cron *Crontab) GetStatus() (status bool) { return cron.lastStatus } -// TimeUp 是否时间快到 +// TimeUp 是否时间快到, 时间间隔调用完TimeUp后必须调用NextTime, 为了精准控制时间 func (cron *Crontab) TimeUp() bool { if cron.interval != nil { @@ -243,19 +235,34 @@ func (cron *Crontab) intervalCalculateNextTime(now time.Time) { if cron.lastStatus == false { - if len(iv.PlanFailCount) > 0 { - - } else if len(iv.PlanFail) > 0 { - idx := randomdata.Number(len(iv.PlanFail)) - lr := iv.PlanFail[idx] - isecond = randomdata.Number(lr.left, lr.right+1) + isecond = intervalPriorityListISecond(&iv.PlanFailCount, iv.FailCount) + if isecond == -1 { + if len(iv.PlanFail) > 0 { + idx := randomdata.Number(len(iv.PlanFail)) + lr := iv.PlanFail[idx] + isecond = randomdata.Number(lr.left, lr.right+1) + } else { + isecond = 0 + } } log.Println("fail:", iv.FailCount, "count time wait:", isecond, "s") } else { - idx := randomdata.Number(len(iv.PlanTrue)) - lr := iv.PlanTrue[idx] - isecond = randomdata.Number(lr.left, lr.right+1) + + isecond = intervalPriorityListISecond(&iv.PlanTrueCount, iv.TrueCount) + if isecond == -1 { + if len(iv.PlanTrue) > 0 { + idx := randomdata.Number(len(iv.PlanTrue)) + lr := iv.PlanTrue[idx] + isecond = randomdata.Number(lr.left, lr.right+1) + + } else { + isecond = 0 + } + + } else { + log.Println("success:", iv.TrueCount, "count time wait:", isecond, "s") + } } iv.Count-- @@ -263,16 +270,19 @@ func (cron *Crontab) intervalCalculateNextTime(now time.Time) { iv.reset() cron.interval.MoveNext() } + + cron.isCalculated = true cron.nextTime = now.Add(time.Duration(isecond) * time.Second) } func (cron *Crontab) intervalTimeUp() bool { - now := time.Now() - - if now.Unix() >= cron.nextTime.Unix() { - cron.isCalculated = false - return true + if cron.isCalculated != false { + now := time.Now() + if now.Unix() >= cron.nextTime.Unix() { + cron.isCalculated = false + return true + } } return false @@ -355,7 +365,7 @@ func createTimePointer(min string, llimit, rlimit int, fixedLeftRight bool) []ti } } - // 全部符合 当左等于左 且 右等于右最大 并且 per == 1 TODO: 如果加入时间间隔 就需要 加多一个 附加值 + // 全部符合 当左等于左 且 右等于右最大 并且 per == 1 if leftfixed == tp.leftlimit && rightfixed == tp.rightlimit && tp.per == 1 { tp.isAll = true } @@ -402,19 +412,31 @@ func parseIntervalString(crontab string) []interface{} { case 'f', 'F': scharIndex := strings.Index(FN, "?") if scharIndex != -1 { + fc := FN[0:scharIndex] flr := FN[scharIndex+1:] - interval.PlanFailCount = append(interval.PlanFailCount, parseRandLRC(fc, flr)) + + node := new(NodeCount) + node.SetValue(getInt(fc[1:])) + node.randLR = parseRandLR(flr) + interval.PlanFailCount.Insert(node) + } else { fvalue := FN[1:] interval.PlanFail = append(interval.PlanFail, parseRandLR(fvalue)) } + case 't', 'T': scharIndex := strings.Index(FN, "?") if scharIndex != -1 { tc := FN[0:scharIndex] tlr := FN[scharIndex+1:] - interval.PlanTrueCount = append(interval.PlanTrueCount, parseRandLRC(tc, tlr)) + + node := new(NodeCount) + node.SetValue(getInt(tc[1:])) + node.randLR = parseRandLR(tlr) + interval.PlanTrueCount.Insert(node) + } else { tvalue := FN[1:] interval.PlanTrue = append(interval.PlanTrue, parseRandLR(tvalue)) @@ -426,7 +448,12 @@ func parseIntervalString(crontab string) []interface{} { if scharIndex != -1 { tc := FN[0:scharIndex] tlr := FN[scharIndex+1:] - interval.PlanTrueCount = append(interval.PlanTrueCount, parseRandLRC(tc, tlr)) + + node := new(NodeCount) + node.SetValue(getInt(tc[1:])) + node.randLR = parseRandLR(tlr) + interval.PlanTrueCount.Insert(node) + } else { tvalue := FN[1:] interval.PlanTrue = append(interval.PlanTrue, parseRandLR(tvalue)) @@ -440,51 +467,3 @@ func parseIntervalString(crontab string) []interface{} { return result } - -func parseRandLRC(fc, flr string) randLRC { - return randLRC{count: getInt(fc[1:]), randLR: parseRandLR(flr)} -} - -func parseRandLR(lrvalue string) randLR { - vlen := len(lrvalue) - lastchar := lrvalue[vlen-1] - - lr := strings.Split(lrvalue, "-") - switch len(lr) { - case 1: - lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[0], lastchar)} - return lr - case 2: - - lr := randLR{parseTimeValue(lr[0], lastchar), parseTimeValue(lr[1], lastchar)} - return lr - default: - panic("lr is error") - } -} - -func getInt(v string) int { - vint, err := strconv.Atoi(v) - if err != nil { - panic(err) - } - return vint -} - -func parseTimeValue(v string, lastchar byte) int { - - vlen := len(v) - - switch lastchar { - case 's': - return getInt(v[:vlen-1]) - case 'm': - return getInt(v[:vlen-1]) * 60 - case 'h': - return getInt(v[:vlen-1]) * 3600 - case 'd': - return getInt(v[:vlen-1]) * 3600 * 24 - default: - return getInt(v) - } -} diff --git a/crontab_test.go b/crontab_test.go index f43cf74..4b87401 100644 --- a/crontab_test.go +++ b/crontab_test.go @@ -2,6 +2,7 @@ package crontab import ( "fmt" + "log" "runtime" "testing" "time" @@ -37,12 +38,12 @@ func TestParseCrontab(t *testing.T) { func TestParseInterval(t *testing.T) { //crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围 //crontab := "f1-2|1-3|5-8x5,f1|10m,10-15,f22?15-12" - crontab := "2" + crontab := "2s" cron := NewCrontab(crontab) now := time.Now() - for i := 0; i <= 6; i++ { + for i := 0; i <= 3; i++ { + log.Println(cron.NextTime()) if cron.TimeUp() { - sec := time.Since(now).Seconds() if i != 0 { if 2.0 <= sec && sec <= 2.1 { @@ -65,6 +66,52 @@ func TestParseIntervalPlus(t *testing.T) { //crontab := "0-5/2,7-30/3,30,35,40-^1 * * * *" //(秒) 分 时 号(每月的多少号, 要注意月可可能性) 星期几(每个星期的) /每 ,列表 -范围 //crontab := "f1-2|1-3|5-8x5,f1|10m,10-15,f1" ^代表往后算 ^5 2月份就代表 28-4=24 f代表失败后1-2秒设置 由SetStatus控制 t 相反默认不写前缀为t + crontab := "f2|f2?3|f3?4|1" + cron := NewCrontab(crontab) + now := time.Now() + t.Error("") + for i := 0; i <= 5*15; i++ { + cron.NextTime() + if cron.TimeUp() { + sec := time.Since(now).Seconds() + cron.SetStatus(false) + t.Error(i, sec) + if i == 0 { + if 1.0 <= sec && sec <= 1.1 { + t.Log(sec) + } else { + t.Error(i, "interval time is ", sec) + } + } + + if i == 1 { + if 2.0 <= sec && sec <= 2.1 { + t.Log(sec) + } else { + t.Error(i, "interval time is ", sec) + } + } + + if i == 2 { + if 3.0 <= sec && sec <= 3.1 { + t.Log(sec) + } else { + t.Error(i, "interval time is ", sec) + } + } + + if i == 3 { + if 4.0 <= sec && sec <= 4.1 { + t.Log(sec) + } else { + t.Error(i, "interval time is ", sec) + } + } + + now = time.Now() + } + time.Sleep(time.Millisecond * 200) + } } func PrintMemUsage() { diff --git a/priority_list.go b/priority_list.go deleted file mode 100644 index 1310451..0000000 --- a/priority_list.go +++ /dev/null @@ -1,120 +0,0 @@ -package crontab - -import ( - "github.com/davecgh/go-spew/spew" -) - -// INode 比较的必须继承的接口 -type INode interface { - Compare(v INode) bool - - // GetValue 获取值 - GetValue() interface{} - // SetValue 设置值 - SetValue(v interface{}) - - GetPrev() INode - SetPrev(INode) - GetNext() INode - SetNext(INode) -} - -// Node 优先链表的节点 -type Node struct { - INode - prev, next INode - // isrelease bool - value interface{} -} - -// NewNode 创建一个PriorityList 节点 -func NewNode(v interface{}) *Node { - n := new(Node) - n.SetValue(v) - return n -} - -// GetValue 获取值 -func (node *Node) GetValue() interface{} { - return node.value -} - -// SetValue 设置值 -func (node *Node) SetValue(v interface{}) { - node.value = v -} - -// GetPrev 获取left值 -func (node *Node) GetPrev() INode { - return node.prev -} - -// SetPrev 设置left值 -func (node *Node) SetPrev(n INode) { - node.prev = n -} - -// GetNext 设置right值 -func (node *Node) GetNext() INode { - return node.next -} - -// SetNext 获取left值 -func (node *Node) SetNext(n INode) { - node.next = n -} - -// PriorityList 优先列表 -type PriorityList struct { - head INode -} - -func (pl *PriorityList) String() string { - content := "[" - - cur := pl.head - for cur != nil { - content += spew.Sprint(cur.GetValue()) + "<->" - cur = cur.GetNext() - } - - if content[len(content)-3:] == "<->" { - content = content[:len(content)-3] - } - - content += "]" - return content -} - -func (pl *PriorityList) InsertValue(node INode) { - - if pl.head == nil { - pl.head = node - } else { - cur := pl.head - var prev INode - for cur != nil { - if !cur.Compare(node) { - // 插入该值 - prev = cur.GetPrev() - if prev == nil { - node.SetNext(pl.head) - pl.head = node - } else { - prev.SetNext(node) - node.SetNext(cur) - cur.SetPrev(node) - node.SetPrev(prev) - return - } - } - cur = cur.GetNext() - } - prev.SetNext(node) - } -} - -// New 创建 PriorityList -func New() *PriorityList { - return new(PriorityList) -} diff --git a/priority_list_test.go b/priority_list_test.go deleted file mode 100644 index 02b0ffb..0000000 --- a/priority_list_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package crontab - -import "testing" - -type FL struct { - Node -} - -func (fl *FL) Compare(v INode) bool { - return fl.GetValue().(int) > v.GetValue().(int) -} - -func TestPriorityInsert(t *testing.T) { - pl := New() - - fl := new(FL) - fl.SetValue(12) - pl.InsertValue(fl) - fl = new(FL) - fl.SetValue(123) - pl.InsertValue(fl) - fl = new(FL) - fl.SetValue(1233) - pl.InsertValue(fl) - fl = new(FL) - fl.SetValue(1) - pl.InsertValue(fl) - t.Error(pl.String()) -}