feat: enhance event handling and add scheduling capabilities
- Introduced a new scheduler to manage timed tasks within the event dispatcher. - Updated the dispatcher to support the new scheduler, allowing for improved event processing. - Enhanced action serialization in the OneBot11 adapter to convert message chains to the appropriate format. - Added new dependencies for cron scheduling and other indirect packages in go.mod and go.sum. - Improved logging for event publishing and handler matching, providing better insights during execution. - Refactored plugin loading to include scheduled job management.
This commit is contained in:
@@ -303,4 +303,4 @@ func BuildSetGroupCard(groupID, userID int64, card string) map[string]interface{
|
||||
"user_id": userID,
|
||||
"card": card,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,9 +227,23 @@ func (a *Adapter) SerializeAction(action protocol.Action) ([]byte, error) {
|
||||
zap.String("hint", "This action type may not be supported by OneBot11"))
|
||||
}
|
||||
|
||||
// 复制参数并转换消息链
|
||||
params := make(map[string]interface{})
|
||||
for k, v := range action.GetParams() {
|
||||
// 检查是否是消息链
|
||||
if k == "message" {
|
||||
if chain, ok := v.(protocol.MessageChain); ok {
|
||||
// 转换为 OneBot11 格式
|
||||
params[k] = ConvertMessageChainToOB11(chain)
|
||||
continue
|
||||
}
|
||||
}
|
||||
params[k] = v
|
||||
}
|
||||
|
||||
ob11Action := &OB11Action{
|
||||
Action: ob11ActionName,
|
||||
Params: action.GetParams(),
|
||||
Params: params,
|
||||
}
|
||||
|
||||
return sonic.Marshal(ob11Action)
|
||||
|
||||
238
internal/adapter/onebot11/message.go
Normal file
238
internal/adapter/onebot11/message.go
Normal file
@@ -0,0 +1,238 @@
|
||||
package onebot11
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"cellbot/internal/protocol"
|
||||
)
|
||||
|
||||
// ConvertMessageChainToOB11 将通用消息链转换为 OneBot11 格式
|
||||
func ConvertMessageChainToOB11(chain protocol.MessageChain) interface{} {
|
||||
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]interface{}{
|
||||
"text": seg.Data["text"],
|
||||
},
|
||||
}
|
||||
|
||||
case protocol.SegmentTypeMention:
|
||||
// @提及(OneBot12 -> OneBot11)
|
||||
userID := seg.Data["user_id"]
|
||||
return &MessageSegment{
|
||||
Type: SegmentTypeAt,
|
||||
Data: map[string]interface{}{
|
||||
"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]interface{}{
|
||||
"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]interface{}{
|
||||
"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]interface{}{
|
||||
"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]interface{}{
|
||||
"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]interface{}{
|
||||
"file": fileID,
|
||||
},
|
||||
}
|
||||
|
||||
case protocol.SegmentTypeReply:
|
||||
// 回复消息段
|
||||
messageID := seg.Data["message_id"]
|
||||
return &MessageSegment{
|
||||
Type: SegmentTypeReply,
|
||||
Data: map[string]interface{}{
|
||||
"id": messageID,
|
||||
},
|
||||
}
|
||||
|
||||
case protocol.SegmentTypeFace:
|
||||
// 表情消息段
|
||||
faceID := seg.Data["id"]
|
||||
return &MessageSegment{
|
||||
Type: SegmentTypeFace,
|
||||
Data: map[string]interface{}{
|
||||
"id": faceID,
|
||||
},
|
||||
}
|
||||
|
||||
default:
|
||||
// 其他类型,尝试直接转换
|
||||
return &MessageSegment{
|
||||
Type: seg.Type,
|
||||
Data: seg.Data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertOB11ToMessageChain 将 OneBot11 消息段转换为通用消息链
|
||||
func ConvertOB11ToMessageChain(ob11Message interface{}) (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.([]interface{}); ok {
|
||||
for _, seg := range segments {
|
||||
if segMap, ok := seg.(map[string]interface{}); ok {
|
||||
segType, _ := segMap["type"].(string)
|
||||
segData, _ := segMap["data"].(map[string]interface{})
|
||||
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]interface{}{
|
||||
"file_id": fileID,
|
||||
},
|
||||
}
|
||||
|
||||
case SegmentTypeReply:
|
||||
messageID := seg.Data["id"]
|
||||
return protocol.NewReplySegment(messageID)
|
||||
|
||||
case SegmentTypeFace:
|
||||
return protocol.MessageSegment{
|
||||
Type: protocol.SegmentTypeFace,
|
||||
Data: map[string]interface{}{
|
||||
"id": seg.Data["id"],
|
||||
},
|
||||
}
|
||||
|
||||
default:
|
||||
// 其他类型,直接转换
|
||||
return protocol.MessageSegment{
|
||||
Type: seg.Type,
|
||||
Data: seg.Data,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user