From b342ed0dbcd0ad88a896f2ca9cbdd06a3ef5e624 Mon Sep 17 00:00:00 2001 From: starainrt Date: Wed, 17 May 2023 17:11:06 +0800 Subject: [PATCH] update --- go.mod | 17 +++++++- go.sum | 31 +++++++++++++-- remind/remind.go | 88 +++++++++++++++++++++++++++++++++--------- remind/reminde_test.go | 58 ++++++++++++++++++++++++++++ when/parse.go | 48 ++++++++++++++++------- when/parse_test.go | 13 ++++++- 6 files changed, 215 insertions(+), 40 deletions(-) create mode 100644 remind/reminde_test.go diff --git a/go.mod b/go.mod index 1532864..fcdee4a 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,19 @@ module b612.me/sdk/candy go 1.20 require ( - b612.me/stardb v1.1.3 - b612.me/startimer v0.0.0-20230501080256-b0fd8947f0dc + b612.me/stardb v1.1.4 + b612.me/startimer v0.0.1 + github.com/glebarez/go-sqlite v1.21.1 +) + +require ( + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/sys v0.4.0 // indirect + modernc.org/libc v1.22.3 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.21.1 // indirect ) diff --git a/go.sum b/go.sum index 0a60ac1..00974d7 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,27 @@ -b612.me/stardb v1.1.3 h1:cx16v64FmfCh+cCF6GDDiVUF+ZISpBxBH3t2GkBkeJY= -b612.me/stardb v1.1.3/go.mod h1:qtGEu+joEQxFESl3tse5xqiD767f6sAmHD284+Xoy48= -b612.me/startimer v0.0.0-20230501080256-b0fd8947f0dc h1:WO8jZiLVssi3myTWX5Oo/+/i9vk+Alo4ymJhHi4TXp0= -b612.me/startimer v0.0.0-20230501080256-b0fd8947f0dc/go.mod h1:8fw+OU7SnxzuLkNCYSbRKmvs4WtHs6SbCHuTf5F6s+U= +b612.me/stardb v1.1.4 h1:Ic+CwGZpDKtgHTkDJ5/1kxgEEGM9Hj5xu9i0n6CbXfs= +b612.me/stardb v1.1.4/go.mod h1:qtGEu+joEQxFESl3tse5xqiD767f6sAmHD284+Xoy48= +b612.me/startimer v0.0.1 h1:7Q4hzkXZR1iFSWyEoTBjUiDx1HsROIvIel3HdfhIhxo= +b612.me/startimer v0.0.1/go.mod h1:7YlIWMVBIxLObVI0Ls+CMCCVZJ+4DdTaqF2TshthZjk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/glebarez/go-sqlite v1.21.1 h1:7MZyUPh2XTrHS7xNEHQbrhfMZuPSzhkm2A1qgg0y5NY= +github.com/glebarez/go-sqlite v1.21.1/go.mod h1:ISs8MF6yk5cL4n/43rSOmVMGJJjHYr7L2MbZZ5Q4E2E= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY= +modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.21.1 h1:GyDFqNnESLOhwwDRaHGdp2jKLDzpyT/rNLglX3ZkMSU= +modernc.org/sqlite v1.21.1/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI= diff --git a/remind/remind.go b/remind/remind.go index 1097b83..cfef7a1 100644 --- a/remind/remind.go +++ b/remind/remind.go @@ -5,18 +5,19 @@ import ( "b612.me/stardb" "b612.me/startimer" "errors" + "fmt" "sync" "time" ) type Remind struct { db *stardb.StarDB - tasks map[int]RemindTask + tasks map[int]Task mu sync.RWMutex - callback func(remind RemindTask) + callback func(remind Task) } -type RemindTask struct { +type Task struct { ID int `db:"id"` Origin string `db:"text"` timer *startimer.StarTimer @@ -32,7 +33,7 @@ func getCreateSql() []string { } } -func NewRemind(db *stardb.StarDB, callback func(task RemindTask)) (*Remind, error) { +func NewRemind(db *stardb.StarDB, callback func(task Task)) (*Remind, error) { if db == nil || db.Db == nil { return nil, errors.New("Invalid hanlder of database") } @@ -48,13 +49,14 @@ func NewRemind(db *stardb.StarDB, callback func(task RemindTask)) (*Remind, erro return innerLoadDB(db, callback) } -func innerLoadDB(db *stardb.StarDB, callback func(task RemindTask)) (*Remind, error) { +func innerLoadDB(db *stardb.StarDB, callback func(task Task)) (*Remind, error) { var rem = Remind{ db: db, mu: sync.RWMutex{}, callback: callback, + tasks: make(map[int]Task), } - var res []RemindTask + var res []Task data, err := db.Query("select * from remind") if err != nil { return nil, err @@ -64,7 +66,7 @@ func innerLoadDB(db *stardb.StarDB, callback func(task RemindTask)) (*Remind, er return nil, err } if len(res) != 0 { - rem.tasks = make(map[int]RemindTask, len(res)) + rem.tasks = make(map[int]Task, len(res)) for _, task := range res { tmr := startimer.NewTimer(time.Now()) err = tmr.ImportRepeats(task.TmrInfo) @@ -85,23 +87,28 @@ func innerLoadDB(db *stardb.StarDB, callback func(task RemindTask)) (*Remind, er return &rem, nil } -func (t RemindTask) GetTimer() startimer.StarTimer { - return *t.timer +func (t Task) GetTimer() *startimer.StarTimer { + return t.timer } -func (r *Remind) callbackFn(task RemindTask) { - r.callback(task) +func (r *Remind) callbackFn(task Task) { + if r.callback != nil { + r.callback(task) + } + if !task.GetTimer().IsRunning() { + r.DeleteTask(task.ID) + } } -func (r *Remind) AddTask(taskStr, key string, msg []byte) (RemindTask, error) { +func (r *Remind) AddTask(taskStr, key string, msg []byte) (Task, error) { tmr, err := when.WhenWithPeriod(taskStr) if err != nil { - return RemindTask{}, err + return Task{}, err } exp, err := tmr.ExportRepeats() if err != nil { - return RemindTask{}, err + return Task{}, err } - var rmt = RemindTask{ + var rmt = Task{ Origin: taskStr, TmrInfo: exp, Key: key, @@ -113,17 +120,23 @@ func (r *Remind) AddTask(taskStr, key string, msg []byte) (RemindTask, error) { }) res, err := r.db.Insert(rmt, "remind", "id") if err != nil { - return RemindTask{}, err + return Task{}, err } id, err := res.LastInsertId() if err != nil { - return RemindTask{}, err + return Task{}, err } rmt.ID = int(id) r.mu.Lock() r.tasks[rmt.ID] = rmt r.mu.Unlock() - rmt.timer.Run() + fmt.Println(tmr.ExportRepeats()) + err = rmt.timer.Run() + time.Sleep(time.Microsecond * 100) + if err != nil || !rmt.timer.IsRunning() { + r.DeleteTask(rmt.ID) + return Task{}, err + } return rmt, nil } @@ -147,3 +160,42 @@ func (r *Remind) DeleteTask(id int) error { delete(r.tasks, id) return nil } + +func (r *Remind) ListTasks() []Task { + var res = make([]Task, 0, len(r.tasks)) + r.mu.RLock() + defer r.mu.RUnlock() + for _, tk := range r.tasks { + res = append(res, tk) + } + return res +} + +func (r *Remind) GetTasksByKey(key string) []Task { + var res []Task + r.mu.RLock() + defer r.mu.RUnlock() + for _, tk := range r.tasks { + if tk.Key == key { + res = append(res, tk) + } + } + return res +} + +func (r *Remind) Stop() error { + for _, task := range r.tasks { + task.GetTimer().Stop() + } + return nil +} + +func (r *Remind) Reset() error { + for _, task := range r.tasks { + err := r.DeleteTask(task.ID) + if err != nil { + return err + } + } + return nil +} diff --git a/remind/reminde_test.go b/remind/reminde_test.go new file mode 100644 index 0000000..1b80a0a --- /dev/null +++ b/remind/reminde_test.go @@ -0,0 +1,58 @@ +package remind + +import ( + "b612.me/stardb" + "fmt" + _ "github.com/glebarez/go-sqlite" + "os" + "testing" + "time" +) + +func exists(path string) bool { + _, err := os.Stat(path) + if os.IsNotExist(err) { + return false + } + return err == nil +} + +func TestRemind(t *testing.T) { + var db stardb.StarDB + err := db.Open("sqlite", "./remind.db") + if err != nil { + t.Fatal(err) + } + sign := make(chan int) + r, err := NewRemind(&db, func(task Task) { + fmt.Println("hello world!", time.Now(), task.ID, task.Key, task.TmrInfo, task.Msg, task.Origin) + sign <- 1 + }) + if err != nil { + t.Fatal(err) + } + fmt.Println("length of remind", len(r.ListTasks())) + if len(r.ListTasks()) < 2 { + tk, err := r.AddTask("每8秒提醒我吃饭", "干饭", []byte{1, 2, 3}) + if err != nil { + t.Fatal(err) + } + tmr := tk.GetTimer() + fmt.Println(tmr.NextTimer()) + } + i := 0 + for { + select { + case <-sign: + i++ + break + case <-time.After(time.Second * 15): + t.FailNow() + } + time.Sleep(time.Second) + fmt.Println(len(r.ListTasks())) + if i == 3 { + break + } + } +} diff --git a/when/parse.go b/when/parse.go index b746aa2..b23afd5 100644 --- a/when/parse.go +++ b/when/parse.go @@ -13,9 +13,10 @@ func matchPeriodPattern01(base time.Time, str string) (startimer.StarTimer, erro str = transChn(str) var rpt startimer.Repeats var duration time.Duration - reg := regexp.MustCompile(`(每隔|每)?(\d{1,4}年)?(\d{1,5}个?月)?(\d{1,4}[明后大]{0,4}[日号天])?([上中下午夜早凌清晨傍晚里]+)?(\d{1,4}个?[点小时钟:]+)?(\d{1,4}[分:])?(\d{1,10}秒?)?(后)?`) + reg := regexp.MustCompile(`(每隔|每)?(\d{0,4}年)?(\d{0,5}个?月)?(\d{0,4}[明后大]{0,4}[日号天])?([上中下午夜早凌清晨傍晚里]+)?(\d{1,4}个?[点小时钟:]+)?(\d{1,4}[分:])?(\d{1,10}秒?)?(后)?`) if reg.MatchString(str) { pts := reg.FindStringSubmatch(str) + setAsDate := false var timeParse = pts[5] count := 1 if pts[1] != "" { @@ -26,19 +27,31 @@ func matchPeriodPattern01(base time.Time, str string) (startimer.StarTimer, erro if !rpt.Every { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_YEAR, Value: uint32(getNumbers(pts[2]))}) } else { - duration += time.Hour * 24 * 365 * time.Duration(getNumbers(pts[2])) + if getNumbers(pts[2]) == 0 { + setAsDate = true + } else { + duration += time.Hour * 24 * 365 * time.Duration(getNumbers(pts[2])) + } } } if pts[3] != "" { - if !rpt.Every { + if !rpt.Every || setAsDate { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MONTH, Value: uint32(getNumbers(pts[3]))}) } else { - duration += time.Hour * 24 * 30 * time.Duration(getNumbers(pts[3])) + if getNumbers(pts[3]) == 0 { + setAsDate = true + } else { + duration += time.Hour * 24 * 30 * time.Duration(getNumbers(pts[3])) + } } } if pts[4] != "" { now := time.Now() switch pts[4] { + case "天": + if rpt.Every { + setAsDate = true + } case "明天": rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_DAY, Value: uint32(now.Add(time.Hour * 24).Day())}) case "后天": @@ -48,27 +61,28 @@ func matchPeriodPattern01(base time.Time, str string) (startimer.StarTimer, erro case "大大后天": rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_DAY, Value: uint32(now.Add(time.Hour * 96).Day())}) default: - if !rpt.Every { + if setAsDate == rpt.Every { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_DAY, Value: uint32(getNumbers(pts[4]))}) } else { duration += time.Hour * 24 * time.Duration(getNumbers(pts[4])) } } } - setAsDate := false + if rpt.Every && timeParse != "" { setAsDate = true - } else if rpt.Every && !strings.Contains(pts[6], "小时") { - setAsDate = true - base = time.Date(base.Year(), base.Month(), base.Day(), 0, 0, 0, 0, base.Location()) } + //else if rpt.Every && !strings.Contains(pts[6], "小时") { + // setAsDate = true + // base = time.Date(base.Year(), base.Month(), base.Day(), 0, 0, 0, 0, base.Location()) + // } var hour uint32 if pts[6] != "" { hour = uint32(getNumbers(pts[6])) if timeParse == "下午" || strings.Contains(timeParse, "晚") || strings.Contains(timeParse, "夜") { hour += 12 } - if !setAsDate && !rpt.Every { + if rpt.Every == setAsDate { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_HOUR, Value: hour}) } else if rpt.Every && !setAsDate { duration += time.Hour * time.Duration(hour) @@ -99,7 +113,7 @@ func matchPeriodPattern01(base time.Time, str string) (startimer.StarTimer, erro } } if pts[7] != "" { - if !setAsDate && !rpt.Every { + if rpt.Every == setAsDate { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MINUTE, Value: uint32(getNumbers(pts[7]))}) } else if rpt.Every && !setAsDate { duration += time.Minute * time.Duration(uint32(getNumbers(pts[7]))) @@ -107,13 +121,13 @@ func matchPeriodPattern01(base time.Time, str string) (startimer.StarTimer, erro base.Add(time.Minute * time.Duration(uint32(getNumbers(pts[7])))) } } else if hour != 0 { - if !rpt.Every && !setAsDate { + if rpt.Every == setAsDate { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_MINUTE, Value: 0}) } } if pts[8] != "" { - if !setAsDate && !rpt.Every { + if rpt.Every == setAsDate { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: uint32(getNumbers(pts[8]))}) } else if rpt.Every && !setAsDate { duration += time.Second * time.Duration(uint32(getNumbers(pts[8]))) @@ -121,7 +135,7 @@ func matchPeriodPattern01(base time.Time, str string) (startimer.StarTimer, erro base.Add(time.Second * time.Duration(uint32(getNumbers(pts[8])))) } } else if hour != 0 { - if !rpt.Every && !setAsDate { + if rpt.Every == setAsDate { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: 0}) } } @@ -151,6 +165,9 @@ func matchPeriodPattern01(base time.Time, str string) (startimer.StarTimer, erro if duration.Seconds() > 0 { rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_SECOND, Value: uint32(duration.Seconds())}) } + if rpt.Every == setAsDate { + rpt.Every = false + } return startimer.NewTimer(base, startimer.WithRepeats(&rpt), startimer.WithRunCountLimit(count)), nil } return startimer.StarTimer{}, errors.New("no Match") @@ -182,6 +199,9 @@ func matchPeroidPattern02(base time.Time, str string) (startimer.StarTimer, erro } rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_WEEK, Value: uint32(num)}) } + } else { + wkNum := getNumbers(wk) + rpt.Repeat = append(rpt.Repeat, startimer.Repeat{Unit: startimer.STAR_WEEK, Value: uint32(wkNum)}) } } diff --git a/when/parse_test.go b/when/parse_test.go index 751c084..afcacac 100644 --- a/when/parse_test.go +++ b/when/parse_test.go @@ -8,8 +8,17 @@ import ( func TestParse(t *testing.T) { for _, code := range []string{"一个小时后告诉我事情", "三个小时后爱我", "每两个小时提醒我吃饭", - "每五个月零二十五天三小时25分15秒告诉我时间", "5月23日上午3点24分12秒打我", "周四上午11点提醒我", - "每周一到周五上午8点提醒我吃饭"} { + "每五个月零二十五天三小时25分15秒告诉我时间", "5月23日上午3点24分12秒打我", "周五上午11点提醒我", "5时25分提醒我", + "每周一到周五上午8点提醒我吃饭", "每天晚上8点提醒我吃饭", "每月16号晚上8点提醒我吃饭"} { + a, _ := WhenWithPeriod(code) + //fmt.Println(a.Repeats()[0]) + fmt.Println(a.NextTimer(), a.RunCountLimit(), code) + fmt.Println(a.NextTimerAfterDate(time.Now().Add(time.Hour * 72))) + } +} + +func TestSigParse(t *testing.T) { + for _, code := range []string{"每月16号晚上8点提醒我吃饭"} { a, _ := WhenWithPeriod(code) //fmt.Println(a.Repeats()[0]) fmt.Println(a.NextTimer(), a.RunCountLimit(), code)