1
0
mirror of https://github.com/fumiama/ReiBot.git synced 2026-06-05 00:50:25 +08:00
Files
ReiBot/rules.go
2022-10-05 00:08:49 +08:00

385 lines
9.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rei
import (
"reflect"
"regexp"
"strings"
"time"
tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/sirupsen/logrus"
)
// PrefixRule check if the text message has the prefix and trim the prefix
//
// 检查消息前缀
func PrefixRule(prefixes ...string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Text == "" { // 确保无空
return false
}
for _, prefix := range prefixes {
if strings.HasPrefix(msg.Text, prefix) {
ctx.State["prefix"] = prefix
arg := strings.TrimLeft(msg.Text[len(prefix):], " ")
ctx.State["args"] = arg
return true
}
}
return false
}
}
// SuffixRule check if the text message has the suffix and trim the suffix
//
// 检查消息后缀
func SuffixRule(suffixes ...string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Text == "" { // 确保无空
return false
}
for _, suffix := range suffixes {
if strings.HasSuffix(msg.Text, suffix) {
ctx.State["suffix"] = suffix
arg := strings.TrimRight(msg.Text[:len(msg.Text)-len(suffix)], " ")
ctx.State["args"] = arg
return true
}
}
return false
}
}
// CommandRule check if the message is a command and trim the command name
func CommandRule(commands ...string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Text == "" { // 确保无空
return false
}
msg.Text = strings.TrimSpace(msg.Text)
if msg.Text == "" { // 确保无空
return false
}
cmdMessage := ""
args := ""
switch {
case ctx.IsToMe && msg.IsCommand():
cmdMessage = msg.Command()
args = msg.CommandArguments()
case strings.HasPrefix(msg.Text, "/"):
cmdMessage, args, _ = strings.Cut(msg.Text, " ")
cmdMessage, _, _ = strings.Cut(cmdMessage, "@")
default:
return false
}
for _, command := range commands {
if strings.HasPrefix(cmdMessage, command) {
ctx.State["command"] = command
ctx.State["args"] = args
return true
}
}
return false
}
}
// RegexRule check if the message can be matched by the regex pattern
func RegexRule(regexPattern string) Rule {
regex := regexp.MustCompile(regexPattern)
return func(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *tgba.Message:
if msg.Text == "" { // 确保无空
logrus.Debugln("RegexRule: null message text")
return false
}
if matched := regex.FindStringSubmatch(msg.Text); matched != nil {
ctx.State["regex_matched"] = matched
logrus.Debugln("RegexRule: match message text", matched)
return true
}
logrus.Debugln("RegexRule: no match message")
return false
case *tgba.CallbackQuery:
if msg.Data == "" {
logrus.Debugln("RegexRule: null query data")
return false
}
if matched := regex.FindStringSubmatch(msg.Data); matched != nil {
ctx.State["regex_matched"] = matched
logrus.Debugln("RegexRule: match query data", matched)
return true
}
logrus.Debugln("RegexRule: no match query data")
return false
default:
logrus.Debugln("RegexRule: stub type")
return false
}
}
}
// ReplyRule check if the message is replying some message
func ReplyRule(messageID int) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.ReplyToMessage == nil { // 确保无空
return false
}
return messageID == msg.MessageID
}
}
// KeywordRule check if the message has a keyword or keywords
func KeywordRule(src ...string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Text == "" { // 确保无空
return false
}
for _, str := range src {
if strings.Contains(msg.Text, str) {
ctx.State["keyword"] = str
return true
}
}
return false
}
}
// FullMatchRule check if src has the same copy of the message
func FullMatchRule(src ...string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Text == "" { // 确保无空
return false
}
for _, str := range src {
if str == msg.Text {
ctx.State["matched"] = msg.Text
return true
}
}
return false
}
}
// ShellRule 定义shell-like规则
func ShellRule(cmd string, model interface{}) Rule {
cmdRule := CommandRule(cmd)
t := reflect.TypeOf(model)
return func(ctx *Ctx) bool {
if !cmdRule(ctx) {
return false
}
// bind flag to struct
args := ParseShell(ctx.State["args"].(string))
val := reflect.New(t)
fs := registerFlag(t, val)
err := fs.Parse(args)
if err != nil {
return false
}
ctx.State["args"] = fs.Args()
ctx.State["flag"] = val.Interface()
return true
}
}
// OnlyToMe only triggered in conditions of @bot or begin with the nicknames
func OnlyToMe(ctx *Ctx) bool {
return ctx.IsToMe
}
// CheckUser only triggered by specific person
func CheckUser(userId ...int64) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.From == nil { // 确保无空
return false
}
for _, uid := range userId {
if msg.From.ID == uid {
return true
}
}
return false
}
}
// CheckChat only triggered in specific chat
func CheckChat(chatId ...int64) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Chat == nil { // 确保无空
return false
}
for _, cid := range chatId {
if msg.Chat.ID == cid {
return true
}
}
return false
}
}
// OnlyPrivate requires that the ctx.Event is private message
func OnlyPrivate(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Chat == nil { // 确保无空
return false
}
return msg.Chat.Type == "private"
}
// OnlyGroup requires that the ctx.Event is group message
func OnlyGroup(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Chat == nil { // 确保无空
return false
}
return msg.Chat.Type == "group"
}
// OnlySuperGroup requires that the ctx.Event is supergroup message
func OnlySuperGroup(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Chat == nil { // 确保无空
return false
}
return msg.Chat.Type == "supergroup"
}
// OnlyPublic requires that the ctx.Event is group or supergroup message
func OnlyPublic(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Chat == nil { // 确保无空
return false
}
return msg.Chat.Type == "supergroup" || msg.Chat.Type == "group"
}
// OnlyChannel requires that the ctx.Event is channel message
func OnlyChannel(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.Chat == nil { // 确保无空
return false
}
return msg.Chat.Type == "channel"
}
// SuperUserPermission only triggered by the bot's owner
func SuperUserPermission(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.From == nil { // 确保无空
return false
}
for _, su := range ctx.Caller.b.SuperUsers {
if su == msg.From.ID {
return true
}
}
return false
}
// CreaterPermission only triggered by the group creater or higher permission
func CreaterPermission(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.From == nil || msg.Chat == nil { // 确保无空
return false
}
for _, su := range ctx.Caller.b.SuperUsers {
if su == msg.From.ID {
return true
}
}
m, err := ctx.Caller.GetChatMember(
tgba.GetChatMemberConfig{
ChatConfigWithUser: tgba.ChatConfigWithUser{
ChatID: msg.Chat.ID,
UserID: msg.From.ID,
},
},
)
if err != nil {
return false
}
return m.IsCreator()
}
// AdminPermission only triggered by the group admins or higher permission
func AdminPermission(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || msg.From == nil || msg.Chat == nil { // 确保无空
return false
}
for _, su := range ctx.Caller.b.SuperUsers {
if su == msg.From.ID {
return true
}
}
m, err := ctx.Caller.GetChatMember(
tgba.GetChatMemberConfig{
ChatConfigWithUser: tgba.ChatConfigWithUser{
ChatID: msg.Chat.ID,
UserID: msg.From.ID,
},
},
)
if err != nil {
return false
}
return m.IsCreator() || m.IsAdministrator()
}
// UserOrGrpAdmin 允许用户单独使用或群管使用
func UserOrGrpAdmin(ctx *Ctx) bool {
if OnlyPublic(ctx) {
return AdminPermission(ctx)
}
return OnlyToMe(ctx)
}
// IsPhoto 消息是图片返回 true
func IsPhoto(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if !ok || len(msg.Photo) == 0 { // 确保无空
return false
}
ctx.State["photos"] = msg.Photo
return true
}
// MustProvidePhoto 消息不存在图片阻塞120秒至有图片超时返回 false
func MustProvidePhoto(needphohint, failhint string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*tgba.Message)
if ok && len(msg.Photo) > 0 { // 确保无空
ctx.State["photos"] = msg.Photo
return true
}
// 没有图片就索取
if needphohint != "" {
_, err := ctx.Caller.Send(tgba.NewMessage(msg.Chat.ID, needphohint))
if err != nil {
return false
}
}
next := NewFutureEvent("Message", 999, false, ctx.CheckSession(), IsPhoto).Next()
select {
case <-time.After(time.Second * 120):
if failhint != "" {
_, _ = ctx.Caller.Send(tgba.NewMessage(msg.Chat.ID, failhint))
}
return false
case newCtx := <-next:
ctx.State["photos"] = newCtx.State["photos"]
ctx.Event = newCtx.Event
return true
}
}
}