1
0
mirror of https://github.com/fumiama/NanoBot.git synced 2026-06-05 18:50:24 +08:00
Files
NanoBot/rules.go
2023-10-18 15:33:21 +09:00

462 lines
10 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 nano
import (
"reflect"
"regexp"
"strings"
"time"
)
// PrefixRule check if the text message has the prefix and trim the prefix
//
// 检查消息前缀
func PrefixRule(prefix string) Rule {
return PrefixGroupRule(prefix)
}
// PrefixGroupRule check if the text message has the prefix and trim the prefix
//
// 检查消息前缀
func PrefixGroupRule(prefixes ...string) Rule {
return func(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *Message:
if msg.Content == "" { // 确保无空
return false
}
for _, prefix := range prefixes {
if strings.HasPrefix(msg.Content, MessageEscape(prefix)) {
ctx.State["prefix"] = prefix
arg := strings.TrimLeft(msg.Content[len(prefix):], " ")
ctx.State["args"] = arg
return true
}
}
return false
default:
return false
}
}
}
// SuffixRule check if the text message has the suffix and trim the suffix
//
// 检查消息后缀
func SuffixRule(suffix string) Rule {
return SuffixGroupRule(suffix)
}
// SuffixGroupRule check if the text message has the suffix and trim the suffix
//
// 检查消息后缀
func SuffixGroupRule(suffixes ...string) Rule {
return func(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *Message:
if msg.Content == "" { // 确保无空
return false
}
for _, suffix := range suffixes {
if strings.HasSuffix(msg.Content, MessageEscape(suffix)) {
ctx.State["suffix"] = suffix
arg := strings.TrimRight(msg.Content[:len(msg.Content)-len(suffix)], " ")
ctx.State["args"] = arg
return true
}
}
return false
default:
return false
}
}
}
// CommandRule check if the message is a command and trim the command name
//
// this rule only supports Message
func CommandRule(command string) Rule {
return CommandGroupRule(command)
}
// CommandGroupRule check if the message is a command and trim the command name
//
// this rule only supports Message
func CommandGroupRule(commands ...string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*Message)
if !ok || msg.Content == "" { // 确保无空
return false
}
msg.Content = strings.TrimSpace(msg.Content)
if msg.Content == "" { // 确保无空
return false
}
cmdMessage := ""
args := ""
switch {
case strings.HasPrefix(msg.Content, "/"):
cmdMessage, args, _ = strings.Cut(msg.Content, " ")
cmdMessage, _, _ = strings.Cut(cmdMessage, "@")
cmdMessage = cmdMessage[1:]
default:
return false
}
for _, command := range commands {
if strings.HasPrefix(cmdMessage, MessageEscape(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 *Message:
if msg.Content == "" { // 确保无空
return false
}
if matched := regex.FindStringSubmatch(msg.Content); matched != nil {
ctx.State["regex_matched"] = matched
return true
}
return false
default:
return false
}
}
}
// ReplyRule check if the message is replying some message
//
// this rule only supports Message
func ReplyRule(messageID string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*Message)
if !ok || msg.MessageReference == nil { // 确保无空
return false
}
return messageID == msg.MessageReference.MessageID
}
}
func KeywordRule(src string) Rule {
return KeywordGroupRule(src)
}
// KeywordGroupRule check if the message has a keyword or keywords
func KeywordGroupRule(src ...string) Rule {
return func(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *Message:
if msg.Content == "" { // 确保无空
return false
}
for _, str := range src {
if strings.Contains(msg.Content, MessageEscape(str)) {
ctx.State["keyword"] = str
return true
}
}
return false
default:
return false
}
}
}
// FullMatchRule check if src has the same copy of the message
func FullMatchRule(src string) Rule {
return FullMatchGroupRule(src)
}
// FullMatchGroupRule check if src has the same copy of the message
func FullMatchGroupRule(src ...string) Rule {
return func(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *Message:
if msg.Content == "" { // 确保无空
return false
}
for _, str := range src {
if MessageEscape(str) == msg.Content {
ctx.State["matched"] = msg.Content
return true
}
}
return false
default:
return false
}
}
}
// ShellRule 定义shell-like规则
//
// this rule only supports Message
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
//
// this rule only supports Message
func OnlyToMe(ctx *Ctx) bool {
return ctx.IsToMe
}
// CheckUser only triggered by specific person
func CheckUser(userID ...string) Rule {
return func(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *Message:
if msg.Author == nil { // 确保无空
return false
}
for _, uid := range userID {
if msg.Author.ID == uid {
return true
}
}
return false
default:
return false
}
}
}
// CheckChannel only triggered in specific channel
func CheckChannel(channelID ...string) Rule {
return func(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *Message:
if msg.ChannelID == "" { // 确保无空
return false
}
for _, cid := range channelID {
if msg.ChannelID == cid {
return true
}
}
return false
default:
return false
}
}
}
// CheckGuild only triggered in specific guild
func CheckGuild(guildID ...string) Rule {
return func(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *Message:
if msg.GuildID == "" { // 确保无空
return false
}
for _, gid := range guildID {
if msg.GuildID == gid {
return true
}
}
return false
default:
return false
}
}
}
// OnlyDirect requires that the ctx.Event is direct message
func OnlyDirect(ctx *Ctx) bool {
if ctx.Message != nil {
return ctx.Message.SrcGuildID != ""
}
if ctx.Type != "" {
return strings.HasPrefix(ctx.Type, "Direct")
}
return false
}
// OnlyChannel requires that the ctx.Event is channel message
func OnlyChannel(ctx *Ctx) bool {
return !OnlyPrivate(ctx)
}
// OnlyPublic requires that the ctx.Event is public message
func OnlyPublic(ctx *Ctx) bool {
if ctx.Message != nil && ctx.Message.SrcGuildID != "" {
return false
}
if ctx.Type != "" {
return strings.HasPrefix(ctx.Type, "At") || strings.HasPrefix(ctx.Type, "Public")
}
return false
}
// OnlyPrivate requires that the ctx.Event is not public message
func OnlyPrivate(ctx *Ctx) bool {
return !OnlyPublic(ctx)
}
// SuperUserPermission only triggered by the bot's owner
func SuperUserPermission(ctx *Ctx) bool {
switch msg := ctx.Value.(type) {
case *Message:
if msg.Author == nil { // 确保无空
return false
}
for _, su := range ctx.caller.SuperUsers {
if su == msg.Author.ID {
return true
}
}
return false
default:
return false
}
}
// CreaterPermission only triggered by the creater or higher permission
func CreaterPermission(ctx *Ctx) bool {
if SuperUserPermission(ctx) {
return true
}
switch msg := ctx.Value.(type) {
case *Message:
if msg.Author == nil || msg.Member == nil { // 确保无空
return false
}
for _, role := range msg.Member.Roles {
if role == RoleIDCreater {
return true
}
}
return false
default:
return false
}
}
// AdminPermission only triggered by the admins or higher permission
func AdminPermission(ctx *Ctx) bool {
if SuperUserPermission(ctx) {
return true
}
switch msg := ctx.Value.(type) {
case *Message:
if msg.Author == nil || msg.Member == nil { // 确保无空
return false
}
for _, role := range msg.Member.Roles {
if role == RoleIDCreater || role == RoleIDAdmin {
return true
}
}
return false
default:
return false
}
}
// ChannelAdminPermission only triggered by the channel admins or higher permission
func ChannelAdminPermission(ctx *Ctx) bool {
if SuperUserPermission(ctx) {
return true
}
switch msg := ctx.Value.(type) {
case *Message:
if msg.Author == nil || msg.Member == nil { // 确保无空
return false
}
for _, role := range msg.Member.Roles {
if role == RoleIDCreater || role == RoleIDAdmin || role == RoleIDChannelAdmin {
return true
}
}
return false
default:
return false
}
}
// UserOrGrpAdmin 允许用户单独使用或群管使用
func UserOrGrpAdmin(ctx *Ctx) bool {
if OnlyPublic(ctx) {
return AdminPermission(ctx)
}
return OnlyToMe(ctx)
}
// UserOrChannelAdmin 允许用户单独使用或频道管理使用
func UserOrChannelAdmin(ctx *Ctx) bool {
if OnlyPublic(ctx) {
return ChannelAdminPermission(ctx)
}
return OnlyToMe(ctx)
}
// HasAttachments 消息包含 Attachments (典型: 图片) 返回 true
func HasAttachments(ctx *Ctx) bool {
msg, ok := ctx.Value.(*Message)
if !ok || len(msg.Attachments) == 0 { // 确保无空
return false
}
ctx.State["attachments"] = msg.Attachments
return true
}
// MustProvidePhoto 消息不存在图片阻塞120秒至有图片超时返回 false
func MustProvidePhoto(onmessage string, needphohint, failhint string) Rule {
return func(ctx *Ctx) bool {
msg, ok := ctx.Value.(*Message)
if ok && len(msg.Attachments) > 0 { // 确保无空
ctx.State["attachments"] = msg.Attachments
return true
}
// 没有图片就索取
if needphohint != "" {
_, err := ctx.PostMessageToChannel(msg.ChannelID, &MessagePost{
Content: needphohint,
MessageReference: &MessageReference{MessageID: msg.ID},
ReplyMessageID: msg.ID,
})
if err != nil {
return false
}
}
next := NewFutureEvent(onmessage, 999, false, ctx.CheckSession(), HasAttachments).Next()
select {
case <-time.After(time.Second * 120):
if failhint != "" {
_, _ = ctx.SendPlainMessage(true, failhint)
}
return false
case newCtx := <-next:
ctx.State["attachments"] = newCtx.State["attachments"]
ctx.Event = newCtx.Event
return true
}
}
}