diff --git a/bot.go b/bot.go index daf97fe..7aea299 100644 --- a/bot.go +++ b/bot.go @@ -30,16 +30,16 @@ type Bot struct { Intents uint32 // Intents 欲接收的事件 Properties json.RawMessage // Properties 一些环境变量, 目前没用 - gateway string // gateway 获得的网关 - shard [2]byte // shard 分片 - seq uint32 // seq 最新的 s - handlers map[string]GeneralHandleType // handlers 方便调用的 handler - mu sync.Mutex // 写锁 - conn *websocket.Conn // conn 目前的 wss 连接 - heartbeat uint32 // heartbeat 心跳周期, 单位毫秒 - hbonce sync.Once // hbonce 保证仅执行一次 heartbeat + gateway string // gateway 获得的网关 + shard [2]byte // shard 分片 + seq uint32 // seq 最新的 s + handlers map[string]eventHandlerType // handlers 方便调用的 handler + mu sync.Mutex // 写锁 + conn *websocket.Conn // conn 目前的 wss 连接 + heartbeat uint32 // heartbeat 心跳周期, 单位毫秒 + hbonce sync.Once // hbonce 保证仅执行一次 heartbeat - ready EventReady // + ready EventReady // ready 连接成功后下发的 bot 基本信息 } // Init 初始化, 只需执行一次 @@ -49,7 +49,7 @@ func (b *Bot) Init(gateway string, shard [2]byte) *Bot { if b.Handler != nil { h := reflect.ValueOf(b.Handler).Elem() t := h.Type() - b.handlers = make(map[string]GeneralHandleType, h.NumField()*4) + b.handlers = make(map[string]eventHandlerType, h.NumField()*4) for i := 0; i < h.NumField(); i++ { f := h.Field(i) if f.IsZero() { @@ -58,7 +58,10 @@ func (b *Bot) Init(gateway string, shard [2]byte) *Bot { tp := t.Field(i).Name[2:] // skip On log.Infoln(getLogHeader(), "注册处理函数", tp) handler := f.Interface() - b.handlers[tp] = *(*GeneralHandleType)(unsafe.Add(unsafe.Pointer(&handler), unsafe.Sizeof(uintptr(0)))) + b.handlers[tp] = eventHandlerType{ + h: *(*generalHandleType)(unsafe.Add(unsafe.Pointer(&handler), unsafe.Sizeof(uintptr(0)))), + t: t.Field(i).Type.In(2).Elem(), + } } } return b @@ -257,6 +260,8 @@ func (bot *Bot) Listen() { switch payload.T { case "RESUMED": log.Infoln(getLogHeader(), bot.ready.User.Username, "的网关连接恢复完成") + default: + bot.processEvent(&payload) } case OpCodeHeartbeat: // Send/Receive log.Debugln(getLogHeader(), "收到服务端推送心跳, 间隔:", time.Since(lastheartbeat)) @@ -280,6 +285,8 @@ func (bot *Bot) Listen() { log.Debugln(getLogHeader(), "收到心跳返回, 间隔:", time.Since(lastheartbeat)) lastheartbeat = time.Now() case OpCodeHTTPCallbackACK: // Reply + default: + log.Warnln(getLogHeader(), "忽略未知事件, 序号:", payload.S, ", Op:", payload.Op, ", 类型:", payload.T, ", 数据:", BytesToString(payload.D)) } } } diff --git a/event.go b/event.go new file mode 100644 index 0000000..a62eb21 --- /dev/null +++ b/event.go @@ -0,0 +1,28 @@ +package nano + +import ( + "encoding/json" + "reflect" + + log "github.com/sirupsen/logrus" +) + +// processEvent 处理需要关注的业务事件 +func (bot *Bot) processEvent(payload *WebsocketPayload) { + tp := UnderlineToCamel(payload.T) + if bot.Handler != nil { + ev, ok := bot.handlers[tp] + if !ok { + return + } + log.Debugln(getLogHeader(), "使用 handlers 处理", tp, "事件") + x := reflect.New(ev.t) + err := json.Unmarshal(payload.D, x.Interface()) + if err != nil { + log.Warnln(getLogHeader(), "解析", tp, "事件时出现错误:", err) + return + } + go ev.h(payload.S, bot, x.UnsafePointer()) + return + } +} diff --git a/handler.go b/handler.go index 104e5eb..d7bf24c 100644 --- a/handler.go +++ b/handler.go @@ -1,9 +1,18 @@ package nano -import "unsafe" +import ( + "reflect" + "unsafe" +) -// GeneralHandleType 作为通用的 handler 函数调用约定使用 -type GeneralHandleType func(int, *Bot, unsafe.Pointer) +// generalHandleType 作为通用的 handler 函数调用约定使用 +type generalHandleType func(uint32, *Bot, unsafe.Pointer) + +// eventHandlerType 一个事件函数调用的必须信息 +type eventHandlerType struct { + h generalHandleType + t reflect.Type +} // Handler 事件订阅 // @@ -11,66 +20,66 @@ type GeneralHandleType func(int, *Bot, unsafe.Pointer) type Handler struct { // GUILDS (1 << 0) - OnGuildCreate func(s int, bot *Bot, d *Guild) - OnGuildUpdate func(s int, bot *Bot, d *Guild) - OnGuildDelete func(s int, bot *Bot, d *Guild) - OnChannelCreate func(s int, bot *Bot, d *Channel) - OnChannelUpdate func(s int, bot *Bot, d *Channel) - OnChannelDelete func(s int, bot *Bot, d *Channel) + OnGuildCreate func(s uint32, bot *Bot, d *Guild) + OnGuildUpdate func(s uint32, bot *Bot, d *Guild) + OnGuildDelete func(s uint32, bot *Bot, d *Guild) + OnChannelCreate func(s uint32, bot *Bot, d *Channel) + OnChannelUpdate func(s uint32, bot *Bot, d *Channel) + OnChannelDelete func(s uint32, bot *Bot, d *Channel) // GUILD_MEMBERS (1 << 1) - OnGuildMemberAdd func(s int, bot *Bot, d *Member) - OnGuildMemberUpdate func(s int, bot *Bot, d *Member) - OnGuildMemberRemove func(s int, bot *Bot, d *Member) + OnGuildMemberAdd func(s uint32, bot *Bot, d *Member) + OnGuildMemberUpdate func(s uint32, bot *Bot, d *Member) + OnGuildMemberRemove func(s uint32, bot *Bot, d *Member) // GUILD_MESSAGES (1 << 9) // 消息事件,仅 *私域* 机器人能够设置此 intents。 - OnMessageCreate func(s int, bot *Bot, d *Message) - OnMessageDelete func(s int, bot *Bot, d *Message) + OnMessageCreate func(s uint32, bot *Bot, d *Message) + OnMessageDelete func(s uint32, bot *Bot, d *MessageDelete) // GUILD_MESSAGE_REACTIONS (1 << 10) - OnMessageReactionAdd func(s int, bot *Bot, d *MessageReaction) - OnMessageReactionRemove func(s int, bot *Bot, d *MessageReaction) + OnMessageReactionAdd func(s uint32, bot *Bot, d *MessageReaction) + OnMessageReactionRemove func(s uint32, bot *Bot, d *MessageReaction) // DIRECT_MESSAGE (1 << 12) - OnDirectMessageCreate func(s int, bot *Bot, d *Message) - OnDirectMessageDelete func(s int, bot *Bot, d *Message) + OnDirectMessageCreate func(s uint32, bot *Bot, d *Message) + OnDirectMessageDelete func(s uint32, bot *Bot, d *MessageDelete) // OPEN_FORUMS_EVENT (1 << 18) // 论坛事件, 此为公域的论坛事件 - OnOpenForumThreadCreate func(s int, bot *Bot, d *Thread) - OnOpenForumThreadUpdate func(s int, bot *Bot, d *Thread) - OnOpenForumThreadDelete func(s int, bot *Bot, d *Thread) - OnOpenForumPostCreate func(s int, bot *Bot, d *Post) - OnOpenForumPostDelete func(s int, bot *Bot, d *Post) - OnOpenForumReplyCreate func(s int, bot *Bot, d *Reply) - OnOpenForumReplyDelete func(s int, bot *Bot, d *Reply) + OnOpenForumThreadCreate func(s uint32, bot *Bot, d *Thread) + OnOpenForumThreadUpdate func(s uint32, bot *Bot, d *Thread) + OnOpenForumThreadDelete func(s uint32, bot *Bot, d *Thread) + OnOpenForumPostCreate func(s uint32, bot *Bot, d *Post) + OnOpenForumPostDelete func(s uint32, bot *Bot, d *Post) + OnOpenForumReplyCreate func(s uint32, bot *Bot, d *Reply) + OnOpenForumReplyDelete func(s uint32, bot *Bot, d *Reply) // AUDIO_OR_LIVE_CHANNEL_MEMBER (1 << 19) // 音视频/直播子频道成员进出事件 - OnAudioOrLiveChannelMemberEnter func(s int, bot *Bot, d *AudioLiveChannelUsersChange) - OnAudioOrLiveChannelMemberExit func(s int, bot *Bot, d *AudioLiveChannelUsersChange) + OnAudioOrLiveChannelMemberEnter func(s uint32, bot *Bot, d *AudioLiveChannelUsersChange) + OnAudioOrLiveChannelMemberExit func(s uint32, bot *Bot, d *AudioLiveChannelUsersChange) // INTERACTION (1 << 26) 事件结构不明 // MESSAGE_AUDIT (1 << 27) - OnMessageAuditPass func(s int, bot *Bot, d *MessageAudited) - OnMessageAuditReject func(s int, bot *Bot, d *MessageAudited) + OnMessageAuditPass func(s uint32, bot *Bot, d *MessageAudited) + OnMessageAuditReject func(s uint32, bot *Bot, d *MessageAudited) // FORUMS_EVENT (1 << 28) // 论坛事件,仅 *私域* 机器人能够设置此 intents。 - OnForumThreadCreate func(s int, bot *Bot, d *Thread) - OnForumThreadUpdate func(s int, bot *Bot, d *Thread) - OnForumThreadDelete func(s int, bot *Bot, d *Thread) - OnForumPostCreate func(s int, bot *Bot, d *Post) - OnForumPostDelete func(s int, bot *Bot, d *Post) - OnForumReplyCreate func(s int, bot *Bot, d *Reply) - OnForumReplyDelete func(s int, bot *Bot, d *Reply) - OnForumPublishAuditResult func(s int, bot *Bot, d *AuditResult) + OnForumThreadCreate func(s uint32, bot *Bot, d *Thread) + OnForumThreadUpdate func(s uint32, bot *Bot, d *Thread) + OnForumThreadDelete func(s uint32, bot *Bot, d *Thread) + OnForumPostCreate func(s uint32, bot *Bot, d *Post) + OnForumPostDelete func(s uint32, bot *Bot, d *Post) + OnForumReplyCreate func(s uint32, bot *Bot, d *Reply) + OnForumReplyDelete func(s uint32, bot *Bot, d *Reply) + OnForumPublishAuditResult func(s uint32, bot *Bot, d *AuditResult) // AUDIO_ACTION (1 << 29) - OnAudioStart func(s int, bot *Bot, d *AudioAction) - OnAudioFinish func(s int, bot *Bot, d *AudioAction) - OnAudioOnMic func(s int, bot *Bot, d *AudioAction) - OnAudioOffMic func(s int, bot *Bot, d *AudioAction) + OnAudioStart func(s uint32, bot *Bot, d *AudioAction) + OnAudioFinish func(s uint32, bot *Bot, d *AudioAction) + OnAudioOnMic func(s uint32, bot *Bot, d *AudioAction) + OnAudioOffMic func(s uint32, bot *Bot, d *AudioAction) // PUBLIC_GUILD_MESSAGES (1 << 30) // 消息事件,此为公域的消息事件 - OnAtMessageCreate func(s int, bot *Bot, d *Message) - OnPublicMessageDelete func(s int, bot *Bot, d *Message) + OnAtMessageCreate func(s uint32, bot *Bot, d *Message) + OnPublicMessageDelete func(s uint32, bot *Bot, d *MessageDelete) } diff --git a/openapi_emoji.go b/openapi_emoji.go index 81a1b31..1ce98cf 100644 --- a/openapi_emoji.go +++ b/openapi_emoji.go @@ -10,6 +10,10 @@ type Emoji struct { Type uint32 `json:"type"` } +func (e *Emoji) String() string { + return "" +} + // MessageReaction https://bot.q.qq.com/wiki/develop/api/openapi/reaction/model.html#messagereaction type MessageReaction struct { UserID string `json:"user_id"` @@ -20,12 +24,12 @@ type MessageReaction struct { } // ReactionTargetType https://bot.q.qq.com/wiki/develop/api/openapi/reaction/model.html#reactiontargettype -type ReactionTargetType int +type ReactionTargetType string // ReactionTarget https://bot.q.qq.com/wiki/develop/api/openapi/reaction/model.html#reactiontarget type ReactionTarget struct { ID string `json:"id"` - Type ReactionTargetType `json:"type"` + Type ReactionTargetType `json:"type"` // 实际是 string 而非 int } // GiveMessageReaction 对消息 message_id 进行表情表态 diff --git a/openapi_message.go b/openapi_message.go index 1ae6bfd..0fa5407 100644 --- a/openapi_message.go +++ b/openapi_message.go @@ -56,7 +56,13 @@ type MessageEmbedField struct { // MessageAttachment https://bot.q.qq.com/wiki/develop/api/openapi/message/model.html#messageattachment type MessageAttachment struct { - URL string `json:"url"` + ContentType string `json:"content_type,omitempty"` + Filename string `json:"filename,omitempty"` + Height int `json:"height,omitempty"` + ID string `json:"id,omitempty"` + Size int `json:"size,omitempty"` + URL string `json:"url,omitempty"` + Width int `json:"width,omitempty"` } // MessageArk https://bot.q.qq.com/wiki/develop/api/openapi/message/model.html#messageark