refactor: modernize codebase for Go 1.26 and fix adapter issues

- Upgrade Go version from 1.24 to 1.26.1 with updated dependencies
- Replace interface{} with any type throughout codebase
- Add message deduplication in OneBot11 adapter to prevent duplicate event processing
- URL-encode access token in WebSocket connections to handle special characters
- Remove duplicate bot startup hooks in DI providers (now handled by botManager.StartAll)
- Use slices.Clone and errgroup.Go patterns for cleaner concurrent code
- Apply omitzero JSON tags for optional fields (Go 1.24+ feature)
This commit is contained in:
lafay
2026-03-18 01:22:49 +08:00
parent f3a72264af
commit f3220a2381
32 changed files with 2262 additions and 296 deletions

View File

@@ -82,16 +82,16 @@ func ConvertAction(action protocol.Action) string {
// SendPrivateMessageAction 发送私聊消息动作
type SendPrivateMessageAction struct {
UserID int64 `json:"user_id"`
Message interface{} `json:"message"`
AutoEscape bool `json:"auto_escape,omitempty"`
UserID int64 `json:"user_id"`
Message any `json:"message"`
AutoEscape bool `json:"auto_escape,omitempty"`
}
// SendGroupMessageAction 发送群消息动作
type SendGroupMessageAction struct {
GroupID int64 `json:"group_id"`
Message interface{} `json:"message"`
AutoEscape bool `json:"auto_escape,omitempty"`
GroupID int64 `json:"group_id"`
Message any `json:"message"`
AutoEscape bool `json:"auto_escape,omitempty"`
}
// DeleteMessageAction 撤回消息动作
@@ -224,12 +224,12 @@ type SetRestartAction struct {
// ActionResponse API响应
type ActionResponse struct {
Status string `json:"status"`
RetCode int `json:"retcode"`
Data map[string]interface{} `json:"data,omitempty"`
Echo string `json:"echo,omitempty"`
Message string `json:"message,omitempty"`
Wording string `json:"wording,omitempty"`
Status string `json:"status"`
RetCode int `json:"retcode"`
Data map[string]any `json:"data,omitempty"`
Echo string `json:"echo,omitempty"`
Message string `json:"message,omitempty"`
Wording string `json:"wording,omitempty"`
}
// 响应状态码常量
@@ -245,7 +245,7 @@ const (
)
// BuildActionRequest 构建动作请求
func BuildActionRequest(action string, params map[string]interface{}, echo string) *OB11Action {
func BuildActionRequest(action string, params map[string]any, echo string) *OB11Action {
return &OB11Action{
Action: action,
Params: params,
@@ -254,8 +254,8 @@ func BuildActionRequest(action string, params map[string]interface{}, echo strin
}
// BuildSendPrivateMsg 构建发送私聊消息请求
func BuildSendPrivateMsg(userID int64, message interface{}, autoEscape bool) map[string]interface{} {
return map[string]interface{}{
func BuildSendPrivateMsg(userID int64, message any, autoEscape bool) map[string]any {
return map[string]any{
"user_id": userID,
"message": message,
"auto_escape": autoEscape,
@@ -263,8 +263,8 @@ func BuildSendPrivateMsg(userID int64, message interface{}, autoEscape bool) map
}
// BuildSendGroupMsg 构建发送群消息请求
func BuildSendGroupMsg(groupID int64, message interface{}, autoEscape bool) map[string]interface{} {
return map[string]interface{}{
func BuildSendGroupMsg(groupID int64, message any, autoEscape bool) map[string]any {
return map[string]any{
"group_id": groupID,
"message": message,
"auto_escape": autoEscape,
@@ -272,15 +272,15 @@ func BuildSendGroupMsg(groupID int64, message interface{}, autoEscape bool) map[
}
// BuildDeleteMsg 构建撤回消息请求
func BuildDeleteMsg(messageID int32) map[string]interface{} {
return map[string]interface{}{
func BuildDeleteMsg(messageID int32) map[string]any {
return map[string]any{
"message_id": messageID,
}
}
// BuildSetGroupBan 构建群组禁言请求
func BuildSetGroupBan(groupID, userID int64, duration int64) map[string]interface{} {
return map[string]interface{}{
func BuildSetGroupBan(groupID, userID int64, duration int64) map[string]any {
return map[string]any{
"group_id": groupID,
"user_id": userID,
"duration": duration,
@@ -288,8 +288,8 @@ func BuildSetGroupBan(groupID, userID int64, duration int64) map[string]interfac
}
// BuildSetGroupKick 构建群组踢人请求
func BuildSetGroupKick(groupID, userID int64, rejectAddRequest bool) map[string]interface{} {
return map[string]interface{}{
func BuildSetGroupKick(groupID, userID int64, rejectAddRequest bool) map[string]any {
return map[string]any{
"group_id": groupID,
"user_id": userID,
"reject_add_request": rejectAddRequest,
@@ -297,8 +297,8 @@ func BuildSetGroupKick(groupID, userID int64, rejectAddRequest bool) map[string]
}
// BuildSetGroupCard 构建设置群名片请求
func BuildSetGroupCard(groupID, userID int64, card string) map[string]interface{} {
return map[string]interface{}{
func BuildSetGroupCard(groupID, userID int64, card string) map[string]any {
return map[string]any{
"group_id": groupID,
"user_id": userID,
"card": card,

View File

@@ -3,6 +3,7 @@ package onebot11
import (
"context"
"fmt"
"net/url"
"sync"
"time"
@@ -28,6 +29,10 @@ type Adapter struct {
wsConnection *net.WebSocketConnection
ctx context.Context
cancel context.CancelFunc
// 消息去重
processedMessages map[int64]time.Time
messageMu sync.RWMutex
}
// Config OneBot11配置
@@ -65,16 +70,20 @@ func NewAdapter(config *Config, logger *zap.Logger, wsManager *net.WebSocketMana
}
adapter := &Adapter{
config: config,
logger: logger.Named("onebot11"),
wsManager: wsManager,
wsWaiter: NewWSResponseWaiter(timeout, logger),
eventBus: eventBus,
selfID: config.SelfID,
ctx: ctx,
cancel: cancel,
config: config,
logger: logger.Named("onebot11"),
wsManager: wsManager,
wsWaiter: NewWSResponseWaiter(timeout, logger),
eventBus: eventBus,
selfID: config.SelfID,
ctx: ctx,
cancel: cancel,
processedMessages: make(map[int64]time.Time),
}
// 启动定期清理过期消息的 goroutine
go adapter.cleanupProcessedMessages()
// 如果使用HTTP连接初始化HTTP客户端
if config.ConnectionType == "http" && config.HTTPUrl != "" {
adapter.httpClient = NewHTTPClient(config.HTTPUrl, config.AccessToken, timeout, logger)
@@ -83,6 +92,43 @@ func NewAdapter(config *Config, logger *zap.Logger, wsManager *net.WebSocketMana
return adapter
}
// cleanupProcessedMessages 定期清理过期的已处理消息记录
func (a *Adapter) cleanupProcessedMessages() {
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
for {
select {
case <-a.ctx.Done():
return
case <-ticker.C:
a.messageMu.Lock()
now := time.Now()
for msgID, processedAt := range a.processedMessages {
if now.Sub(processedAt) > 10*time.Minute {
delete(a.processedMessages, msgID)
}
}
a.messageMu.Unlock()
}
}
}
// isMessageProcessed 检查消息是否已处理
func (a *Adapter) isMessageProcessed(messageID int64) bool {
a.messageMu.RLock()
_, exists := a.processedMessages[messageID]
a.messageMu.RUnlock()
return exists
}
// markMessageProcessed 标记消息为已处理
func (a *Adapter) markMessageProcessed(messageID int64) {
a.messageMu.Lock()
a.processedMessages[messageID] = time.Now()
a.messageMu.Unlock()
}
// Name 获取协议名称
func (a *Adapter) Name() string {
return "OneBot"
@@ -174,7 +220,7 @@ func (a *Adapter) GetSelfID() string {
}
// SendAction 发送动作
func (a *Adapter) SendAction(ctx context.Context, action protocol.Action) (map[string]interface{}, error) {
func (a *Adapter) SendAction(ctx context.Context, action protocol.Action) (map[string]any, error) {
// 序列化为OneBot11格式
data, err := a.SerializeAction(action)
if err != nil {
@@ -228,7 +274,7 @@ func (a *Adapter) SerializeAction(action protocol.Action) ([]byte, error) {
}
// 复制参数并转换消息链
params := make(map[string]interface{})
params := make(map[string]any)
for k, v := range action.GetParams() {
// 检查是否是消息链
if k == "message" {
@@ -259,10 +305,10 @@ func (a *Adapter) connectWebSocket(ctx context.Context) error {
zap.String("url", a.config.WSUrl),
zap.Bool("has_token", a.config.AccessToken != ""))
// 添加访问令牌到URL
// 添加访问令牌到URL需要对token进行URL编码以处理特殊字符
wsURL := a.config.WSUrl
if a.config.AccessToken != "" {
wsURL += "?access_token=" + a.config.AccessToken
wsURL += "?access_token=" + url.QueryEscape(a.config.AccessToken)
a.logger.Debug("Added access token to WebSocket URL")
}
@@ -342,7 +388,7 @@ func (a *Adapter) connectHTTPPost(ctx context.Context) error {
}
// sendActionWebSocket 通过WebSocket发送动作
func (a *Adapter) sendActionWebSocket(data []byte) (map[string]interface{}, error) {
func (a *Adapter) sendActionWebSocket(data []byte) (map[string]any, error) {
if a.wsConnection == nil {
return nil, fmt.Errorf("websocket connection not established")
}
@@ -383,7 +429,7 @@ func (a *Adapter) sendActionWebSocket(data []byte) (map[string]interface{}, erro
}
// sendActionHTTP 通过HTTP发送动作
func (a *Adapter) sendActionHTTP(data []byte) (map[string]interface{}, error) {
func (a *Adapter) sendActionHTTP(data []byte) (map[string]any, error) {
if a.httpClient == nil {
return nil, fmt.Errorf("http client not initialized")
}
@@ -439,7 +485,7 @@ func (a *Adapter) handleWebSocketMessages() {
zap.String("preview", string(message[:min(len(message), 200)])))
// 尝试解析为响应(先检查是否有 echo 字段)
var tempMap map[string]interface{}
var tempMap map[string]any
if err := sonic.Unmarshal(message, &tempMap); err == nil {
if echo, ok := tempMap["echo"].(string); ok && echo != "" {
// 有 echo 字段说明是API响应
@@ -478,6 +524,24 @@ func (a *Adapter) handleWebSocketMessages() {
continue
}
// 消息去重检查(基于 message_id
data := event.GetData()
// message_id 可能是 int32 或 int64
var messageID int64
if mid, ok := data["message_id"].(int32); ok && mid > 0 {
messageID = int64(mid)
} else if mid, ok := data["message_id"].(int64); ok && mid > 0 {
messageID = mid
}
if messageID > 0 {
if a.isMessageProcessed(messageID) {
a.logger.Warn("Duplicate message detected, skipping",
zap.Int64("message_id", messageID))
continue
}
a.markMessageProcessed(messageID)
}
// 发布事件到事件总线
a.logger.Info("Publishing event to event bus",
zap.String("event_type", string(event.GetType())),

View File

@@ -41,9 +41,9 @@ func NewHTTPClient(baseURL, accessToken string, timeout time.Duration, logger *z
}
// Call 调用API
func (c *HTTPClient) Call(ctx context.Context, action string, params map[string]interface{}) (*OB11Response, error) {
func (c *HTTPClient) Call(ctx context.Context, action string, params map[string]any) (*OB11Response, error) {
// 构建请求数据
reqData := map[string]interface{}{
reqData := map[string]any{
"action": action,
"params": params,
}

View File

@@ -14,7 +14,7 @@ func (a *Adapter) convertToEvent(raw *RawEvent) (protocol.Event, error) {
baseEvent := &protocol.BaseEvent{
Timestamp: raw.Time,
SelfID: strconv.FormatInt(raw.SelfID, 10),
Data: make(map[string]interface{}),
Data: make(map[string]any),
}
switch raw.PostType {
@@ -49,7 +49,7 @@ func (a *Adapter) convertMessageEvent(raw *RawEvent, base *protocol.BaseEvent) (
}
if raw.Sender != nil {
senderData := map[string]interface{}{
senderData := map[string]any{
"user_id": raw.Sender.UserID,
"nickname": raw.Sender.Nickname,
}
@@ -69,7 +69,7 @@ func (a *Adapter) convertMessageEvent(raw *RawEvent, base *protocol.BaseEvent) (
}
if raw.Anonymous != nil {
base.Data["anonymous"] = map[string]interface{}{
base.Data["anonymous"] = map[string]any{
"id": raw.Anonymous.ID,
"name": raw.Anonymous.Name,
"flag": raw.Anonymous.Flag,
@@ -111,7 +111,7 @@ func (a *Adapter) convertNoticeEvent(raw *RawEvent, base *protocol.BaseEvent) (p
case NoticeTypeGroupUpload:
// 文件上传信息
if raw.File != nil {
base.Data["file"] = map[string]interface{}{
base.Data["file"] = map[string]any{
"id": raw.File.ID,
"name": raw.File.Name,
"size": raw.File.Size,
@@ -156,12 +156,12 @@ func (a *Adapter) convertMetaEvent(raw *RawEvent, base *protocol.BaseEvent) (pro
base.DetailType = raw.MetaType
if raw.Status != nil {
statusData := map[string]interface{}{
statusData := map[string]any{
"online": raw.Status.Online,
"good": raw.Status.Good,
}
if raw.Status.Stat != nil {
statusData["stat"] = map[string]interface{}{
statusData["stat"] = map[string]any{
"packet_received": raw.Status.Stat.PacketReceived,
"packet_sent": raw.Status.Stat.PacketSent,
"packet_lost": raw.Status.Stat.PacketLost,
@@ -183,7 +183,7 @@ func (a *Adapter) convertMetaEvent(raw *RawEvent, base *protocol.BaseEvent) (pro
}
// parseMessageSegments 解析消息段
func (a *Adapter) parseMessageSegments(message interface{}) ([]MessageSegment, error) {
func (a *Adapter) parseMessageSegments(message any) ([]MessageSegment, error) {
if message == nil {
return nil, fmt.Errorf("message is nil")
}
@@ -193,7 +193,7 @@ func (a *Adapter) parseMessageSegments(message interface{}) ([]MessageSegment, e
return []MessageSegment{
{
Type: SegmentTypeText,
Data: map[string]interface{}{
Data: map[string]any{
"text": str,
},
},
@@ -215,7 +215,7 @@ func (a *Adapter) parseMessageSegments(message interface{}) ([]MessageSegment, e
}
// BuildMessage 构建OneBot11消息
func BuildMessage(segments []MessageSegment) interface{} {
func BuildMessage(segments []MessageSegment) any {
if len(segments) == 0 {
return ""
}
@@ -235,7 +235,7 @@ func BuildTextMessage(text string) []MessageSegment {
return []MessageSegment{
{
Type: SegmentTypeText,
Data: map[string]interface{}{
Data: map[string]any{
"text": text,
},
},
@@ -247,7 +247,7 @@ func BuildImageMessage(file string) []MessageSegment {
return []MessageSegment{
{
Type: SegmentTypeImage,
Data: map[string]interface{}{
Data: map[string]any{
"file": file,
},
},
@@ -258,7 +258,7 @@ func BuildImageMessage(file string) []MessageSegment {
func BuildAtMessage(userID int64) MessageSegment {
return MessageSegment{
Type: SegmentTypeAt,
Data: map[string]interface{}{
Data: map[string]any{
"qq": userID,
},
}
@@ -268,7 +268,7 @@ func BuildAtMessage(userID int64) MessageSegment {
func BuildReplyMessage(messageID int32) MessageSegment {
return MessageSegment{
Type: SegmentTypeReply,
Data: map[string]interface{}{
Data: map[string]any{
"id": messageID,
},
}
@@ -278,7 +278,7 @@ func BuildReplyMessage(messageID int32) MessageSegment {
func BuildFaceMessage(faceID int) MessageSegment {
return MessageSegment{
Type: SegmentTypeFace,
Data: map[string]interface{}{
Data: map[string]any{
"id": faceID,
},
}
@@ -288,7 +288,7 @@ func BuildFaceMessage(faceID int) MessageSegment {
func BuildRecordMessage(file string) MessageSegment {
return MessageSegment{
Type: SegmentTypeRecord,
Data: map[string]interface{}{
Data: map[string]any{
"file": file,
},
}
@@ -298,7 +298,7 @@ func BuildRecordMessage(file string) MessageSegment {
func BuildVideoMessage(file string) MessageSegment {
return MessageSegment{
Type: SegmentTypeVideo,
Data: map[string]interface{}{
Data: map[string]any{
"file": file,
},
}
@@ -308,7 +308,7 @@ func BuildVideoMessage(file string) MessageSegment {
func BuildShareMessage(url, title string) MessageSegment {
return MessageSegment{
Type: SegmentTypeShare,
Data: map[string]interface{}{
Data: map[string]any{
"url": url,
"title": title,
},
@@ -319,7 +319,7 @@ func BuildShareMessage(url, title string) MessageSegment {
func BuildLocationMessage(lat, lon float64, title, content string) MessageSegment {
return MessageSegment{
Type: SegmentTypeLocation,
Data: map[string]interface{}{
Data: map[string]any{
"lat": lat,
"lon": lon,
"title": title,
@@ -332,7 +332,7 @@ func BuildLocationMessage(lat, lon float64, title, content string) MessageSegmen
func BuildMusicMessage(musicType, musicID string) MessageSegment {
return MessageSegment{
Type: SegmentTypeMusic,
Data: map[string]interface{}{
Data: map[string]any{
"type": musicType,
"id": musicID,
},
@@ -343,7 +343,7 @@ func BuildMusicMessage(musicType, musicID string) MessageSegment {
func BuildCustomMusicMessage(url, audio, title, content, image string) MessageSegment {
return MessageSegment{
Type: SegmentTypeMusic,
Data: map[string]interface{}{
Data: map[string]any{
"type": "custom",
"url": url,
"audio": audio,

View File

@@ -7,7 +7,7 @@ import (
)
// ConvertMessageChainToOB11 将通用消息链转换为 OneBot11 格式
func ConvertMessageChainToOB11(chain protocol.MessageChain) interface{} {
func ConvertMessageChainToOB11(chain protocol.MessageChain) any {
if len(chain) == 0 {
return ""
}
@@ -38,7 +38,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
// 文本消息段
return &MessageSegment{
Type: SegmentTypeText,
Data: map[string]interface{}{
Data: map[string]any{
"text": seg.Data["text"],
},
}
@@ -48,7 +48,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
userID := seg.Data["user_id"]
return &MessageSegment{
Type: SegmentTypeAt,
Data: map[string]interface{}{
Data: map[string]any{
"qq": userID,
},
}
@@ -61,7 +61,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
}
return &MessageSegment{
Type: SegmentTypeAt,
Data: map[string]interface{}{
Data: map[string]any{
"qq": userID,
},
}
@@ -75,7 +75,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
}
return &MessageSegment{
Type: SegmentTypeImage,
Data: map[string]interface{}{
Data: map[string]any{
"file": fileID,
},
}
@@ -88,7 +88,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
}
return &MessageSegment{
Type: SegmentTypeRecord,
Data: map[string]interface{}{
Data: map[string]any{
"file": fileID,
},
}
@@ -101,7 +101,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
}
return &MessageSegment{
Type: SegmentTypeRecord,
Data: map[string]interface{}{
Data: map[string]any{
"file": fileID,
},
}
@@ -114,7 +114,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
}
return &MessageSegment{
Type: SegmentTypeVideo,
Data: map[string]interface{}{
Data: map[string]any{
"file": fileID,
},
}
@@ -124,7 +124,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
messageID := seg.Data["message_id"]
return &MessageSegment{
Type: SegmentTypeReply,
Data: map[string]interface{}{
Data: map[string]any{
"id": messageID,
},
}
@@ -134,7 +134,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
faceID := seg.Data["id"]
return &MessageSegment{
Type: SegmentTypeFace,
Data: map[string]interface{}{
Data: map[string]any{
"id": faceID,
},
}
@@ -149,7 +149,7 @@ func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
}
// ConvertOB11ToMessageChain 将 OneBot11 消息段转换为通用消息链
func ConvertOB11ToMessageChain(ob11Message interface{}) (protocol.MessageChain, error) {
func ConvertOB11ToMessageChain(ob11Message any) (protocol.MessageChain, error) {
chain := protocol.MessageChain{}
// 如果是字符串,转换为文本消息段
@@ -167,11 +167,11 @@ func ConvertOB11ToMessageChain(ob11Message interface{}) (protocol.MessageChain,
}
// 如果是接口数组,尝试转换
if segments, ok := ob11Message.([]interface{}); ok {
if segments, ok := ob11Message.([]any); ok {
for _, seg := range segments {
if segMap, ok := seg.(map[string]interface{}); ok {
if segMap, ok := seg.(map[string]any); ok {
segType, _ := segMap["type"].(string)
segData, _ := segMap["data"].(map[string]interface{})
segData, _ := segMap["data"].(map[string]any)
genericSeg := convertOB11SegmentToGeneric(MessageSegment{
Type: segType,
Data: segData,
@@ -211,7 +211,7 @@ func convertOB11SegmentToGeneric(seg MessageSegment) protocol.MessageSegment {
}
return protocol.MessageSegment{
Type: protocol.SegmentTypeVoice,
Data: map[string]interface{}{
Data: map[string]any{
"file_id": fileID,
},
}
@@ -223,7 +223,7 @@ func convertOB11SegmentToGeneric(seg MessageSegment) protocol.MessageSegment {
case SegmentTypeFace:
return protocol.MessageSegment{
Type: protocol.SegmentTypeFace,
Data: map[string]interface{}{
Data: map[string]any{
"id": seg.Data["id"],
},
}

View File

@@ -2,32 +2,32 @@ package onebot11
// RawEvent OneBot11原始事件
type RawEvent struct {
Time int64 `json:"time"`
SelfID int64 `json:"self_id"`
PostType string `json:"post_type"`
MessageType string `json:"message_type,omitempty"`
SubType string `json:"sub_type,omitempty"`
MessageID int32 `json:"message_id,omitempty"`
UserID int64 `json:"user_id,omitempty"`
GroupID int64 `json:"group_id,omitempty"`
Message interface{} `json:"message,omitempty"`
RawMessage string `json:"raw_message,omitempty"`
Font int32 `json:"font,omitempty"`
Sender *Sender `json:"sender,omitempty"`
Anonymous *Anonymous `json:"anonymous,omitempty"`
NoticeType string `json:"notice_type,omitempty"`
OperatorID int64 `json:"operator_id,omitempty"`
Duration int64 `json:"duration,omitempty"`
RequestType string `json:"request_type,omitempty"`
Comment string `json:"comment,omitempty"`
Flag string `json:"flag,omitempty"`
MetaType string `json:"meta_event_type,omitempty"`
Status *Status `json:"status,omitempty"`
Interval int64 `json:"interval,omitempty"`
File *FileInfo `json:"file,omitempty"` // 群文件上传信息
TargetID int64 `json:"target_id,omitempty"` // 戳一戳、红包运气王目标ID
HonorType string `json:"honor_type,omitempty"` // 群荣誉类型
Extra map[string]interface{} `json:"-"`
Time int64 `json:"time"`
SelfID int64 `json:"self_id"`
PostType string `json:"post_type"`
MessageType string `json:"message_type,omitempty"`
SubType string `json:"sub_type,omitempty"`
MessageID int32 `json:"message_id,omitempty"`
UserID int64 `json:"user_id,omitempty"`
GroupID int64 `json:"group_id,omitempty"`
Message any `json:"message,omitempty"`
RawMessage string `json:"raw_message,omitempty"`
Font int32 `json:"font,omitempty"`
Sender *Sender `json:"sender,omitempty"`
Anonymous *Anonymous `json:"anonymous,omitempty"`
NoticeType string `json:"notice_type,omitempty"`
OperatorID int64 `json:"operator_id,omitempty"`
Duration int64 `json:"duration,omitempty"`
RequestType string `json:"request_type,omitempty"`
Comment string `json:"comment,omitempty"`
Flag string `json:"flag,omitempty"`
MetaType string `json:"meta_event_type,omitempty"`
Status *Status `json:"status,omitempty"`
Interval int64 `json:"interval,omitempty"`
File *FileInfo `json:"file,omitempty"` // 群文件上传信息
TargetID int64 `json:"target_id,omitempty"` // 戳一戳、红包运气王目标ID
HonorType string `json:"honor_type,omitempty"` // 群荣誉类型
Extra map[string]any `json:"-"`
}
// Sender 发送者信息
@@ -79,23 +79,23 @@ type Stat struct {
// OB11Action OneBot11动作
type OB11Action struct {
Action string `json:"action"`
Params map[string]interface{} `json:"params"`
Echo string `json:"echo,omitempty"`
Action string `json:"action"`
Params map[string]any `json:"params"`
Echo string `json:"echo,omitempty"`
}
// OB11Response OneBot11响应
type OB11Response struct {
Status string `json:"status"`
RetCode int `json:"retcode"`
Data map[string]interface{} `json:"data,omitempty"`
Echo string `json:"echo,omitempty"`
Status string `json:"status"`
RetCode int `json:"retcode"`
Data map[string]any `json:"data,omitempty"`
Echo string `json:"echo,omitempty"`
}
// MessageSegment 消息段
type MessageSegment struct {
Type string `json:"type"`
Data map[string]interface{} `json:"data"`
Type string `json:"type"`
Data map[string]any `json:"data"`
}
// 消息段类型常量