161 lines
4.8 KiB
Go
161 lines
4.8 KiB
Go
package napcat
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
)
|
||
|
||
// Event 是收到的一条 OneBot 事件。按 PostType 取对应的子事件指针。
|
||
type Event struct {
|
||
Time int64 `json:"time"`
|
||
SelfID int64 `json:"self_id"`
|
||
PostType string `json:"post_type"`
|
||
Raw json.RawMessage `json:"-"`
|
||
|
||
Message *MessageEvent // post_type == "message" / "message_sent"
|
||
Notice *NoticeEvent // post_type == "notice"
|
||
Request *RequestEvent // post_type == "request"
|
||
Meta *MetaEvent // post_type == "meta_event"
|
||
}
|
||
|
||
type BaseEvent struct {
|
||
Time int64 `json:"time"`
|
||
SelfID int64 `json:"self_id"`
|
||
PostType string `json:"post_type"`
|
||
}
|
||
|
||
// MessageEvent 是私聊/群聊消息事件。bot 自己发出的消息以 message_sent 上报。
|
||
type MessageEvent struct {
|
||
BaseEvent
|
||
MessageType string `json:"message_type"` // private | group
|
||
SubType string `json:"sub_type"` // friend/group/normal/anonymous/notice
|
||
MessageID int64 `json:"message_id"`
|
||
UserID int64 `json:"user_id"`
|
||
GroupID int64 `json:"group_id"`
|
||
TargetID int64 `json:"target_id"` // 群临时会话目标
|
||
TempSource int64 `json:"temp_source"` // 群临时会话来源
|
||
Message json.RawMessage `json:"message"` // 段数组或 CQ 码字符串
|
||
RawMessage string `json:"raw_message"`
|
||
Font int64 `json:"font"`
|
||
Sender Sender `json:"sender"`
|
||
}
|
||
|
||
// NoticeEvent 是通知事件(撤回、入群、禁言、戳一戳等)。
|
||
// 未映射的字段收进 Extra,避免 NapCat 增加字段时丢数据。
|
||
type NoticeEvent struct {
|
||
BaseEvent
|
||
NoticeType string `json:"notice_type"`
|
||
SubType string `json:"sub_type"`
|
||
GroupID int64 `json:"group_id"`
|
||
UserID int64 `json:"user_id"`
|
||
OperatorID int64 `json:"operator_id"`
|
||
TargetID int64 `json:"target_id"`
|
||
MessageID int64 `json:"message_id"`
|
||
Duration int64 `json:"duration"` // 禁言时长(秒)
|
||
File *FileNotice `json:"file"`
|
||
HonorType string `json:"honor_type"`
|
||
CardNew string `json:"card_new"`
|
||
CardOld string `json:"card_old"`
|
||
|
||
Extra map[string]any `json:"-"`
|
||
}
|
||
|
||
func (n *NoticeEvent) UnmarshalJSON(data []byte) error {
|
||
type alias NoticeEvent
|
||
var a alias
|
||
if err := json.Unmarshal(data, &a); err != nil {
|
||
return err
|
||
}
|
||
*n = NoticeEvent(a)
|
||
|
||
var m map[string]any
|
||
if err := json.Unmarshal(data, &m); err == nil {
|
||
for k := range knownNoticeKeys {
|
||
delete(m, k)
|
||
}
|
||
if len(m) > 0 {
|
||
n.Extra = m
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
var knownNoticeKeys = map[string]struct{}{
|
||
"time": {}, "self_id": {}, "post_type": {}, "notice_type": {}, "sub_type": {},
|
||
"group_id": {}, "user_id": {}, "operator_id": {}, "target_id": {},
|
||
"message_id": {}, "duration": {}, "file": {}, "honor_type": {},
|
||
"card_new": {}, "card_old": {},
|
||
}
|
||
|
||
// FileNotice 是群文件上传/离线文件通知里的文件信息。
|
||
type FileNotice struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
Size int64 `json:"size"`
|
||
BusID int64 `json:"busid"`
|
||
}
|
||
|
||
// RequestEvent 是好友/群请求事件(加好友、加群、被邀请入群)。
|
||
type RequestEvent struct {
|
||
BaseEvent
|
||
RequestType string `json:"request_type"` // friend | group
|
||
SubType string `json:"sub_type"` // group 时为 add/invite
|
||
UserID int64 `json:"user_id"`
|
||
GroupID int64 `json:"group_id"`
|
||
Comment string `json:"comment"`
|
||
Flag string `json:"flag"`
|
||
}
|
||
|
||
// MetaEvent 是元事件(连接生命周期与心跳)。
|
||
type MetaEvent struct {
|
||
BaseEvent
|
||
MetaType string `json:"meta_event_type"` // lifecycle | heartbeat
|
||
SubType string `json:"sub_type"` // connect/enable/disable
|
||
HeartbeatInterval int64 `json:"interval"`
|
||
Status *Status `json:"status,omitempty"`
|
||
}
|
||
|
||
func decodeEvent(data []byte) (*Event, error) {
|
||
var probe struct {
|
||
PostType string `json:"post_type"`
|
||
}
|
||
if err := json.Unmarshal(data, &probe); err != nil {
|
||
return nil, err
|
||
}
|
||
if probe.PostType == "" {
|
||
return nil, fmt.Errorf("napcat: missing post_type: %s", truncate(data))
|
||
}
|
||
ev := &Event{Raw: append(json.RawMessage(nil), data...)}
|
||
var base BaseEvent
|
||
_ = json.Unmarshal(data, &base)
|
||
ev.Time, ev.SelfID, ev.PostType = base.Time, base.SelfID, probe.PostType
|
||
|
||
switch probe.PostType {
|
||
case "message", "message_sent":
|
||
var m MessageEvent
|
||
if err := json.Unmarshal(data, &m); err != nil {
|
||
return nil, err
|
||
}
|
||
ev.Message = &m
|
||
case "notice":
|
||
var n NoticeEvent
|
||
if err := json.Unmarshal(data, &n); err != nil {
|
||
return nil, err
|
||
}
|
||
ev.Notice = &n
|
||
case "request":
|
||
var r RequestEvent
|
||
if err := json.Unmarshal(data, &r); err != nil {
|
||
return nil, err
|
||
}
|
||
ev.Request = &r
|
||
case "meta_event":
|
||
var m MetaEvent
|
||
if err := json.Unmarshal(data, &m); err != nil {
|
||
return nil, err
|
||
}
|
||
ev.Meta = &m
|
||
}
|
||
return ev, nil
|
||
}
|