From 4bf573933b67a9c618523fc4f8d2bbd74e97e469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Thu, 6 Oct 2022 21:13:47 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E5=93=8D=E5=BA=94=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E4=B8=BB=E4=BA=BA=20&=20=E6=8C=89=E9=A1=BA=E5=BA=8F=E6=89=93?= =?UTF-8?q?=E5=8D=B0=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cd.go | 4 +- engine.go | 5 ++ example/echo/main.go | 3 +- example/main.go | 2 +- manager.go | 23 ++++++ rule.go | 187 ++++++++++++++++++++++++++++++++----------- rules.go | 2 +- 7 files changed, 175 insertions(+), 51 deletions(-) diff --git a/cd.go b/cd.go index f28e353..f6633bf 100644 --- a/cd.go +++ b/cd.go @@ -26,7 +26,7 @@ func init() { startTime = time.Now().Unix() msg, err := ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "●cd"+tok)) if err != nil { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "ERROR: "+err.Error())) + _, _ = ctx.SendPlainMessage(false, "ERROR: ", err) return } process.SleepAbout1sTo2s() @@ -54,7 +54,7 @@ func init() { msg, err := ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, binutils.BytesToString(my))) cl() if err != nil { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "ERROR: "+err.Error())) + _, _ = ctx.SendPlainMessage(false, "ERROR: ", err) return } process.SleepAbout1sTo2s() diff --git a/engine.go b/engine.go index b6b9909..44087c8 100644 --- a/engine.go +++ b/engine.go @@ -477,6 +477,11 @@ func (e *Engine) OnCallbackQueryKeywordGroup(keywords []string, rules ...Rule) * return StoreMatcher(matcher) } +// OnCallbackQueryPrefixGroup 前缀触发器组 +func OnCallbackQueryPrefixGroup(prefix []string, rules ...Rule) *Matcher { + return defaultEngine.OnCallbackQueryPrefixGroup(prefix, rules...) +} + // OnCallbackQueryPrefixGroup 前缀触发器组 func (e *Engine) OnCallbackQueryPrefixGroup(prefix []string, rules ...Rule) *Matcher { matcher := &Matcher{ diff --git a/example/echo/main.go b/example/echo/main.go index a0f4edf..a8c5424 100644 --- a/example/echo/main.go +++ b/example/echo/main.go @@ -3,7 +3,6 @@ package echo import ( ctrl "github.com/FloatTech/zbpctrl" rei "github.com/fumiama/ReiBot" - tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) func init() { @@ -16,6 +15,6 @@ func init() { if args == "" { return } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, args)) + _, _ = ctx.SendPlainMessage(false, args) }) } diff --git a/example/main.go b/example/main.go index 0efc372..add584d 100644 --- a/example/main.go +++ b/example/main.go @@ -10,7 +10,7 @@ import ( func main() { rei.OnMessageFullMatch("help").SetBlock(true). Handle(func(ctx *rei.Ctx) { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "echo string")) + _, _ = ctx.SendPlainMessage(false, "echo string") }) rei.Run(rei.Bot{ Token: "", diff --git a/manager.go b/manager.go index 37b3be3..282069b 100644 --- a/manager.go +++ b/manager.go @@ -3,6 +3,7 @@ package rei import ( "fmt" "os" + "sort" "sync/atomic" "unicode" @@ -81,3 +82,25 @@ func Delete(service string) { } } } + +// ForEachByPrio iterates through managers by their priority. +func ForEachByPrio(iterator func(i int, manager *ctrl.Control[*Ctx]) bool) { + for i, v := range cpmp2lstbyprio() { + if !iterator(i, v) { + return + } + } +} + +func cpmp2lstbyprio() []*ctrl.Control[*Ctx] { + m.RLock() + defer m.RUnlock() + ret := make([]*ctrl.Control[*Ctx], 0, len(m.M)) + for _, v := range m.M { + ret = append(ret, v) + } + sort.SliceStable(ret, func(i, j int) bool { + return enmap[ret[i].Service].prio < enmap[ret[j].Service].prio + }) + return ret +} diff --git a/rule.go b/rule.go index e38eb68..86eb747 100644 --- a/rule.go +++ b/rule.go @@ -4,12 +4,14 @@ import ( "fmt" "strconv" "strings" + "time" "unsafe" "github.com/FloatTech/floatbox/process" ctrl "github.com/FloatTech/zbpctrl" tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5" "github.com/wdvxdr1123/ZeroBot/extension" + "github.com/wdvxdr1123/ZeroBot/extension/rate" ) func newctrl(service string, o *ctrl.Options[*Ctx]) Rule { @@ -24,22 +26,66 @@ func Lookup(service string) (*ctrl.Control[*Ctx], bool) { return m.Lookup(service) } +// respLimiterManager 请求响应限速器管理 +// +// 每 1d 1次触发 +var respLimiterManager = rate.NewManager[int64](time.Hour*24, 1) + func init() { process.NewCustomOnce(&m).Do(func() { OnMessageCommandGroup([]string{ "响应", "response", "沉默", "silence", - }, UserOrGrpAdmin).SetBlock(true).secondPriority().Handle(func(ctx *Ctx) { + }, UserOrGrpAdmin).SetBlock(true).Limit(func(ctx *Ctx) *rate.Limiter { + return respLimiterManager.Load(ctx.Message.Chat.ID) + }).secondPriority().Handle(func(ctx *Ctx) { grp := ctx.Message.Chat.ID msg := "" switch ctx.State["command"] { case "响应", "response": - err := m.Response(grp) - if err == nil { - msg = ctx.Caller.Self.String() + "将开始在此工作啦~" - } else { - msg = "ERROR: " + err.Error() + if m.CanResponse(grp) { + msg = ctx.Caller.Self.String() + "已经在工作了哦~" + break } + if SuperUserPermission(ctx) { + err := m.Response(grp) + if err == nil { + msg = ctx.Caller.Self.String() + "将开始在此工作啦~" + } else { + msg = "ERROR: " + err.Error() + } + break + } + notify := &tgba.PhotoConfig{ + BaseFile: tgba.BaseFile{ + BaseChat: tgba.BaseChat{ + ReplyMarkup: tgba.NewInlineKeyboardMarkup( + tgba.NewInlineKeyboardRow( + tgba.NewInlineKeyboardButtonData( + "同意", + "respermit"+fmt.Sprintf("%016x", uint64(grp)), + ), + tgba.NewInlineKeyboardButtonData( + "拒绝", + "resrefuse"+fmt.Sprintf("%016x", uint64(grp)), + ), + ), + ), + }, + File: tgba.FileID(ctx.Message.Chat.Photo.BigFileID), + }, + Caption: "主人, @" + ctx.Message.From.String() + " 请求响应~\n*ChatType*: " + ctx.Message.Chat.Type + "\n*ChatUserName*: " + ctx.Message.Chat.UserName + "\n*ChatID*: " + strconv.FormatInt(ctx.Message.Chat.ID, 10) + "\n*ChatTitle*: " + ctx.Message.Chat.Title + "\n*ChatDescription*: " + ctx.Message.Chat.Description, + ParseMode: "Markdown", + } + for _, id := range ctx.Caller.b.SuperUsers { + notify.ChatID = id + _, _ = ctx.Caller.Send(notify) + } + msg = "已将响应请求发给主人了, 请耐心等待回应哦~" case "沉默", "silence": + if !m.CanResponse(grp) { + msg = ctx.Caller.Self.String() + "已经在休息了哦~" + break + } err := m.Silence(grp) if err == nil { msg = ctx.Caller.Self.String() + "将开始休息啦~" @@ -49,7 +95,52 @@ func init() { default: msg = "ERROR: bad command\"" + fmt.Sprint(ctx.State["command"]) + "\"" } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, msg)) + _, _ = ctx.SendPlainMessage(false, msg) + }) + + OnCallbackQueryRegex(`^respermit([0-9a-f]{16})$`, SuperUserPermission).SetBlock(true).secondPriority().Handle(func(ctx *Ctx) { + grp, err := strconv.ParseUint(ctx.State["regex_matched"].([]string)[1], 16, 64) + if err != nil { + _, _ = ctx.Caller.Send(tgba.NewCallbackWithAlert(ctx.Value.(*tgba.CallbackQuery).ID, "ERROR: "+err.Error())) + return + } + msg := "" + err = m.Response(int64(grp)) + if err == nil { + msg = ctx.Caller.Self.String() + "将开始在此工作啦~" + } else { + msg = "ERROR: " + err.Error() + } + _, err = ctx.Caller.Send(&tgba.MessageConfig{ + BaseChat: tgba.BaseChat{ + ChatID: int64(grp), + }, + Text: msg, + }) + if err != nil { + _, _ = ctx.Caller.Send(tgba.NewCallbackWithAlert(ctx.Value.(*tgba.CallbackQuery).ID, "ERROR: "+err.Error())) + return + } + _, _ = ctx.Caller.Send(tgba.NewCallbackWithAlert(ctx.Value.(*tgba.CallbackQuery).ID, "已发送")) + }) + + OnCallbackQueryRegex(`^resrefuse([0-9a-f]{16})$`, SuperUserPermission).SetBlock(true).secondPriority().Handle(func(ctx *Ctx) { + grp, err := strconv.ParseUint(ctx.State["regex_matched"].([]string)[1], 16, 64) + if err != nil { + _, _ = ctx.Caller.Send(tgba.NewCallbackWithAlert(ctx.Value.(*tgba.CallbackQuery).ID, "ERROR: "+err.Error())) + return + } + _, err = ctx.Caller.Send(&tgba.MessageConfig{ + BaseChat: tgba.BaseChat{ + ChatID: int64(grp), + }, + Text: "很遗憾, 因为各种原因, 您暂时未获使用权限呢", + }) + if err != nil { + _, _ = ctx.Caller.Send(tgba.NewCallbackWithAlert(ctx.Value.(*tgba.CallbackQuery).ID, "ERROR: "+err.Error())) + return + } + _, _ = ctx.Caller.Send(tgba.NewCallbackWithAlert(ctx.Value.(*tgba.CallbackQuery).ID, "已发送")) }) OnMessageCommandGroup([]string{ @@ -75,33 +166,36 @@ func init() { default: msg = "ERROR: bad command\"" + cmd + "\"" } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, msg)) + _, _ = ctx.SendPlainMessage(false, msg) }) OnMessageCommandGroup([]string{ "启用", "enable", "禁用", "disable", }, UserOrGrpAdmin).SetBlock(true).secondPriority().Handle(func(ctx *Ctx) { + grp := ctx.Message.Chat.ID + if !m.CanResponse(grp) { + return + } model := extension.CommandModel{} _ = ctx.Parse(&model) service, ok := Lookup(model.Args) if !ok { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "没有找到指定服务!")) + _, _ = ctx.SendPlainMessage(false, "没有找到指定服务!") return } - grp := ctx.Message.Chat.ID if strings.Contains(model.Command, "启用") || strings.Contains(model.Command, "enable") { service.Enable(grp) if service.Options.OnEnable != nil { service.Options.OnEnable(ctx) } else { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "已启用服务: "+model.Args)) + _, _ = ctx.SendPlainMessage(false, "已启用服务: ", model.Args) } } else { service.Disable(grp) if service.Options.OnDisable != nil { service.Options.OnDisable(ctx) } else { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "已禁用服务: "+model.Args)) + _, _ = ctx.SendPlainMessage(false, "已禁用服务: ", model.Args) } } }) @@ -113,45 +207,52 @@ func init() { _ = ctx.Parse(&model) service, ok := Lookup(model.Args) if !ok { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "没有找到指定服务!")) + _, _ = ctx.SendPlainMessage(false, "没有找到指定服务!") return } if strings.Contains(model.Command, "启用") || strings.Contains(model.Command, "enable") { service.Enable(0) - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "已全局启用服务: "+model.Args)) + _, _ = ctx.SendPlainMessage(false, "已全局启用服务: ", model.Args) } else { service.Disable(0) - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "已全局禁用服务: "+model.Args)) + _, _ = ctx.SendPlainMessage(false, "已全局禁用服务: ", model.Args) } }) OnMessageCommandGroup([]string{"还原", "reset"}, UserOrGrpAdmin).SetBlock(true).secondPriority().Handle(func(ctx *Ctx) { + grp := ctx.Message.Chat.ID + if !m.CanResponse(grp) { + return + } model := extension.CommandModel{} _ = ctx.Parse(&model) service, ok := Lookup(model.Args) if !ok { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "没有找到指定服务!")) + _, _ = ctx.SendPlainMessage(false, "没有找到指定服务!") return } - grp := ctx.Message.Chat.ID service.Reset(grp) - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "已还原服务的默认启用状态: "+model.Args)) + _, _ = ctx.SendPlainMessage(false, "已还原服务的默认启用状态: ", model.Args) }) OnMessageCommandGroup([]string{ "禁止", "ban", "允许", "permit", }, AdminPermission).SetBlock(true).secondPriority().Handle(func(ctx *Ctx) { + grp := ctx.Message.Chat.ID + if !m.CanResponse(grp) { + return + } model := extension.CommandModel{} _ = ctx.Parse(&model) args := strings.Split(model.Args, " ") if len(args) >= 2 { service, ok := Lookup(args[0]) if !ok { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "没有找到指定服务!")) + _, _ = ctx.SendPlainMessage(false, "没有找到指定服务!") return } grp := ctx.Message.Chat.ID - msg := "**" + args[0] + "报告**" + msg := "*" + args[0] + "报告*" issu := SuperUserPermission(ctx) if strings.Contains(model.Command, "允许") || strings.Contains(model.Command, "permit") { for _, usr := range args[1:] { @@ -190,10 +291,10 @@ func init() { } } } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, msg)) + _, _ = ctx.SendPlainMessage(false, msg) return } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "参数错误!")) + _, _ = ctx.SendPlainMessage(false, "参数错误!") }) OnMessageCommandGroup([]string{ @@ -205,10 +306,10 @@ func init() { if len(args) >= 2 { service, ok := Lookup(args[0]) if !ok { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "没有找到指定服务!")) + _, _ = ctx.SendPlainMessage(false, "没有找到指定服务!") return } - msg := "**" + args[0] + "全局报告**" + msg := "*" + args[0] + "全局报告*" if strings.Contains(model.Command, "允许") || strings.Contains(model.Command, "permit") { for _, usr := range args[1:] { uid, err := strconv.ParseInt(usr, 10, 64) @@ -226,10 +327,10 @@ func init() { } } } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, msg)) + _, _ = ctx.SendPlainMessage(false, msg) return } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "参数错误!")) + _, _ = ctx.SendPlainMessage(false, "参数错误!") }) OnMessageCommandGroup([]string{ @@ -239,7 +340,7 @@ func init() { _ = ctx.Parse(&model) args := strings.Split(model.Args, " ") if len(args) >= 1 { - msg := "**报告**" + msg := "*报告*" if strings.Contains(model.Command, "解") || strings.Contains(model.Command, "un") { for _, usr := range args { uid, err := strconv.ParseInt(usr, 10, 64) @@ -259,10 +360,10 @@ func init() { } } } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, msg)) + _, _ = ctx.SendPlainMessage(false, msg) return } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "参数错误!")) + _, _ = ctx.SendPlainMessage(false, "参数错误!") }) OnMessageCommandGroup([]string{ @@ -272,15 +373,15 @@ func init() { _ = ctx.Parse(&model) service, ok := Lookup(model.Args) if !ok { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "没有找到指定服务!")) + _, _ = ctx.SendPlainMessage(false, "没有找到指定服务!") return } err := service.Flip() if err != nil { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "ERROR: "+err.Error())) + _, _ = ctx.SendPlainMessage(false, "ERROR: ", err) return } - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "已改变全局默认启用状态: "+model.Args)) + _, _ = ctx.SendPlainMessage(false, "已改变全局默认启用状态: ", model.Args) }) OnMessageCommandGroup([]string{"用法", "usage"}, UserOrGrpAdmin).SetBlock(true).secondPriority(). @@ -289,47 +390,43 @@ func init() { _ = ctx.Parse(&model) service, ok := Lookup(model.Args) if !ok { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "没有找到指定服务!")) + _, _ = ctx.SendPlainMessage(false, "没有找到指定服务!") return } if service.Options.Help != "" { gid := ctx.Message.Chat.ID - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, service.EnableMarkIn(gid).String()+" "+service.String())) + _, _ = ctx.SendPlainMessage(false, service.EnableMarkIn(gid), " ", service) } else { - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, "该服务无帮助!")) + _, _ = ctx.SendPlainMessage(false, "该服务无帮助!") } }) OnMessageCommandGroup([]string{"服务列表", "service_list"}, UserOrGrpAdmin).SetBlock(true).secondPriority(). Handle(func(ctx *Ctx) { - i := 0 gid := ctx.Message.Chat.ID m.RLock() msg := make([]any, 1, len(m.M)*4+1) m.RUnlock() msg[0] = "--------服务列表--------\n发送\"/用法 name\"查看详情\n发送\"/响应\"启用会话" - m.ForEach(func(key string, manager *ctrl.Control[*Ctx]) bool { - i++ - msg = append(msg, "\n", i, ": ", manager.EnableMarkIn(gid), key) + ForEachByPrio(func(i int, service *ctrl.Control[*Ctx]) bool { + msg = append(msg, "\n", i+1, ": ", service.EnableMarkIn(gid), service.Service) return true }) - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, fmt.Sprint(msg...))) + _, _ = ctx.SendPlainMessage(false, msg...) }) OnMessageCommandGroup([]string{"服务详情", "service_detail"}, UserOrGrpAdmin).SetBlock(true).secondPriority(). Handle(func(ctx *Ctx) { - i := 0 gid := ctx.Message.Chat.ID m.RLock() msgs := make([]any, 1, len(m.M)*7+1) m.RUnlock() msgs[0] = "---服务详情---\n" - m.ForEach(func(key string, service *ctrl.Control[*Ctx]) bool { - i++ - msgs = append(msgs, i, ": ", service.EnableMarkIn(gid), key, "\n", service, "\n\n") + ForEachByPrio(func(i int, service *ctrl.Control[*Ctx]) bool { + msgs = append(msgs, i+1, ": ", service.EnableMarkIn(gid), service.Service, "\n", service, "\n\n") return true }) - _, _ = ctx.Caller.Send(tgba.NewMessage(ctx.Message.Chat.ID, fmt.Sprint(msgs...))) + _, _ = ctx.SendPlainMessage(false, msgs...) }) }) } diff --git a/rules.go b/rules.go index 019e937..939b33a 100644 --- a/rules.go +++ b/rules.go @@ -529,7 +529,7 @@ func MustProvidePhoto(needphohint, failhint string) Rule { select { case <-time.After(time.Second * 120): if failhint != "" { - _, _ = ctx.Caller.Send(tgba.NewMessage(msg.Chat.ID, failhint)) + _, _ = ctx.SendPlainMessage(true, failhint) } return false case newCtx := <-next: