Files
cellbot/internal/adapter/onebot11/message.go
lafay f3220a2381 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)
2026-03-18 01:22:49 +08:00

239 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package onebot11
import (
"fmt"
"cellbot/internal/protocol"
)
// ConvertMessageChainToOB11 将通用消息链转换为 OneBot11 格式
func ConvertMessageChainToOB11(chain protocol.MessageChain) any {
if len(chain) == 0 {
return ""
}
// 转换为 OneBot11 消息段格式
segments := make([]MessageSegment, 0, len(chain))
for _, seg := range chain {
ob11Seg := convertSegmentToOB11(seg)
if ob11Seg != nil {
segments = append(segments, *ob11Seg)
}
}
// 如果只有一个文本消息段,直接返回文本字符串
if len(segments) == 1 && segments[0].Type == SegmentTypeText {
if text, ok := segments[0].Data["text"].(string); ok {
return text
}
}
return segments
}
// convertSegmentToOB11 将通用消息段转换为 OneBot11 消息段
func convertSegmentToOB11(seg protocol.MessageSegment) *MessageSegment {
switch seg.Type {
case protocol.SegmentTypeText:
// 文本消息段
return &MessageSegment{
Type: SegmentTypeText,
Data: map[string]any{
"text": seg.Data["text"],
},
}
case protocol.SegmentTypeMention:
// @提及OneBot12 -> OneBot11
userID := seg.Data["user_id"]
return &MessageSegment{
Type: SegmentTypeAt,
Data: map[string]any{
"qq": userID,
},
}
case protocol.SegmentTypeAt:
// OneBot11 兼容格式
userID, ok := seg.Data["user_id"]
if !ok {
userID = seg.Data["qq"]
}
return &MessageSegment{
Type: SegmentTypeAt,
Data: map[string]any{
"qq": userID,
},
}
case protocol.SegmentTypeImage:
// 图片消息段
fileID, ok := seg.Data["file_id"].(string)
if !ok {
// 兼容 file 字段
fileID, _ = seg.Data["file"].(string)
}
return &MessageSegment{
Type: SegmentTypeImage,
Data: map[string]any{
"file": fileID,
},
}
case protocol.SegmentTypeVoice:
// 语音消息段OneBot12 -> OneBot11
fileID, ok := seg.Data["file_id"].(string)
if !ok {
fileID, _ = seg.Data["file"].(string)
}
return &MessageSegment{
Type: SegmentTypeRecord,
Data: map[string]any{
"file": fileID,
},
}
case protocol.SegmentTypeRecord:
// OneBot11 兼容格式
fileID, ok := seg.Data["file"].(string)
if !ok {
fileID, _ = seg.Data["file_id"].(string)
}
return &MessageSegment{
Type: SegmentTypeRecord,
Data: map[string]any{
"file": fileID,
},
}
case protocol.SegmentTypeVideo:
// 视频消息段
fileID, ok := seg.Data["file_id"].(string)
if !ok {
fileID, _ = seg.Data["file"].(string)
}
return &MessageSegment{
Type: SegmentTypeVideo,
Data: map[string]any{
"file": fileID,
},
}
case protocol.SegmentTypeReply:
// 回复消息段
messageID := seg.Data["message_id"]
return &MessageSegment{
Type: SegmentTypeReply,
Data: map[string]any{
"id": messageID,
},
}
case protocol.SegmentTypeFace:
// 表情消息段
faceID := seg.Data["id"]
return &MessageSegment{
Type: SegmentTypeFace,
Data: map[string]any{
"id": faceID,
},
}
default:
// 其他类型,尝试直接转换
return &MessageSegment{
Type: seg.Type,
Data: seg.Data,
}
}
}
// ConvertOB11ToMessageChain 将 OneBot11 消息段转换为通用消息链
func ConvertOB11ToMessageChain(ob11Message any) (protocol.MessageChain, error) {
chain := protocol.MessageChain{}
// 如果是字符串,转换为文本消息段
if str, ok := ob11Message.(string); ok {
return protocol.NewMessageChain(protocol.NewTextSegment(str)), nil
}
// 如果是数组,解析为消息段数组
if segments, ok := ob11Message.([]MessageSegment); ok {
for _, seg := range segments {
genericSeg := convertOB11SegmentToGeneric(seg)
chain = append(chain, genericSeg)
}
return chain, nil
}
// 如果是接口数组,尝试转换
if segments, ok := ob11Message.([]any); ok {
for _, seg := range segments {
if segMap, ok := seg.(map[string]any); ok {
segType, _ := segMap["type"].(string)
segData, _ := segMap["data"].(map[string]any)
genericSeg := convertOB11SegmentToGeneric(MessageSegment{
Type: segType,
Data: segData,
})
chain = append(chain, genericSeg)
}
}
return chain, nil
}
return nil, fmt.Errorf("unsupported message format: %T", ob11Message)
}
// convertOB11SegmentToGeneric 将 OneBot11 消息段转换为通用消息段
func convertOB11SegmentToGeneric(seg MessageSegment) protocol.MessageSegment {
switch seg.Type {
case SegmentTypeText:
return protocol.NewTextSegment(seg.Data["text"].(string))
case SegmentTypeAt:
// OneBot11 @ 转换为 OneBot12 mention
userID := seg.Data["qq"]
return protocol.NewMentionSegment(userID)
case SegmentTypeImage:
fileID, ok := seg.Data["file"].(string)
if !ok {
fileID, _ = seg.Data["file_id"].(string)
}
return protocol.NewImageSegment(fileID)
case SegmentTypeRecord:
// OneBot11 record 转换为 OneBot12 voice
fileID, ok := seg.Data["file"].(string)
if !ok {
fileID, _ = seg.Data["file_id"].(string)
}
return protocol.MessageSegment{
Type: protocol.SegmentTypeVoice,
Data: map[string]any{
"file_id": fileID,
},
}
case SegmentTypeReply:
messageID := seg.Data["id"]
return protocol.NewReplySegment(messageID)
case SegmentTypeFace:
return protocol.MessageSegment{
Type: protocol.SegmentTypeFace,
Data: map[string]any{
"id": seg.Data["id"],
},
}
default:
// 其他类型,直接转换
return protocol.MessageSegment{
Type: seg.Type,
Data: seg.Data,
}
}
}