:refactor: 重构消息处理逻辑,新增媒体消息处理功能并优化联系人详情获取
All checks were successful
BuildImage / build-image (push) Successful in 3m2s

This commit is contained in:
李寻欢 2025-04-24 16:07:34 +08:00
parent b839e4991a
commit de3c7bcd2c
6 changed files with 112 additions and 55 deletions

2
go.mod
View File

@ -3,7 +3,7 @@ module gitee.ltd/lxh/wechat-robot
go 1.24.0
require (
gitee.ltd/lxh/xybot v0.0.4
gitee.ltd/lxh/xybot v0.0.5
github.com/docker/docker v28.1.1+incompatible
github.com/docker/go-connections v0.5.0
github.com/go-co-op/gocron/v2 v2.16.1

2
go.sum
View File

@ -4,6 +4,8 @@ gitee.ltd/lxh/xybot v0.0.3 h1:/xRCnW2nMtx/hdV7TdpEcL3Sh8f9oBGHToONk0yGstA=
gitee.ltd/lxh/xybot v0.0.3/go.mod h1:jYfEAQ3WPsST/PY4fEEVFjU6KtMocxn3sQi78I+vdxc=
gitee.ltd/lxh/xybot v0.0.4 h1:sEs6ZOZud2oDWvW1MVpwHWJUq3AyxYA1G/SGP4En+/0=
gitee.ltd/lxh/xybot v0.0.4/go.mod h1:jYfEAQ3WPsST/PY4fEEVFjU6KtMocxn3sQi78I+vdxc=
gitee.ltd/lxh/xybot v0.0.5 h1:kgwJktO/p7WbywUuAGTPH2V4VOta6dnYs1CXz6qVvZU=
gitee.ltd/lxh/xybot v0.0.5/go.mod h1:jYfEAQ3WPsST/PY4fEEVFjU6KtMocxn3sQi78I+vdxc=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=

View File

@ -3,7 +3,9 @@ package tasks
import (
"gitee.ltd/lxh/wechat-robot/internal/model"
"gitee.ltd/lxh/xybot"
"gitee.ltd/lxh/xybot/friend"
"github.com/gofiber/fiber/v2/log"
"slices"
"strings"
)
@ -26,13 +28,22 @@ func syncContact(containerHost, robotWxId string, robotId uint) {
return
}
// 将ids拆分成二十个一个的数组之后再获取详情
var contacts = make([]friend.ContactListItem, 0)
chunker := slices.Chunk(ids, 20)
processChunk := func(chunk []string) bool {
// 获取昵称等详细信息
contacts, err := robotCli.Friend.GetContractDetail(ids)
var c = make([]friend.ContactListItem, 0)
c, err = robotCli.Friend.GetContractDetail(chunk)
if err != nil {
// 处理错误
log.Errorf("[%s]获取联系人详情失败: %v", robotWxId, err)
return
return false
}
contacts = append(contacts, c...)
return true
}
chunker(processChunk)
// 循环联系人信息,打印一下
db := model.GetDB()

View File

@ -1,13 +1,10 @@
package tasks
import (
"encoding/xml"
"gitee.ltd/lxh/wechat-robot/internal/minio"
"gitee.ltd/lxh/wechat-robot/internal/model"
"gitee.ltd/lxh/wechat-robot/internal/types"
"gitee.ltd/lxh/wechat-robot/internal/wechat"
messageHandler "gitee.ltd/lxh/wechat-robot/pkg/message"
"gitee.ltd/lxh/xybot"
"github.com/gofiber/fiber/v2/log"
"strings"
"time"
)
@ -43,7 +40,7 @@ func syncMessage(client *xybot.Client, robotId uint) {
//log.Debugf("当前同步机器人Id: %d消息数量: %d客户端信息: %+v", robotId, len(messages), client)
// 处理消息
var msg []model.Message
//var msg []model.Message
for _, message := range messages {
//log.Debugf("当前同步机器人Id: %d消息内容: %s", robotId, message.Content.String)
var m model.Message
@ -72,50 +69,14 @@ func syncMessage(client *xybot.Client, robotId uint) {
m.Content = strings.Join(strings.Split(m.Content, "\n")[1:], "\n")
}
// 处理一下如果是图片、文件、表情包等信息直接下载下来存到OSS
if m.Type == types.MsgTypeImage || m.Type == types.MsgTypeVideo {
// 解析消息xml文件
// 解析为结构体
var media wechat.MediaMessage
if err = xml.Unmarshal([]byte(m.Content), &media); err != nil {
log.Errorf("%v解析消息失败: %v", m.Type, err.Error())
continue
}
var md5Str, bs64Str string
switch m.Type {
case types.MsgTypeImage:
fileUrl := ""
md5Str = media.Img.Md5
if media.Img.CdnBigImgUrl != "" {
fileUrl = media.Img.CdnBigImgUrl
} else if media.Img.CdnMidImgUrl != "" {
fileUrl = media.Img.CdnMidImgUrl
} else if media.Img.CdnThumbUrl != "" {
fileUrl = media.Img.CdnThumbUrl
} else {
continue
}
if bs64Str, err = client.Tool.CdnDownloadImg(media.Img.AesKey, fileUrl); err != nil {
log.Errorf("图片文件下载失败: %s", err.Error())
continue
}
case types.MsgTypeVideo:
if bs64Str, err = client.Tool.DownloadVideo(m.ClientMsgId); err != nil {
log.Errorf("视频文件下载失败: %s", err.Error())
continue
}
}
// 下载完成保存到OSS
if m.FileUrl, err = minio.SaveBase64(bs64Str, md5Str); err != nil {
log.Errorf("文件保存到Minio失败: %s", err.Error())
continue
}
}
msg = append(msg, m)
}
//msg = append(msg, m)
// 保存入库
db.Save(&msg)
db.Save(&m)
// 异步处理消息
go messageHandler.Handler(&m, client)
}
// 保存入库
//db.Save(&msg)
}

