Files
snowluma/context.go

137 lines
4.0 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 snowluma
import (
"context"
"sync"
)
// Context 是交给处理函数的上下文:携带事件,并把 API 调用路由到
// 产生该事件的连接;HTTP 上报模式下 Reply/Approve 走快速操作。
type Context struct {
// API 内嵌全部类型化 API 方法,调用时路由到本事件的来源连接。
API
Bot *Client
Event *Event
quick *quickBox
segOnce sync.Once
segs []Segment
segErr error
}
// Call 在本事件来源的连接上执行任意 action(未收录 API 的兜底入口)。
func (c *Context) Call(ctx context.Context, action string, params any, out any) error {
return c.API.call.Call(ctx, action, params, out)
}
// Segments 返回消息事件的消息段数组(CQ 码字符串也会被解析),结果带缓存。
func (c *Context) Segments() []Segment {
c.segOnce.Do(func() {
if c.Event.Message != nil {
c.segs, c.segErr = DecodeMessage(c.Event.Message.Message)
}
})
if c.segErr != nil {
return nil
}
return c.segs
}
// PlainText 返回消息里所有 text 段拼接出的文本。
func (c *Context) PlainText() string { return SegmentsText(c.Segments()) }
// SelfID 返回产生本事件的机器人 QQ 号。
func (c *Context) SelfID() int64 { return c.Event.SelfID }
// IsGroup 判断是否群聊消息事件。
func (c *Context) IsGroup() bool {
return c.Event.Message != nil && c.Event.Message.MessageType == "group"
}
// IsPrivate 判断是否私聊消息事件。
func (c *Context) IsPrivate() bool {
return c.Event.Message != nil && c.Event.Message.MessageType == "private"
}
// IsSelfMessage 判断是否 bot 自己发出的消息(message_sent)。
func (c *Context) IsSelfMessage() bool { return c.Event.PostType == "message_sent" }
// HasAtMe 判断消息是否 @ 了机器人(不含 @全体)。
func (c *Context) HasAtMe() bool {
me := c.SelfID()
for _, s := range c.Segments() {
if s.Type == "at" && intOf(s.Data["qq"]) == me {
return true
}
}
return false
}
// Reply 回复当前消息:群聊发 send_group_msg,私聊发 send_private_msg。
// HTTP 上报模式下改为随响应返回快速操作 reply(此时 message_id 返回 0)。
func (c *Context) Reply(message ...Segment) (MessageID, error) {
ev := c.Event
if ev.Message == nil {
return 0, errReplyNotMessage
}
if c.quick != nil {
c.quick.set("reply", message)
return 0, nil
}
if ev.Message.MessageType == "group" {
return c.SendGroupMsg(nil, ev.Message.GroupID, message...)
}
return c.SendPrivateMsg(nil, ev.Message.UserID, message...)
}
// ReplyText 回复一段纯文本。
func (c *Context) ReplyText(text string) (MessageID, error) { return c.Reply(Text(text)) }
// Recall 撤回触发本事件的那条消息(需要 bot 有管理员权限/为私聊双方)。
func (c *Context) Recall() error {
if c.Event.Message == nil {
return errReplyNotMessage
}
return c.DeleteMsg(nil, c.Event.Message.MessageID)
}
// Approve 同意当前好友/群请求。
func (c *Context) Approve() error { return c.approveRequest(true, "") }
// Reject 拒绝当前好友/群请求,reason 为拒绝理由(好友请求则为验证备注)。
func (c *Context) Reject(reason string) error { return c.approveRequest(false, reason) }
func (c *Context) approveRequest(approve bool, text string) error {
ev := c.Event
if ev.Request == nil {
return errRequestOnly
}
if c.quick != nil {
c.quick.set("approve", approve)
if text != "" {
if ev.Request.RequestType == "friend" {
c.quick.set("remark", text)
} else {
c.quick.set("reason", text)
}
}
return nil
}
if ev.Request.RequestType == "friend" {
return c.SetFriendAddRequest(nil, ev.Request.Flag, approve, text)
}
return c.SetGroupAddRequest(nil, ev.Request.Flag, ev.Request.SubType, approve, text)
}
var (
errReplyNotMessage = &frameError{"reply is only available for message events"}
errRequestOnly = &frameError{"approve/reject is only available for request events"}
)
type frameError struct{ msg string }
func (e *frameError) Error() string { return "snowluma: " + e.msg }
// MessageID 是 OneBot 消息 ID。
type MessageID = int64