mirror of
https://github.com/fumiama/ReiBot.git
synced 2026-06-05 00:50:25 +08:00
161 lines
3.8 KiB
Go
161 lines
3.8 KiB
Go
package rei
|
||
|
||
import (
|
||
"fmt"
|
||
"reflect"
|
||
"sync"
|
||
|
||
tgba "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||
)
|
||
|
||
type Ctx struct {
|
||
Event
|
||
State
|
||
Caller *TelegramClient
|
||
Message *tgba.Message
|
||
ma *Matcher
|
||
IsToMe bool
|
||
}
|
||
|
||
// decoder 反射获取的数据
|
||
type decoder []dec
|
||
|
||
type dec struct {
|
||
index int
|
||
key string
|
||
}
|
||
|
||
// decoder 缓存
|
||
var decoderCache = sync.Map{}
|
||
|
||
// Parse 将 Ctx.State 映射到结构体
|
||
func (ctx *Ctx) Parse(model interface{}) (err error) {
|
||
var (
|
||
rv = reflect.ValueOf(model).Elem()
|
||
t = rv.Type()
|
||
modelDec decoder
|
||
)
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
err = fmt.Errorf("parse state error: %v", r)
|
||
}
|
||
}()
|
||
d, ok := decoderCache.Load(t)
|
||
if ok {
|
||
modelDec = d.(decoder)
|
||
} else {
|
||
modelDec = decoder{}
|
||
for i := 0; i < t.NumField(); i++ {
|
||
t1 := t.Field(i)
|
||
if key, ok := t1.Tag.Lookup("zero"); ok {
|
||
modelDec = append(modelDec, dec{
|
||
index: i,
|
||
key: key,
|
||
})
|
||
}
|
||
}
|
||
decoderCache.Store(t, modelDec)
|
||
}
|
||
for _, d := range modelDec { // decoder类型非小内存,无法被编译器优化为快速拷贝
|
||
rv.Field(d.index).Set(reflect.ValueOf(ctx.State[d.key]))
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// CheckSession 判断会话连续性
|
||
func (ctx *Ctx) CheckSession() Rule {
|
||
msg := ctx.Value.(*tgba.Message)
|
||
return func(ctx2 *Ctx) bool {
|
||
msg2, ok := ctx2.Value.(*tgba.Message)
|
||
if !ok || msg.From == nil || msg.Chat == nil || msg2.From == nil || msg2.Chat == nil { // 确保无空
|
||
return false
|
||
}
|
||
return msg.From.ID == msg2.From.ID && msg.Chat.ID == msg2.Chat.ID
|
||
}
|
||
}
|
||
|
||
// Send 发送消息到对方
|
||
//
|
||
// c.ChatID = ctx.Message.Chat.ID
|
||
// if replytosender {
|
||
// c.ReplyToMessageID = ctx.Message.MessageID
|
||
// }
|
||
func (ctx *Ctx) Send(replytosender bool, c tgba.Chattable) (tgba.Message, error) {
|
||
msg := reflect.ValueOf(c).Elem()
|
||
msg.FieldByName("ChatID").SetInt(ctx.Message.Chat.ID)
|
||
if replytosender {
|
||
msg.FieldByName("ReplyToMessageID").SetInt(int64(ctx.Message.MessageID))
|
||
}
|
||
return ctx.Caller.Send(c)
|
||
}
|
||
|
||
// SendPlainMessage 发送无 entities 文本消息到对方
|
||
func (ctx *Ctx) SendPlainMessage(replytosender bool, printable ...any) (tgba.Message, error) {
|
||
msg := tgba.NewMessage(ctx.Message.Chat.ID, fmt.Sprint(printable...))
|
||
if replytosender {
|
||
msg.ReplyToMessageID = ctx.Message.MessageID
|
||
}
|
||
return ctx.Caller.Send(&msg)
|
||
}
|
||
|
||
// SendMessage 发送富文本消息到对方
|
||
func (ctx *Ctx) SendMessage(replytosender bool, text string, entities ...tgba.MessageEntity) (tgba.Message, error) {
|
||
msg := &tgba.MessageConfig{
|
||
BaseChat: tgba.BaseChat{
|
||
ChatID: ctx.Message.Chat.ID,
|
||
},
|
||
Text: text,
|
||
Entities: entities,
|
||
}
|
||
if replytosender {
|
||
msg.ReplyToMessageID = ctx.Message.MessageID
|
||
}
|
||
return ctx.Caller.Send(msg)
|
||
}
|
||
|
||
// SendPhoto 发送图片消息到对方
|
||
func (ctx *Ctx) SendPhoto(file tgba.RequestFileData, replytosender bool, caption string, captionentities ...tgba.MessageEntity) (tgba.Message, error) {
|
||
msg := &tgba.PhotoConfig{
|
||
BaseFile: tgba.BaseFile{
|
||
BaseChat: tgba.BaseChat{
|
||
ChatID: ctx.Message.Chat.ID,
|
||
},
|
||
File: file,
|
||
},
|
||
Caption: caption,
|
||
CaptionEntities: captionentities,
|
||
}
|
||
if replytosender {
|
||
msg.ReplyToMessageID = ctx.Message.MessageID
|
||
}
|
||
return ctx.Caller.Send(msg)
|
||
}
|
||
|
||
// SendAudio 发送音频消息到对方
|
||
func (ctx *Ctx) SendAudio(file tgba.RequestFileData, replytosender bool, caption string, captionentities ...tgba.MessageEntity) (tgba.Message, error) {
|
||
msg := tgba.AudioConfig{
|
||
BaseFile: tgba.BaseFile{
|
||
BaseChat: tgba.BaseChat{
|
||
ChatID: ctx.Message.Chat.ID,
|
||
},
|
||
File: file,
|
||
},
|
||
Caption: caption,
|
||
CaptionEntities: captionentities,
|
||
}
|
||
if replytosender {
|
||
msg.ReplyToMessageID = ctx.Message.MessageID
|
||
}
|
||
return ctx.Caller.Send(&msg)
|
||
}
|
||
|
||
// Block 匹配成功后阻止后续触发
|
||
func (ctx *Ctx) Block() {
|
||
ctx.ma.SetBlock(true)
|
||
}
|
||
|
||
// Block 在 pre, rules, mid 阶段阻止后续触发
|
||
func (ctx *Ctx) Break() {
|
||
ctx.ma.Break = true
|
||
}
|