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:
@@ -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,
|
||||
|
||||
@@ -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())),
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
// 消息段类型常量
|
||||
|
||||
Reference in New Issue
Block a user