mirror of
https://github.com/fumiama/ReiBot.git
synced 2026-06-05 17:10:25 +08:00
add plugin
This commit is contained in:
41
README.md
41
README.md
@@ -5,9 +5,42 @@ Lightweight Telegram bot framework
|
||||
|
||||
This framework is a simple wrapper for [go-telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api), aiming to make the event processing easier.
|
||||
|
||||
## Example
|
||||
## Quick Start
|
||||
> Here is a plugin-based example
|
||||
```go
|
||||
package main
|
||||
|
||||
See under `example` folder or below.
|
||||
import (
|
||||
rei "github.com/fumiama/ReiBot"
|
||||
tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rei.OnMessagePrefix("echo").SetBlock(true).SecondPriority().
|
||||
Handle(func(ctx *rei.Ctx) {
|
||||
args := ctx.State["args"].(string)
|
||||
if args == "" {
|
||||
return
|
||||
}
|
||||
msg := ctx.Value.(*tgba.Message)
|
||||
ctx.Caller.Send(tgba.NewMessage(msg.Chat.ID, args))
|
||||
})
|
||||
rei.Run(rei.Bot{
|
||||
Token: "",
|
||||
Buffer: 256,
|
||||
UpdateConfig: tgba.UpdateConfig{
|
||||
Offset: 0,
|
||||
Limit: 0,
|
||||
Timeout: 60,
|
||||
},
|
||||
Debug: true,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Event-Based
|
||||
|
||||
> If Handler in Bot is implemented, the plugin function will be disabled.
|
||||
|
||||

|
||||
|
||||
@@ -32,7 +65,7 @@ func main() {
|
||||
Timeout: 60,
|
||||
},
|
||||
Debug: true,
|
||||
Handler: rei.Handler{
|
||||
Handler: &rei.Handler{
|
||||
OnMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) {
|
||||
if len(msg.Text) <= len("测试") {
|
||||
return
|
||||
@@ -60,4 +93,4 @@ func main() {
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
2
bot.go
2
bot.go
@@ -17,7 +17,7 @@ type Bot struct {
|
||||
// Debug 控制调试信息的输出与否
|
||||
Debug bool `json:"debug"`
|
||||
// Handler 注册对各种事件的处理
|
||||
Handler Handler
|
||||
Handler *Handler
|
||||
// handlers 方便调用的 handler
|
||||
handlers map[string]GeneralHandleType
|
||||
}
|
||||
|
||||
24
client.go
24
client.go
@@ -18,18 +18,20 @@ type TelegramClient struct {
|
||||
// NewTelegramClient ...
|
||||
func NewTelegramClient(c *Bot) (tc TelegramClient) {
|
||||
tc.b = *c
|
||||
h := reflect.ValueOf(&tc.b.Handler).Elem()
|
||||
t := h.Type()
|
||||
tc.b.handlers = make(map[string]GeneralHandleType, 16)
|
||||
for i := 0; i < h.NumField(); i++ {
|
||||
f := h.Field(i)
|
||||
if f.IsZero() {
|
||||
continue
|
||||
if tc.b.Handler != nil {
|
||||
h := reflect.ValueOf(tc.b.Handler).Elem()
|
||||
t := h.Type()
|
||||
tc.b.handlers = make(map[string]GeneralHandleType, 16)
|
||||
for i := 0; i < h.NumField(); i++ {
|
||||
f := h.Field(i)
|
||||
if f.IsZero() {
|
||||
continue
|
||||
}
|
||||
tp := t.Field(i).Name[2:]
|
||||
log.Println("[INFO] register handler", tp)
|
||||
handler := f.Interface()
|
||||
tc.b.handlers[tp] = *(*GeneralHandleType)(unsafe.Add(unsafe.Pointer(&handler), unsafe.Sizeof(uintptr(0))))
|
||||
}
|
||||
tp := t.Field(i).Name[2:]
|
||||
log.Println("[INFO] register handler", tp)
|
||||
handler := f.Interface()
|
||||
tc.b.handlers[tp] = *(*GeneralHandleType)(unsafe.Add(unsafe.Pointer(&handler), unsafe.Sizeof(uintptr(0))))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
8
context.go
Normal file
8
context.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package rei
|
||||
|
||||
type Ctx struct {
|
||||
Event
|
||||
State
|
||||
Caller *TelegramClient
|
||||
ma *Matcher
|
||||
}
|
||||
176
engine.go
Normal file
176
engine.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package rei
|
||||
|
||||
// New 生成空引擎
|
||||
func NewEngine() *Engine {
|
||||
return &Engine{
|
||||
preHandler: []Rule{},
|
||||
midHandler: []Rule{},
|
||||
postHandler: []Process{},
|
||||
}
|
||||
}
|
||||
|
||||
var defaultEngine = NewEngine()
|
||||
|
||||
// Engine is the pre_handler, mid_handler, post_handler manager
|
||||
type Engine struct {
|
||||
preHandler []Rule
|
||||
midHandler []Rule
|
||||
postHandler []Process
|
||||
matchers []*Matcher
|
||||
}
|
||||
|
||||
// Delete 移除该 Engine 注册的所有 Matchers
|
||||
func (e *Engine) Delete() {
|
||||
for _, m := range e.matchers {
|
||||
m.Delete()
|
||||
}
|
||||
}
|
||||
|
||||
// UsePreHandler 向该 Engine 添加新 PreHandler(Rule),
|
||||
// 会在 Rule 判断前触发,如果 preHandler
|
||||
// 没有通过,则 Rule, Matcher 不会触发
|
||||
//
|
||||
// 可用于分群组管理插件等
|
||||
func (e *Engine) UsePreHandler(rules ...Rule) {
|
||||
e.preHandler = append(e.preHandler, rules...)
|
||||
}
|
||||
|
||||
// UseMidHandler 向该 Engine 添加新 MidHandler(Rule),
|
||||
// 会在 Rule 判断后, Matcher 触发前触发,如果 midHandler
|
||||
// 没有通过,则 Matcher 不会触发
|
||||
//
|
||||
// 可用于速率限制等
|
||||
func (e *Engine) UseMidHandler(rules ...Rule) {
|
||||
e.midHandler = append(e.midHandler, rules...)
|
||||
}
|
||||
|
||||
// UsePostHandler 向该 Engine 添加新 PostHandler(Rule),
|
||||
// 会在 Matcher 触发后触发,如果 PostHandler 返回 false,
|
||||
// 则后续的 post handler 不会触发
|
||||
//
|
||||
// 可用于速率限制等
|
||||
func (e *Engine) UsePostHandler(handler ...Process) {
|
||||
e.postHandler = append(e.postHandler, handler...)
|
||||
}
|
||||
|
||||
// On 添加新的指定消息类型的匹配器(默认Engine)
|
||||
func On(typ string, rules ...Rule) *Matcher { return defaultEngine.On(typ, rules...) }
|
||||
|
||||
// On 添加新的指定消息类型的匹配器
|
||||
func (e *Engine) On(typ string, rules ...Rule) *Matcher {
|
||||
matcher := &Matcher{
|
||||
Type: typ,
|
||||
Rules: rules,
|
||||
Engine: e,
|
||||
}
|
||||
e.matchers = append(e.matchers, matcher)
|
||||
return StoreMatcher(matcher)
|
||||
}
|
||||
|
||||
// OnMessage 消息触发器
|
||||
func (e *Engine) OnMessage(rules ...Rule) *Matcher { return e.On("Message", rules...) }
|
||||
|
||||
// OnMessage 消息触发器
|
||||
func OnMessage(rules ...Rule) *Matcher { return On("Message", rules...) }
|
||||
|
||||
// OnEditedMessage 修改消息触发器
|
||||
func (e *Engine) OnEditedMessage(rules ...Rule) *Matcher { return e.On("EditedMessage", rules...) }
|
||||
|
||||
// OnEditedMessage 修改消息触发器
|
||||
func OnEditedMessage(rules ...Rule) *Matcher { return On("EditedMessage", rules...) }
|
||||
|
||||
// OnChannelPost ...
|
||||
func (e *Engine) OnChannelPost(rules ...Rule) *Matcher { return e.On("ChannelPost", rules...) }
|
||||
|
||||
// OnChannelPost ...
|
||||
func OnChannelPost(rules ...Rule) *Matcher { return On("ChannelPost", rules...) }
|
||||
|
||||
// OnEditedChannelPost ...
|
||||
func (e *Engine) OnEditedChannelPost(rules ...Rule) *Matcher {
|
||||
return e.On("EditedChannelPost", rules...)
|
||||
}
|
||||
|
||||
// OnEditedChannelPost ...
|
||||
func OnEditedChannelPost(rules ...Rule) *Matcher {
|
||||
return On("EditedChannelPost", rules...)
|
||||
}
|
||||
|
||||
// OnInlineQuery ...
|
||||
func (e *Engine) OnInlineQuery(rules ...Rule) *Matcher { return e.On("InlineQuery", rules...) }
|
||||
|
||||
// OnInlineQuery ...
|
||||
func OnInlineQuery(rules ...Rule) *Matcher { return On("InlineQuery", rules...) }
|
||||
|
||||
// OnChosenInlineResult ...
|
||||
func (e *Engine) OnChosenInlineResult(rules ...Rule) *Matcher {
|
||||
return e.On("ChosenInlineResult", rules...)
|
||||
}
|
||||
|
||||
// OnChosenInlineResult ...
|
||||
func OnChosenInlineResult(rules ...Rule) *Matcher { return On("ChosenInlineResult", rules...) }
|
||||
|
||||
// OnCallbackQuery ...
|
||||
func (e *Engine) OnCallbackQuery(rules ...Rule) *Matcher { return e.On("CallbackQuery", rules...) }
|
||||
|
||||
// OnCallbackQuery ...
|
||||
func OnCallbackQuery(rules ...Rule) *Matcher { return On("CallbackQuery", rules...) }
|
||||
|
||||
// OnShippingQuery ...
|
||||
func (e *Engine) OnShippingQuery(rules ...Rule) *Matcher { return e.On("ShippingQuery", rules...) }
|
||||
|
||||
// OnShippingQuery ...
|
||||
func OnShippingQuery(rules ...Rule) *Matcher { return On("ShippingQuery", rules...) }
|
||||
|
||||
// OnPreCheckoutQuery ...
|
||||
func (e *Engine) OnPreCheckoutQuery(rules ...Rule) *Matcher {
|
||||
return e.On("PreCheckoutQuery", rules...)
|
||||
}
|
||||
|
||||
// OnPreCheckoutQuery ...
|
||||
func OnPreCheckoutQuery(rules ...Rule) *Matcher { return On("PreCheckoutQuery", rules...) }
|
||||
|
||||
// OnPoll ...
|
||||
func (e *Engine) OnPoll(rules ...Rule) *Matcher { return e.On("Poll", rules...) }
|
||||
|
||||
// OnPoll ...
|
||||
func OnPoll(rules ...Rule) *Matcher { return On("Poll", rules...) }
|
||||
|
||||
// OnPollAnswer ...
|
||||
func (e *Engine) OnPollAnswer(rules ...Rule) *Matcher { return e.On("PollAnswer", rules...) }
|
||||
|
||||
// OnPollAnswer ...
|
||||
func OnPollAnswer(rules ...Rule) *Matcher { return On("PollAnswer", rules...) }
|
||||
|
||||
// OnMyChatMember ...
|
||||
func (e *Engine) OnMyChatMember(rules ...Rule) *Matcher { return e.On("MyChatMember", rules...) }
|
||||
|
||||
// OnMyChatMember ...
|
||||
func OnMyChatMember(rules ...Rule) *Matcher { return On("MyChatMember", rules...) }
|
||||
|
||||
// OnChatMember ...
|
||||
func (e *Engine) OnChatMember(rules ...Rule) *Matcher { return e.On("ChatMember", rules...) }
|
||||
|
||||
// OnChatMember ...
|
||||
func OnChatMember(rules ...Rule) *Matcher { return On("ChatMember", rules...) }
|
||||
|
||||
// OnChatJoinRequest ...
|
||||
func (e *Engine) OnChatJoinRequest(rules ...Rule) *Matcher { return e.On("ChatJoinRequest", rules...) }
|
||||
|
||||
// OnChatJoinRequest ...
|
||||
func OnChatJoinRequest(rules ...Rule) *Matcher { return On("ChatJoinRequest", rules...) }
|
||||
|
||||
// OnPrefix 前缀触发器
|
||||
func OnMessagePrefix(prefix string, rules ...Rule) *Matcher {
|
||||
return defaultEngine.OnMessagePrefix(prefix, rules...)
|
||||
}
|
||||
|
||||
// OnPrefix 前缀触发器
|
||||
func (e *Engine) OnMessagePrefix(prefix string, rules ...Rule) *Matcher {
|
||||
matcher := &Matcher{
|
||||
Type: "Message",
|
||||
Rules: append([]Rule{PrefixRule(prefix)}, rules...),
|
||||
Engine: e,
|
||||
}
|
||||
e.matchers = append(e.matchers, matcher)
|
||||
return StoreMatcher(matcher)
|
||||
}
|
||||
80
event.go
80
event.go
@@ -14,7 +14,7 @@ type Event struct {
|
||||
// UpdateID is the update's unique identifier.
|
||||
UpdateID int
|
||||
// Value is the non-null field value in Update
|
||||
Value reflect.Value
|
||||
Value any
|
||||
}
|
||||
|
||||
func (tc *TelegramClient) processEvent(update tgba.Update) {
|
||||
@@ -26,6 +26,29 @@ func (tc *TelegramClient) processEvent(update tgba.Update) {
|
||||
continue
|
||||
}
|
||||
tp := t.Field(i).Name
|
||||
if tc.b.Handler == nil {
|
||||
matcherLock.RLock()
|
||||
n := len(matcherMap[tp])
|
||||
if n == 0 {
|
||||
matcherLock.RUnlock()
|
||||
continue
|
||||
}
|
||||
log.Println("[INFO] pass", tp, "event to plugins")
|
||||
matchers := make([]*Matcher, n)
|
||||
copy(matchers, matcherMap[tp])
|
||||
matcherLock.RUnlock()
|
||||
ctx := &Ctx{
|
||||
Event: Event{
|
||||
Type: tp,
|
||||
UpdateID: update.UpdateID,
|
||||
Value: f.Interface(),
|
||||
},
|
||||
State: State{},
|
||||
Caller: tc,
|
||||
}
|
||||
match(ctx, matchers)
|
||||
continue
|
||||
}
|
||||
h, ok := tc.b.handlers[tp]
|
||||
if !ok {
|
||||
continue
|
||||
@@ -34,3 +57,58 @@ func (tc *TelegramClient) processEvent(update tgba.Update) {
|
||||
go h(update.UpdateID, tc, f.UnsafePointer())
|
||||
}
|
||||
}
|
||||
|
||||
func match(ctx *Ctx, matchers []*Matcher) {
|
||||
loop:
|
||||
for _, matcher := range matchers {
|
||||
for k := range ctx.State { // Clear State
|
||||
delete(ctx.State, k)
|
||||
}
|
||||
matcherLock.RLock()
|
||||
m := matcher.copy()
|
||||
matcherLock.RUnlock()
|
||||
ctx.ma = m
|
||||
|
||||
// pre handler
|
||||
if m.Engine != nil {
|
||||
for _, handler := range m.Engine.preHandler {
|
||||
if !handler(ctx) { // 有 pre handler 未满足
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, rule := range m.Rules {
|
||||
if rule != nil && !rule(ctx) { // 有 Rule 的条件未满足
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
|
||||
// mid handler
|
||||
if m.Engine != nil {
|
||||
for _, handler := range m.Engine.midHandler {
|
||||
if !handler(ctx) { // 有 mid handler 未满足
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if m.Process != nil {
|
||||
m.Process(ctx) // 处理事件
|
||||
}
|
||||
if matcher.Temp { // 临时 Matcher 删除
|
||||
matcher.Delete()
|
||||
}
|
||||
|
||||
if m.Engine != nil {
|
||||
// post handler
|
||||
for _, handler := range m.Engine.postHandler {
|
||||
handler(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if m.Block { // 阻断后续
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
48
example/handler/main.go
Normal file
48
example/handler/main.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
rei "github.com/fumiama/ReiBot"
|
||||
tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rei.Run(rei.Bot{
|
||||
Token: "",
|
||||
Buffer: 256,
|
||||
UpdateConfig: tgba.UpdateConfig{
|
||||
Offset: 0,
|
||||
Limit: 0,
|
||||
Timeout: 60,
|
||||
},
|
||||
Debug: true,
|
||||
Handler: &rei.Handler{
|
||||
OnMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) {
|
||||
if len(msg.Text) <= len("测试") {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(msg.Text, "测试") {
|
||||
return
|
||||
}
|
||||
_, err := bot.Send(tgba.NewMessage(msg.Chat.ID, msg.Text[len("测试"):]))
|
||||
if err != nil {
|
||||
log.Println("[ERRO]", err)
|
||||
}
|
||||
},
|
||||
OnEditedMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) {
|
||||
if len(msg.Text) <= len("测试") {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(msg.Text, "测试") {
|
||||
return
|
||||
}
|
||||
_, err := bot.Send(tgba.NewMessage(msg.Chat.ID, "已编辑:"+msg.Text[len("测试"):]))
|
||||
if err != nil {
|
||||
log.Println("[ERRO]", err)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
rei "github.com/fumiama/ReiBot"
|
||||
tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rei.OnMessagePrefix("echo").SetBlock(true).SecondPriority().
|
||||
Handle(func(ctx *rei.Ctx) {
|
||||
args := ctx.State["args"].(string)
|
||||
if args == "" {
|
||||
return
|
||||
}
|
||||
msg := ctx.Value.(*tgba.Message)
|
||||
ctx.Caller.Send(tgba.NewMessage(msg.Chat.ID, args))
|
||||
})
|
||||
rei.Run(rei.Bot{
|
||||
Token: "",
|
||||
Buffer: 256,
|
||||
@@ -18,31 +24,5 @@ func main() {
|
||||
Timeout: 60,
|
||||
},
|
||||
Debug: true,
|
||||
Handler: rei.Handler{
|
||||
OnMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) {
|
||||
if len(msg.Text) <= len("测试") {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(msg.Text, "测试") {
|
||||
return
|
||||
}
|
||||
_, err := bot.Send(tgba.NewMessage(msg.Chat.ID, msg.Text[len("测试"):]))
|
||||
if err != nil {
|
||||
log.Println("[ERRO]", err)
|
||||
}
|
||||
},
|
||||
OnEditedMessage: func(updateid int, bot *rei.TelegramClient, msg *tgba.Message) {
|
||||
if len(msg.Text) <= len("测试") {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(msg.Text, "测试") {
|
||||
return
|
||||
}
|
||||
_, err := bot.Send(tgba.NewMessage(msg.Chat.ID, "已编辑:"+msg.Text[len("测试"):]))
|
||||
if err != nil {
|
||||
log.Println("[ERRO]", err)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
130
matcher.go
Normal file
130
matcher.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package rei
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
// Rule filter the event
|
||||
Rule func(ctx *Ctx) bool
|
||||
// Process 事件处理函数
|
||||
Process func(ctx *Ctx)
|
||||
)
|
||||
|
||||
// Matcher 是 ZeroBot 匹配和处理事件的最小单元
|
||||
type Matcher struct {
|
||||
// Temp 是否为临时Matcher,临时 Matcher 匹配一次后就会删除当前 Matcher
|
||||
Temp bool
|
||||
// Block 是否阻断后续 Matcher,为 true 时当前Matcher匹配成功后,后续Matcher不参与匹配
|
||||
Block bool
|
||||
// Priority 优先级,越小优先级越高
|
||||
Priority int
|
||||
// Event 当前匹配到的事件
|
||||
Event *Event
|
||||
// Type 匹配的事件类型
|
||||
Type string
|
||||
// Rules 匹配规则
|
||||
Rules []Rule
|
||||
// Process 处理事件的函数
|
||||
Process Process
|
||||
// Engine 注册 Matcher 的 Engine,Engine可为一系列 Matcher 添加通用 Rule 和 其他钩子
|
||||
Engine *Engine
|
||||
}
|
||||
|
||||
var (
|
||||
// 所有主匹配器列表
|
||||
matcherMap = make(map[string][]*Matcher, 0)
|
||||
// Matcher 修改读写锁
|
||||
matcherLock = sync.RWMutex{}
|
||||
)
|
||||
|
||||
// State store the context of a matcher.
|
||||
type State map[string]interface{}
|
||||
|
||||
func sortMatcher(typ string) {
|
||||
sort.Slice(matcherMap[typ], func(i, j int) bool { // 按优先级排序
|
||||
return matcherMap[typ][i].Priority < matcherMap[typ][j].Priority
|
||||
})
|
||||
}
|
||||
|
||||
// SetBlock 设置是否阻断后面的 Matcher 触发
|
||||
func (m *Matcher) SetBlock(block bool) *Matcher {
|
||||
m.Block = block
|
||||
return m
|
||||
}
|
||||
|
||||
// SetPriority 设置当前 Matcher 优先级
|
||||
func (m *Matcher) SetPriority(priority int) *Matcher {
|
||||
matcherLock.Lock()
|
||||
defer matcherLock.Unlock()
|
||||
m.Priority = priority
|
||||
sortMatcher(m.Type)
|
||||
return m
|
||||
}
|
||||
|
||||
// FirstPriority 设置当前 Matcher 优先级 - 0
|
||||
func (m *Matcher) FirstPriority() *Matcher {
|
||||
return m.SetPriority(0)
|
||||
}
|
||||
|
||||
// SecondPriority 设置当前 Matcher 优先级 - 1
|
||||
func (m *Matcher) SecondPriority() *Matcher {
|
||||
return m.SetPriority(1)
|
||||
}
|
||||
|
||||
// ThirdPriority 设置当前 Matcher 优先级 - 2
|
||||
func (m *Matcher) ThirdPriority() *Matcher {
|
||||
return m.SetPriority(2)
|
||||
}
|
||||
|
||||
// BindEngine bind the matcher to a engine
|
||||
func (m *Matcher) BindEngine(e *Engine) *Matcher {
|
||||
m.Engine = e
|
||||
return m
|
||||
}
|
||||
|
||||
// StoreMatcher store a matcher to matcher list.
|
||||
func StoreMatcher(m *Matcher) *Matcher {
|
||||
matcherLock.Lock()
|
||||
defer matcherLock.Unlock()
|
||||
matcherMap[m.Type] = append(matcherMap[m.Type], m)
|
||||
sortMatcher(m.Type)
|
||||
return m
|
||||
}
|
||||
|
||||
// StoreTempMatcher store a matcher only triggered once.
|
||||
func StoreTempMatcher(m *Matcher) *Matcher {
|
||||
m.Temp = true
|
||||
StoreMatcher(m)
|
||||
return m
|
||||
}
|
||||
|
||||
// Delete remove the matcher from list
|
||||
func (m *Matcher) Delete() {
|
||||
matcherLock.Lock()
|
||||
defer matcherLock.Unlock()
|
||||
for i, matcher := range matcherMap[m.Type] {
|
||||
if m == matcher {
|
||||
matcherMap[m.Type] = append(matcherMap[m.Type][:i], matcherMap[m.Type][i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Matcher) copy() *Matcher {
|
||||
return &Matcher{
|
||||
Type: m.Type,
|
||||
Rules: m.Rules,
|
||||
Block: m.Block,
|
||||
Priority: m.Priority,
|
||||
Process: m.Process,
|
||||
Temp: m.Temp,
|
||||
Engine: m.Engine,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle 直接处理事件
|
||||
func (m *Matcher) Handle(handler Process) *Matcher {
|
||||
m.Process = handler
|
||||
return m
|
||||
}
|
||||
28
rules.go
Normal file
28
rules.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package rei
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
// PrefixRule check if the 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user