19
pkg/message/handler.go Normal file
View File

@ -0,0 +1,19 @@
package message
import (
"gitee.ltd/lxh/wechat-robot/internal/model"
"gitee.ltd/lxh/wechat-robot/internal/types"
"gitee.ltd/lxh/xybot"
)
// Handler
// @description: 处理微信消息
// @param msg *model.Message 数据库保存的消息记录
// @param client *xybot.Client 机器人客户端
func Handler(msg *model.Message, client *xybot.Client) {
// 处理一下如果是图片、文件、表情包等信息直接下载下来存到OSS
if msg.Type == types.MsgTypeImage || msg.Type == types.MsgTypeVideo {
handlerMedia(msg, client)
}
}

64
pkg/message/media.go Normal file
View File

@ -0,0 +1,64 @@
package message
import (
"encoding/xml"
"gitee.ltd/lxh/wechat-robot/internal/minio"
"gitee.ltd/lxh/wechat-robot/internal/model"
"gitee.ltd/lxh/wechat-robot/internal/types"
"gitee.ltd/lxh/wechat-robot/internal/wechat"
"gitee.ltd/lxh/xybot"
"github.com/gofiber/fiber/v2/log"
)
// handlerMedia
// @description: 处理媒体消息
// @param msg *model.Message 消息记录
// @param client *xybot.Client 机器人客户端
func handlerMedia(msg *model.Message, client *xybot.Client) {
var err error
// 解析消息xml文件
// 解析为结构体
var media wechat.MediaMessage
if err = xml.Unmarshal([]byte(msg.Content), &media); err != nil {
log.Errorf("%v解析消息失败: %v", msg.Type, err.Error())
return
}
var md5Str, bs64Str string
switch msg.Type {
case types.MsgTypeImage:
fileUrl := ""
md5Str = media.Img.Md5
if media.Img.CdnBigImgUrl != "" {
fileUrl = media.Img.CdnBigImgUrl
} else if media.Img.CdnMidImgUrl != "" {
fileUrl = media.Img.CdnMidImgUrl
} else if media.Img.CdnThumbUrl != "" {
fileUrl = media.Img.CdnThumbUrl
} else {
return
}
if bs64Str, err = client.Tool.CdnDownloadImg(media.Img.AesKey, fileUrl); err != nil {
log.Errorf("图片文件下载失败: %s", err.Error())
return
}
case types.MsgTypeVideo:
if bs64Str, err = client.Tool.DownloadVideo(msg.ClientMsgId); err != nil {
log.Errorf("视频文件下载失败: %s", err.Error())
return
}
}
// 下载完成保存到OSS
msg.FileUrl, err = minio.SaveBase64(bs64Str, md5Str)
if err != nil {
log.Errorf("文件保存到Minio失败: %s", err.Error())
return
}
// 更新数据库
if err = model.GetDB().Model(&msg).Where("id = ?", msg.ID).Update("file_url", msg.FileUrl).Error; err != nil {
log.Errorf("更新数据库失败: %s", err.Error())
return
}
}