diff --git a/README.md b/README.md index ec9ad196..04230e1a 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ zerobot [-h] [-t token] [-u url] [-n nickname] [-p prefix] [-d|w] [-g 监听地 - [x] /服务列表 - [x] /服务详情 - [x] @Bot 插件冲突检测 (会在本群发送一条消息并在约 1s 后撤回以检测其它同类 bot 中已启用的插件并禁用) -- **定时指令触发器** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/job"` +- **定时指令触发器** `import _ "github.com/FloatTech/zbputils/job"` - [x] 记录以"完全匹配关键词"触发的(代表我执行的)指令 - [x] 取消以"完全匹配关键词"触发的(代表我执行的)指令 - [x] 记录在"cron"触发的指令 @@ -194,9 +194,17 @@ print("run[CQ:image,file="+j["img"]+"]") - **摸鱼** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu"` - [x] /启用 moyu - [x] /禁用 moyu +``` +记录在"0 10 * * *"触发的指令 +摸鱼提醒 +``` - **摸鱼人日历** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu_calendar"` - [x] /启用 moyucalendar - [x] /禁用 moyucalendar +``` +记录在"30 8 * * *"触发的指令 +摸鱼人日历 +``` - **涩图** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/setutime"` - [x] 来份[涩图/二次元/风景/车万] - [x] 添加[涩图/二次元/风景/车万][P站图片ID] @@ -349,9 +357,10 @@ print("run[CQ:image,file="+j["img"]+"]") - **城市疫情查询** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/epidemic"` - [x] xxx疫情 - **早报** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/zaobao"` -> api早上8点更新,推荐定时在8点30后。配合插件`job`中的记录在"cron"触发的指令使用。 + - api早上8点更新,推荐定时在8点30后。配合插件`job`中的记录在"cron"触发的指令使用 + - [x] /启用 zaobao + - [x] /禁用 zaobao ``` -/启用 zaobao 记录在"00 9 * * *"触发的指令 今日早报 ``` diff --git a/go.mod b/go.mod index bf9f23c0..e254ea7f 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/FloatTech/ZeroBot-Plugin go 1.17 require ( - github.com/FloatTech/AnimeAPI v1.3.1-0.20220311024222-ed58ddf6834e + github.com/FloatTech/AnimeAPI v1.3.1 github.com/FloatTech/sqlite v0.2.1 - github.com/FloatTech/zbputils v1.3.1-0.20220311032316-df8ab8b3c180 + github.com/FloatTech/zbputils v1.3.1 github.com/antchfx/htmlquery v1.2.4 github.com/corona10/goimagehash v1.0.3 github.com/fogleman/gg v1.3.0 diff --git a/go.sum b/go.sum index 2d47dbe0..083a0b5f 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,10 @@ -github.com/FloatTech/AnimeAPI v1.3.1-0.20220311024222-ed58ddf6834e h1:PKm/g1M7rYu6YMOV5k8xCOkgXTKF2Tk9v2exeYyCe+0= -github.com/FloatTech/AnimeAPI v1.3.1-0.20220311024222-ed58ddf6834e/go.mod h1:JNF2O/RdbrsDIccSQ29a4g1pQRrZsN0Jh3ggFZYzZuY= +github.com/FloatTech/AnimeAPI v1.3.1 h1:EBNz9pzfH5vYqs8HyME9AL3gXjO+iJ5DgWmqOfdNb18= +github.com/FloatTech/AnimeAPI v1.3.1/go.mod h1:rEBMdnN1yPKt9DdL/BRSRibp7jR1SQiLIaEeQ53R+dk= github.com/FloatTech/bot-manager v1.0.0/go.mod h1:8YYRJ16oroGHQGD2En0oVnmcKJkxR9O/jd5BPSfWfOQ= github.com/FloatTech/sqlite v0.2.1 h1:9t6Me48XJJCIoPy4nLRvcdhcVKfT0c2lilp7SEKROG8= github.com/FloatTech/sqlite v0.2.1/go.mod h1:6NfHRzqOo9RWeMJEoAQVuo51Omd5LFNxCNQhMF02/9U= -github.com/FloatTech/zbputils v1.3.1-0.20220307143543-1139754cacdf/go.mod h1:u+PiX1khNvtAgfRVTVP4hkA2oUnn5q5dTZSk1Cgp0Gw= -github.com/FloatTech/zbputils v1.3.1-0.20220311032316-df8ab8b3c180 h1:8tE9DYu0+YMk3oKeO0ffl80818ZrPM9afbRgb2ag0tQ= -github.com/FloatTech/zbputils v1.3.1-0.20220311032316-df8ab8b3c180/go.mod h1:u+PiX1khNvtAgfRVTVP4hkA2oUnn5q5dTZSk1Cgp0Gw= +github.com/FloatTech/zbputils v1.3.1 h1:ZdK5vkjdtDoeB83FoPAd+vIRmKdILeDSsLLiDIdanVI= +github.com/FloatTech/zbputils v1.3.1/go.mod h1:ByNutpHjwyrhaxo54dRjJDEppko0Fcot2iOv7WrIDUg= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc h1:AAx50/fb/xS4lvsdQg+bFbGvqSDhyV1MF+p2PLCamZ0= github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc/go.mod h1:OMmITAib6POA37xCichWM0aRnoVpSMZO1rB/G01wrr0= diff --git a/main.go b/main.go index e610318f..c0295c1c 100644 --- a/main.go +++ b/main.go @@ -35,6 +35,8 @@ import ( _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复 + _ "github.com/FloatTech/zbputils/job" // 定时指令触发器 + // ^^^^ // // ^^^^^^^^^^^^^^ // // ^^^^^^^高优先级区^^^^^^^ // @@ -79,7 +81,6 @@ import ( _ "github.com/FloatTech/ZeroBot-Plugin/plugin/image_finder" // 关键字搜图 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/inject" // 注入指令 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/jandan" // 煎蛋网无聊图 - _ "github.com/FloatTech/ZeroBot-Plugin/plugin/job" // 定时指令触发器 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi" // 绝绝子生成器 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolicon" // lolicon 随机图片 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu" // 摸鱼 diff --git a/plugin/job/main.go b/plugin/job/main.go deleted file mode 100644 index c94710c1..00000000 --- a/plugin/job/main.go +++ /dev/null @@ -1,541 +0,0 @@ -// Package job 定时指令触发器 -package job - -import ( - "encoding/json" - "hash/crc64" - "strconv" - "strings" - "sync" - "time" - - "github.com/FloatTech/zbputils/binary" - "github.com/FloatTech/zbputils/control" - "github.com/FloatTech/zbputils/control/order" - "github.com/FloatTech/zbputils/ctxext" - "github.com/FloatTech/zbputils/process" - "github.com/FloatTech/zbputils/vevent" - "github.com/FloatTech/zbputils/web" - "github.com/fumiama/cron" - "github.com/sirupsen/logrus" - "github.com/tidwall/gjson" - zero "github.com/wdvxdr1123/ZeroBot" - "github.com/wdvxdr1123/ZeroBot/extension/rate" - "github.com/wdvxdr1123/ZeroBot/message" -) - -var ( - lo map[int64]vevent.Loop - entries = map[int64]cron.EntryID{} // id entryid - matchers = map[int64]*zero.Matcher{} - mu sync.Mutex - limit = rate.NewLimiter(time.Second*2, 1) - en = control.Register("job", order.AcquirePrio(), &control.Options{ - DisableOnDefault: false, - Help: "定时指令触发器\n- 记录以\"完全匹配关键词\"触发的指令\n- 取消以\"完全匹配关键词\"触发的指令\n- 记录在\"cron\"触发的指令\n- 取消在\"cron\"触发的指令\n- 查看所有触发指令\n- 查看在\"cron\"触发的指令\n- 查看以\"完全匹配关键词\"触发的指令\n- 注入指令结果:任意指令\n- 执行指令:任意指令", - PrivateDataFolder: "job", - }) -) - -func init() { - db.DBPath = en.DataFolder() + "job.db" - err := db.Open() - if err != nil { - panic(err) - } - go func() { - process.GlobalInitMutex.Lock() - process.SleepAbout1sTo2s() - lo = make(map[int64]vevent.Loop, len(zero.BotConfig.Driver)) - for _, drv := range zero.BotConfig.Driver { - id := drv.SelfID() - ids := strconv.FormatInt(id, 36) - c := &cmd{} - lo[id] = vevent.NewLoop(id) - err := db.Create(ids, c) - logrus.Infoln("[job]创建表", ids) - if err != nil { - panic(err) - } - _ = db.FindFor(ids, c, "", func() error { - mu.Lock() - defer mu.Unlock() - if strings.HasPrefix(c.Cron, "fm:") { - m := en.OnFullMatch(c.Cron[3:] /* skip fm: */).SetBlock(true) - m.Handle(generalhandler(c)) - matchers[c.ID] = getmatcher(m) - return nil - } - if strings.HasPrefix(c.Cron, "sm:") { - m := en.OnFullMatch(c.Cron[3:] /* skip fm: */).SetBlock(true) - m.Handle(superuserhandler(c)) - matchers[c.ID] = getmatcher(m) - return nil - } - eid, err := process.CronTab.AddFunc(c.Cron, inject(id, []byte(c.Cmd))) - if err != nil { - return err - } - entries[c.ID] = eid - return nil - }) - } - logrus.Infoln("[job]本地环回初始化完成") - process.GlobalInitMutex.Unlock() - }() - en.OnRegex(`^记录在"(.*)"触发的指令$`, ctxext.UserOrGrpAdmin, islonotnil, isfirstregmatchnotnil, logevent).SetBlock(true).Handle(func(ctx *zero.Ctx) { - cron := ctx.State["regex_matched"].([]string)[1] - command := ctx.State["job_raw_event"].(string) - c := &cmd{ - ID: idof(cron, command), - Cron: cron, - Cmd: command, - } - err := addcmd(ctx.Event.SelfID, c) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.SendChain(message.Text("成功!")) - }) - en.OnRegex(`^记录以"(.*)"触发的指令$`, zero.SuperUserPermission, islonotnil, isfirstregmatchnotnil, logevent).SetBlock(true).Handle(func(ctx *zero.Ctx) { - cron := "fm:" + ctx.State["regex_matched"].([]string)[1] - command := ctx.State["job_new_event"].(gjson.Result).Get("message").Raw - logrus.Debugln("[job] get cmd:", command) - c := &cmd{ - ID: idof(cron, command), - Cron: cron, - Cmd: command, - } - err := registercmd(ctx.Event.SelfID, c) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.SendChain(message.Text("成功!")) - }) - en.OnRegex(`^记录以"(.*)"触发的代表我执行的指令$`, zero.SuperUserPermission, islonotnil, isfirstregmatchnotnil, logevent).SetBlock(true).Handle(func(ctx *zero.Ctx) { - cron := "sm:" + ctx.State["regex_matched"].([]string)[1] - command := ctx.State["job_raw_event"].(string) - logrus.Debugln("[job] get cmd:", command) - c := &cmd{ - ID: idof(cron, command), - Cron: cron, - Cmd: command, - } - err := registercmd(ctx.Event.SelfID, c) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.SendChain(message.Text("成功!")) - }) - en.OnRegex(`^取消在"(.*)"触发的指令$`, ctxext.UserOrGrpAdmin, islonotnil, isfirstregmatchnotnil).SetBlock(true).Handle(func(ctx *zero.Ctx) { - cron := ctx.State["regex_matched"].([]string)[1] - err := rmcmd(ctx.Event.SelfID, ctx.Event.UserID, cron) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.SendChain(message.Text("成功!")) - }) - en.OnRegex(`^取消以"(.*)"触发的(代表我执行的)?指令$`, zero.SuperUserPermission, islonotnil, isfirstregmatchnotnil).SetBlock(true).Handle(func(ctx *zero.Ctx) { - issu := ctx.State["regex_matched"].([]string)[2] != "" - cron := "" - if issu { - cron = "sm:" - } else { - cron = "fm:" - } - cron += ctx.State["regex_matched"].([]string)[1] - err := delcmd(ctx.Event.SelfID, cron) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.SendChain(message.Text("成功!")) - }) - en.OnFullMatch("查看所有触发指令", zero.SuperUserPermission, islonotnil).SetBlock(true).Handle(func(ctx *zero.Ctx) { - c := &cmd{} - ids := strconv.FormatInt(ctx.Event.SelfID, 36) - mu.Lock() - defer mu.Unlock() - n, err := db.Count(ids) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - lst := make([]string, 0, n) - err = db.FindFor(ids, c, "GROUP BY cron", func() error { - lst = append(lst, c.Cron+"\n") - return nil - }) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.SendChain(message.Text(lst)) - }) - en.OnRegex(`^查看在"(.*)"触发的指令$`, zero.SuperUserPermission, islonotnil, isfirstregmatchnotnil).SetBlock(true).Handle(func(ctx *zero.Ctx) { - c := &cmd{} - ids := strconv.FormatInt(ctx.Event.SelfID, 36) - cron := ctx.State["regex_matched"].([]string)[1] - mu.Lock() - defer mu.Unlock() - n, err := db.Count(ids) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - lst := make([]string, 0, n) - err = db.FindFor(ids, c, "WHERE cron='"+cron+"'", func() error { - lst = append(lst, c.Cmd+"\n") - return nil - }) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.SendChain(message.Text(lst)) - }) - en.OnRegex(`^查看以"(.*)"触发的(代表我执行的)?指令$`, zero.SuperUserPermission, islonotnil, isfirstregmatchnotnil).SetBlock(true).Handle(func(ctx *zero.Ctx) { - c := &cmd{} - ids := strconv.FormatInt(ctx.Event.SelfID, 36) - issu := ctx.State["regex_matched"].([]string)[2] != "" - cron := "" - if issu { - cron = "sm:" - } else { - cron = "fm:" - } - cron += ctx.State["regex_matched"].([]string)[1] - mu.Lock() - defer mu.Unlock() - n, err := db.Count(ids) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - lst := make([]string, 0, n) - err = db.FindFor(ids, c, "WHERE cron='"+cron+"'", func() error { - lst = append(lst, c.Cmd+"\n") - return nil - }) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.SendChain(message.Text(lst)) - }) - en.OnPrefix("执行指令:", ctxext.UserOrGrpAdmin, islonotnil, func(ctx *zero.Ctx) bool { - return ctx.State["args"].(string) != "" - }, parseArgs).SetBlock(true).Handle(func(ctx *zero.Ctx) { - ev := strings.ReplaceAll(ctx.Event.RawEvent.Raw, "执行指令:", "") - logrus.Debugln("[job] inject:", ev) - inject(ctx.Event.SelfID, binary.StringToBytes(ev))() - }) - en.OnPrefix("注入指令结果:", ctxext.UserOrGrpAdmin, islonotnil, func(ctx *zero.Ctx) bool { - return ctx.State["args"].(string) != "" - }, parseArgs).SetBlock(true).Handle(func(ctx *zero.Ctx) { - vevent.NewLoopOf(vevent.NewAPICallerHook(ctx, func(rsp zero.APIResponse, err error) { - if err == nil { - logrus.Debugln("[job] CallerHook returned") - id := message.NewMessageID(rsp.Data.Get("message_id").String()) - if id.ID() == 0 { - ctx.SendChain(message.Text("ERROR:未获取到返回结果")) - return - } - msg := ctx.GetMessage(id) - ctx.Event.NativeMessage = json.RawMessage("\"" + msg.Elements.String() + "\"") - ctx.Event.RawMessageID = json.RawMessage(msg.MessageId.String()) - ctx.Event.RawMessage = msg.Elements.String() - time.Sleep(time.Second * 5) // 防止风控 - ctx.Event.Time = time.Now().Unix() - ctx.DeleteMessage(id) - vev, cl := binary.OpenWriterF(func(w *binary.Writer) { - err = json.NewEncoder(w).Encode(ctx.Event) - }) - if err != nil { - cl() - ctx.SendChain(message.Text("ERROR:", err)) - return - } - logrus.Debugln("[job] inject:", binary.BytesToString(vev)) - inject(ctx.Event.SelfID, vev)() - cl() - } - })).Echo(binary.StringToBytes(strings.ReplaceAll(ctx.Event.RawEvent.Raw, "注入指令结果:", ""))) - }) -} - -func islonotnil(ctx *zero.Ctx) bool { - return len(lo) > 0 -} - -func isfirstregmatchnotnil(ctx *zero.Ctx) bool { - return ctx.State["regex_matched"].([]string)[1] != "" -} - -func inject(bot int64, response []byte) func() { - return func() { - if limit.Acquire() { - lo[bot].Echo(response) - } - } -} - -func idof(cron, cmd string) int64 { - return int64(crc64.Checksum(binary.StringToBytes(cron+cmd), crc64.MakeTable(crc64.ISO))) -} - -func addcmd(bot int64, c *cmd) error { - mu.Lock() - defer mu.Unlock() - eid, err := process.CronTab.AddFunc(c.Cron, inject(bot, []byte(c.Cmd))) - if err != nil { - return err - } - entries[c.ID] = eid - return db.Insert(strconv.FormatInt(bot, 36), c) -} - -func registercmd(bot int64, c *cmd) error { - mu.Lock() - defer mu.Unlock() - m := en.OnFullMatch(c.Cron[3:] /* skip fm: or sm: */).SetBlock(true) - if strings.HasPrefix(c.Cron, "sm:") { - m.Handle(superuserhandler(c)) - } else { - m.Handle(generalhandler(c)) - } - matchers[c.ID] = getmatcher(m) - return db.Insert(strconv.FormatInt(bot, 36), c) -} - -func generalhandler(c *cmd) zero.Handler { - return func(ctx *zero.Ctx) { - ctx.Event.NativeMessage = json.RawMessage(c.Cmd) // c.Cmd only have message - ctx.Event.Time = time.Now().Unix() - var err error - vev, cl := binary.OpenWriterF(func(w *binary.Writer) { - err = json.NewEncoder(w).Encode(ctx.Event) - }) - if err != nil { - cl() - ctx.SendChain(message.Text("ERROR:", err)) - return - } - logrus.Debugln("[job] inject:", binary.BytesToString(vev)) - inject(ctx.Event.SelfID, vev)() - cl() - } -} - -func superuserhandler(c *cmd) zero.Handler { - e := &zero.Event{Sender: new(zero.User)} - err := json.Unmarshal(binary.StringToBytes(c.Cmd), e) - return func(ctx *zero.Ctx) { - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return - } - ctx.Event.UserID = e.UserID - ctx.Event.RawMessage = e.RawMessage - ctx.Event.Sender = e.Sender - ctx.Event.NativeMessage = e.NativeMessage - vev, cl := binary.OpenWriterF(func(w *binary.Writer) { - err = json.NewEncoder(w).Encode(ctx.Event) - }) - if err != nil { - cl() - ctx.SendChain(message.Text("ERROR:", err)) - return - } - logrus.Debugln("[job] inject:", binary.BytesToString(vev)) - inject(ctx.Event.SelfID, vev)() - cl() - } -} - -func rmcmd(bot, caller int64, cron string) error { - c := &cmd{} - mu.Lock() - defer mu.Unlock() - bots := strconv.FormatInt(bot, 36) - e := new(zero.Event) - var delcmd []string - err := db.FindFor(bots, c, "WHERE cron='"+cron+"'", func() error { - err := json.Unmarshal(binary.StringToBytes(c.Cmd), e) - if err != nil { - return err - } - if e.UserID != caller { - return nil - } - eid, ok := entries[c.ID] - if ok { - process.CronTab.Remove(eid) - delete(entries, c.ID) - delcmd = append(delcmd, "id="+strconv.FormatInt(c.ID, 10)) - } - return nil - }) - if err != nil { - return err - } - if len(delcmd) > 0 { - return db.Del(bots, "WHERE "+strings.Join(delcmd, " or ")) - } - return nil -} - -func delcmd(bot int64, cron string) error { - c := &cmd{} - mu.Lock() - defer mu.Unlock() - bots := strconv.FormatInt(bot, 36) - var delcmd []string - err := db.FindFor(bots, c, "WHERE cron='"+cron+"'", func() error { - m, ok := matchers[c.ID] - if ok { - m.Delete() - delete(matchers, c.ID) - delcmd = append(delcmd, "id="+strconv.FormatInt(c.ID, 10)) - } - return nil - }) - if err != nil { - return err - } - if len(delcmd) > 0 { - return db.Del(bots, "WHERE "+strings.Join(delcmd, " or ")) - } - return nil -} - -func parseArgs(ctx *zero.Ctx) bool { - cmds := ctx.State["args"].(string) - if !strings.Contains(cmds, "?::") && !strings.Contains(cmds, "!::") { - return true - } - args := make(map[int]string) - for strings.Contains(ctx.Event.RawEvent.Raw, "?::") { - start := strings.Index(ctx.Event.RawEvent.Raw, "?::") - msgend := strings.Index(ctx.Event.RawEvent.Raw[start+3:], "::") - if msgend < 0 { - ctx.SendChain(message.Text("ERROR:找不到结束的::")) - return false - } - msgend += start + 3 - numend := strings.Index(ctx.Event.RawEvent.Raw[msgend+2:], "!") - if numend <= 0 { - ctx.SendChain(message.Text("ERROR:找不到结束的!")) - return false - } - numend += msgend + 2 - logrus.Debugln("[job]", start, msgend, numend) - msg := ctx.Event.RawEvent.Raw[start+3 : msgend] - arg, err := strconv.Atoi(ctx.Event.RawEvent.Raw[msgend+2 : numend]) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return false - } - arr, ok := args[arg] - if !ok { - var id message.MessageID - if msg == "" { - id = ctx.SendChain(message.At(ctx.Event.UserID), message.Text("请输入参数", arg)) - } else { - id = ctx.SendChain(message.At(ctx.Event.UserID), message.Text("[", arg, "] ", msg)) - } - select { - case <-time.After(time.Second * 120): - ctx.Send(message.ReplyWithMessage(id, message.Text("参数读取超时"))) - if msg[0] != '?' { - return false - } - case e := <-zero.NewFutureEvent("message", 0, true, zero.CheckUser(ctx.Event.UserID)).Next(): - args[arg] = e.Message.String() - arr = args[arg] - process.SleepAbout1sTo2s() - ctx.SendChain(message.Reply(e.MessageID), message.Text("已记录")) - process.SleepAbout1sTo2s() - } - } - ctx.Event.RawEvent.Raw = ctx.Event.RawEvent.Raw[:start] + arr + ctx.Event.RawEvent.Raw[numend+1:] - } - args = make(map[int]string) - for strings.Contains(ctx.Event.RawEvent.Raw, "!::") { - start := strings.Index(ctx.Event.RawEvent.Raw, "!::") - msgend := strings.Index(ctx.Event.RawEvent.Raw[start+3:], "::") - if msgend < 0 { - ctx.SendChain(message.Text("ERROR:找不到结束的::")) - return false - } - msgend += start + 3 - numend := strings.Index(ctx.Event.RawEvent.Raw[msgend+2:], "!") - if numend <= 0 { - ctx.SendChain(message.Text("ERROR:找不到结束的!")) - return false - } - numend += msgend + 2 - logrus.Debugln("[job]", start, msgend, numend) - u := ctx.Event.RawEvent.Raw[start+3 : msgend] - if u == "" { - return false - } - arg, err := strconv.Atoi(ctx.Event.RawEvent.Raw[msgend+2 : numend]) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - return false - } - arr, ok := args[arg] - if !ok { - isnilable := u[0] == '?' - if isnilable { - u = u[1:] - if u == "" { - return false - } - } - b, err := web.GetData(u) - if err != nil { - ctx.SendChain(message.Text("ERROR:", err)) - if !isnilable { - return false - } - } - if len(b) > 0 { - type fakejson struct { - Arg string `json:"arg"` - } - f := fakejson{Arg: binary.BytesToString(b)} - w := binary.SelectWriter() - defer binary.PutWriter(w) - _ = json.NewEncoder(w).Encode(&f) - arr = w.String()[8 : w.Len()-3] - args[arg] = arr - } - } - w := binary.SelectWriter() - w.WriteString(ctx.Event.RawEvent.Raw[:start]) - w.WriteString(arr) - w.WriteString(ctx.Event.RawEvent.Raw[numend+1:]) - ctx.Event.RawEvent.Raw = string(w.Bytes()) - binary.PutWriter(w) - } - return true -} - -func logevent(ctx *zero.Ctx) bool { - ctx.SendChain(message.Text("您的下一条指令将被记录,在", ctx.State["regex_matched"].([]string)[1], "时触发")) - select { - case <-time.After(time.Second * 120): - ctx.SendChain(message.Text("指令记录超时")) - return false - case e := <-zero.NewFutureEvent("message", 0, true, zero.CheckUser(ctx.Event.UserID)).Next(): - ctx.State["job_raw_event"] = e.RawEvent.Raw - ctx.State["job_new_event"] = e.RawEvent - return true - } -} diff --git a/plugin/job/matcher.go b/plugin/job/matcher.go deleted file mode 100644 index 03e7c6ec..00000000 --- a/plugin/job/matcher.go +++ /dev/null @@ -1,16 +0,0 @@ -package job - -import ( - "unsafe" - - "github.com/FloatTech/zbputils/control" - zero "github.com/wdvxdr1123/ZeroBot" -) - -type matcherinstance struct { - m *zero.Matcher -} - -func getmatcher(m control.Matcher) *zero.Matcher { - return (*matcherinstance)(unsafe.Pointer(&m)).m -} diff --git a/plugin/job/model.go b/plugin/job/model.go deleted file mode 100644 index 2ff06db3..00000000 --- a/plugin/job/model.go +++ /dev/null @@ -1,11 +0,0 @@ -package job - -import sql "github.com/FloatTech/sqlite" - -type cmd struct { - ID int64 `db:"id"` - Cron string `db:"cron"` - Cmd string `db:"cmd"` -} - -var db = &sql.Sqlite{} diff --git a/plugin/moyu/run.go b/plugin/moyu/run.go index fbcf0f5b..a6c2fb81 100644 --- a/plugin/moyu/run.go +++ b/plugin/moyu/run.go @@ -2,68 +2,62 @@ package moyu import ( + "sync" "time" control "github.com/FloatTech/zbputils/control" - "github.com/FloatTech/zbputils/process" zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" "github.com/FloatTech/zbputils/control/order" ) +var ( + msg message.Message + mu sync.Mutex + lastupdate time.Time +) + func init() { // 插件主体 control.Register("moyu", order.AcquirePrio(), &control.Options{ DisableOnDefault: true, Help: "moyu\n" + "- /启用 moyu\n" + - "- /禁用 moyu", - }) - - // 定时任务每天10点执行一次 - _, err := process.CronTab.AddFunc("0 10 * * *", func() { sendNotice() }) - if err != nil { - panic(err) - } -} - -// 获取数据拼接消息链并发送 -func sendNotice() { - m, ok := control.Lookup("moyu") - if ok { - if registry.Connect() != nil { - return - } - msg := message.Message{ - message.Text(time.Now().Format("2006-01-02")), - message.Text("上午好,摸鱼人!\n工作再累,一定不要忘记摸鱼哦!有事没事起身去茶水间,去厕所,去廊道走走别老在工位上坐着,钱是老板的,但命是自己的。\n"), - message.Text(weekend()), - message.Text("\n"), - message.Text(GetHoliday("元旦")), - message.Text("\n"), - message.Text(GetHoliday("春节")), - message.Text("\n"), - message.Text(GetHoliday("清明节")), - message.Text("\n"), - message.Text(GetHoliday("劳动节")), - message.Text("\n"), - message.Text(GetHoliday("端午节")), - message.Text("\n"), - message.Text(GetHoliday("中秋节")), - message.Text("\n"), - message.Text(GetHoliday("国庆节")), - message.Text("\n"), - message.Text("上班是帮老板赚钱,摸鱼是赚老板的钱!最后,祝愿天下所有摸鱼人,都能愉快的渡过每一天…"), - } - _ = registry.Close() - zero.RangeBot(func(id int64, ctx *zero.Ctx) bool { - for _, g := range ctx.GetGroupList().Array() { - grp := g.Get("group_id").Int() - if m.IsEnabledIn(grp) { - ctx.SendGroupMessage(grp, msg) + "- /禁用 moyu\n" + + "- 记录在\"0 10 * * *\"触发的指令\n" + + " - 摸鱼提醒", + }).OnFullMatch("摸鱼提醒").SetBlock(true). + Handle(func(ctx *zero.Ctx) { + mu.Lock() + defer mu.Unlock() + if msg == nil || time.Since(lastupdate) > time.Hour*20 { + if registry.Connect() != nil { + return } + msg = message.Message{ + message.Text(time.Now().Format("2006-01-02")), + message.Text("上午好,摸鱼人!\n工作再累,一定不要忘记摸鱼哦!有事没事起身去茶水间,去厕所,去廊道走走别老在工位上坐着,钱是老板的,但命是自己的。\n"), + message.Text(weekend()), + message.Text("\n"), + message.Text(GetHoliday("元旦")), + message.Text("\n"), + message.Text(GetHoliday("春节")), + message.Text("\n"), + message.Text(GetHoliday("清明节")), + message.Text("\n"), + message.Text(GetHoliday("劳动节")), + message.Text("\n"), + message.Text(GetHoliday("端午节")), + message.Text("\n"), + message.Text(GetHoliday("中秋节")), + message.Text("\n"), + message.Text(GetHoliday("国庆节")), + message.Text("\n"), + message.Text("上班是帮老板赚钱,摸鱼是赚老板的钱!最后,祝愿天下所有摸鱼人,都能愉快的渡过每一天…"), + } + _ = registry.Close() + lastupdate = time.Now() } - return true + ctx.Send(msg) }) - } } diff --git a/plugin/moyu_calendar/calendar.go b/plugin/moyu_calendar/calendar.go index 88358158..02e84a0f 100644 --- a/plugin/moyu_calendar/calendar.go +++ b/plugin/moyu_calendar/calendar.go @@ -14,7 +14,6 @@ import ( control "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control/order" - "github.com/FloatTech/zbputils/process" zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" @@ -31,7 +30,9 @@ func init() { DisableOnDefault: true, Help: "摸鱼人日历\n" + "- /启用 moyucalendar\n" + - "- /禁用 moyucalendar", + "- /禁用 moyucalendar\n" + + "- 记录在\"30 8 * * *\"触发的指令\n" + + " - 摸鱼人日历", }).OnFullMatch("摸鱼人日历").SetBlock(true). Handle(func(ctx *zero.Ctx) { title := fmt.Sprintf("摸鱼人日历 %d月%d日", time.Now().Month(), time.Now().Day()) @@ -52,40 +53,6 @@ func init() { } ctx.SendChain(message.Image(image)) }) - - // 定时任务每天8点30分执行一次 - _, err := process.CronTab.AddFunc("30 8 * * *", func() { - m, ok := control.Lookup("moyucalendar") - if !ok { - return - } - title := fmt.Sprintf("摸鱼人日历 %d月%d日", time.Now().Month(), time.Now().Day()) - sg, cookies, err := sougou(title, "摸鱼人日历", ua) - if err != nil { - return - } - wx, err := redirect(sg, cookies, ua) - if err != nil { - return - } - image, err := calendar(wx, ua) - if err != nil { - return - } - zero.RangeBot(func(id int64, ctx *zero.Ctx) bool { - for _, g := range ctx.GetGroupList().Array() { - grp := g.Get("group_id").Int() - if m.IsEnabledIn(grp) { - ctx.SendGroupMessage(grp, message.Message{message.Image(image)}) - process.SleepAbout1sTo2s() - } - } - return true - }) - }) - if err != nil { - panic(err) - } } func sougou(title, publisher, ua string) (string, []*http.Cookie, error) { diff --git a/plugin/zaobao/zaobao.go b/plugin/zaobao/zaobao.go index e4e0f956..0924ae1e 100644 --- a/plugin/zaobao/zaobao.go +++ b/plugin/zaobao/zaobao.go @@ -24,20 +24,18 @@ const ( var ( picdata []byte - mu sync.RWMutex + mu sync.Mutex pictime time.Time ) func init() { // 插件主体 engine := control.Register("zaobao", order.AcquirePrio(), &control.Options{ DisableOnDefault: true, - Help: "zaobao\n" + + Help: "易即今日公众号api的今日早报\n" + "api早上8点更新,推荐定时在8点30后\n" + - "配合插件job中的记录在'cron'触发的指令使用\n" + - "------示例------\n" + - "每天早上九点定时发送\n" + - "记录在'00 9 * * *'触发的指令\n" + - "今日早报", + "配合插件job中的记录在\"cron\"触发的指令使用\n" + + "- 记录在\"0 9 * * *\"触发的指令\n" + + " - 今日早报", }) engine.OnFullMatch("今日早报", zero.OnlyGroup).SetBlock(false). Handle(func(ctx *zero.Ctx) { @@ -51,23 +49,9 @@ func init() { // 插件主体 } func getdata() error { // 获取图片链接并且下载 - mu.RLock() - if time.Since(pictime) > time.Hour*20 { - mu.RUnlock() - mu.Lock() - picdata = nil - pictime = time.Now() - mu.Unlock() - mu.RLock() - } - if picdata != nil { - mu.RUnlock() - return nil - } - mu.RUnlock() mu.Lock() defer mu.Unlock() - if picdata != nil { + if picdata != nil && time.Since(pictime) <= time.Hour*20 { return nil } data, err := web.GetDataWith(web.NewDefaultClient(), api, "GET", "", ua) @@ -78,5 +62,6 @@ func getdata() error { // 获取图片链接并且下载 if err != nil { return err } + pictime = time.Now() return nil }