napcat: NapCatQQ (OneBot 11) Go SDK, initial release

This commit is contained in:
2026-10-18 20:20:29 +08:00
commit 7f1738a987
14 changed files with 2879 additions and 0 deletions

136
context.go Normal file
View File

@ -0,0 +1,136 @@
package napcat
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 "napcat: " + e.msg }
// MessageID 是 OneBot 消息 ID。
type MessageID = int64