You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
3.9 KiB
Go

package remind
import (
"b612.me/sdk/candy/when"
"b612.me/stardb"
"b612.me/startimer"
"errors"
"fmt"
"sync"
"time"
)
type Remind struct {
db *stardb.StarDB
tasks map[int]Task
mu *sync.RWMutex
callback func(remind Task)
}
type Task struct {
ID int `db:"id"`
Origin string `db:"text"`
timer *startimer.StarTimer
TmrInfo string `db:"code"`
Key string `db:"key"`
Msg []byte `db:"msg"`
}
func getCreateSql() []string {
return []string{
"CREATE TABLE IF NOT EXISTS remind(id INTEGER PRIMARY KEY AUTOINCREMENT,key VARCHAR(64),code TEXT,text TEXT,msg BLOB)",
"CREATE INDEX IF NOT EXISTS key_idx ON remind (key)",
}
}
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")
}
if err := db.Ping(); err != nil {
return nil, err
}
for _, sql := range getCreateSql() {
_, err := db.Exec(sql)
if err != nil {
return nil, err
}
}
return innerLoadDB(db, callback)
}
func innerLoadDB(db *stardb.StarDB, callback func(task Task)) (*Remind, error) {
var rem = Remind{
db: db,
mu: new(sync.RWMutex),
callback: callback,
tasks: make(map[int]Task),
}
var res []Task
data, err := db.Query("select * from remind")
if err != nil {
return nil, err
}
err = data.Orm(&res)
if err != nil {
return nil, err
}
if len(res) != 0 {
rem.tasks = make(map[int]Task, len(res))
for _, task := range res {
tmr := startimer.NewTimer(time.Now())
err = tmr.ImportRepeats(task.TmrInfo)
if err != nil {
return nil, err
}
task.timer = &tmr
task.timer.AddTask(func() {
rem.callbackFn(task)
})
err = task.timer.Run()
if err != nil {
return nil, err
}
rem.tasks[task.ID] = task
}
}
return &rem, nil
}
func (t Task) GetTimer() *startimer.StarTimer {
return t.timer
}
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) (Task, error) {
tmr, err := when.WhenWithPeriod(taskStr)
if err != nil {
return Task{}, err
}
exp, err := tmr.ExportRepeats()
if err != nil {
return Task{}, err
}
var rmt = Task{
Origin: taskStr,
TmrInfo: exp,
Key: key,
Msg: msg,
timer: &tmr,
}
rmt.timer.AddTask(func() {
r.callbackFn(rmt)
})
res, err := r.db.Insert(rmt, "remind", "id")
if err != nil {
return Task{}, err
}
id, err := res.LastInsertId()
if err != nil {
return Task{}, err
}
rmt.ID = int(id)
r.mu.Lock()
r.tasks[rmt.ID] = rmt
r.mu.Unlock()
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
}
func (r *Remind) DeleteTask(id int) error {
r.mu.RLock()
data, ok := r.tasks[id]
r.mu.RUnlock()
if !ok {
return errors.New("no such id")
}
r.mu.Lock()
defer r.mu.Unlock()
err := data.timer.Stop()
if err != nil {
return err
}
_, err = r.db.Exec("delete from remind where id=?", id)
if err != nil {
return err
}
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) GetTaskByID(id int) Task {
r.mu.RLock()
defer r.mu.RUnlock()
return r.tasks[id]
}
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
}