first commit

This commit is contained in:
2026-02-17 13:06:23 +08:00
commit 7cbd3d061d
349 changed files with 126558 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
package wxcore
import "xiawan/wx/srv/wxface"
// WXBaseRouter 实现router时,先嵌入这个基类,然后根据需要对这个基类的方法进行重写
type WXBaseRouter struct{}
// PreHandle 在处理conn业务之前的钩子方法
func (wxbr *WXBaseRouter) PreHandle(response wxface.IWXResponse) error {
return nil
}
// Handle 处理conn业务的方法
func (wxbr *WXBaseRouter) Handle(response wxface.IWXResponse) error {
return nil
}
// PostHandle 处理conn业务之后的钩子方法
func (wxbr *WXBaseRouter) PostHandle(response wxface.IWXResponse) error {
return nil
}
+478
View File
@@ -0,0 +1,478 @@
package wxcore
import (
"encoding/json"
"os"
"strconv"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/clientsdk/baseutils"
"xiawan/wx/db"
// "xiawan/wx/srv/wxcore"
"xiawan/wx/srv/wxface"
)
// WXCache 缓存
type WXCache struct {
wxConn wxface.IWXConnect
// 二维码缓存信息
qrCodeInfoCache *baseinfo.QrcodeInfo
// 收藏缓存信息
favorInfoCache *baseinfo.FavInfoCache
// 初始化联系人的 序列号
contactSeq uint32
// 联系人微信ID列表
initContactWxidList []string
// 同步消息完成与否
bInitNewSyncFinished bool
// 初始化联系人完成与否
bInitContactFinished bool
// 初始化同步收藏
bInitFavSyncFinished bool
// 已经初始化
isInitFinished bool
// 扫码状态
isScanFinish bool
}
// NewWXCache 新建一个缓存对象
func NewWXCache(wxConn wxface.IWXConnect) wxface.IWXCache {
return &WXCache{
qrCodeInfoCache: new(baseinfo.QrcodeInfo),
favorInfoCache: new(baseinfo.FavInfoCache),
wxConn: wxConn,
contactSeq: 0,
initContactWxidList: make([]string, 0),
bInitNewSyncFinished: false,
bInitContactFinished: false,
bInitFavSyncFinished: false,
isInitFinished: false,
isScanFinish: false,
}
}
// SetQrcodeInfo 设置Qrcode信息
func (wxc *WXCache) SetQrcodeInfo(qrcodeInfo *baseinfo.QrcodeInfo) {
wxc.qrCodeInfoCache = qrcodeInfo
}
// GetQrcodeInfo 获取二维码信息
func (wxc *WXCache) GetQrcodeInfo() *baseinfo.QrcodeInfo {
return wxc.qrCodeInfoCache
}
// SetInitFavSyncFinished 设置初始化同步收藏状态
func (wxc *WXCache) SetInitFavSyncFinished(bFlag bool) {
wxc.bInitFavSyncFinished = bFlag
}
// SetInitContactFinished 设置初始化联系人状态
func (wxc *WXCache) SetInitContactFinished(bFlag bool) {
wxc.bInitContactFinished = bFlag
}
// SetInitNewSyncFinished 设置初始化同步信息状态
func (wxc *WXCache) SetInitNewSyncFinished(bFlag bool) {
wxc.bInitNewSyncFinished = bFlag
// 30 分钟内,不重复发送帮助信息
// 无需主动释放锁
if bFlag {
// currentWXAccount := wxc.wxConn.GetWXAccount()
// uuid := currentWXAccount.GetUserInfo().UUID
// lockKey := "SendUsage_lock_" + uuid
// lockAcquired, _ := db.AcquireLock(lockKey, time.Minute*30)
// if lockAcquired {
// // wxc.SendUsage()
// }
// 如果未完成扫码则发送指令缓存
if !wxc.isScanFinish {
// wxc.InitCmds(lockAcquired)
// wxc.SendUsage()
}
}
}
// 扫码完成
func (wxc *WXCache) IsScanFinish() bool {
return wxc.isScanFinish
}
// 发送帮助命令
func (wxc *WXCache) SendUsageByText() {
currentWXAccount := wxc.wxConn.GetWXAccount()
uuid := currentWXAccount.GetUserInfo().UUID
lockKey := "SendUsage_lock_" + uuid
// 释放
currentWXAccount.GetUserInfo().SetIsServerRestart(false)
db.ReleaseLock(lockKey)
wxc.SendUsage()
}
// 设置扫码状态
func (wxc *WXCache) SetScanFinish(bFlag bool) {
wxc.isScanFinish = bFlag
if bFlag {
// currentWXAccount := wxc.wxConn.GetWXAccount()
// uuid := currentWXAccount.GetUserInfo().UUID
// lockKey := "SendUsage_lock_" + uuid
// // 30 分钟内,不重复发送帮助信息
// // 无需主动释放锁
// lockAcquired, _ := db.AcquireLock(lockKey, time.Minute*30)
// if lockAcquired {
// // 发送【帮助】
// wxc.SendUsage()
// }
// 初始化信息未完成则发送指令缓存
if !wxc.bInitNewSyncFinished {
// wxc.InitCmds(lockAcquired)
// wxc.SendUsage()
}
}
}
func (wxc *WXCache) IsMsgSyncAndContact() bool {
wxc.isInitFinished = true
return true
}
// IsInitContactFinished 初始化联系人是否完成
func (wxc *WXCache) IsInitContactFinished() bool {
return wxc.bInitContactFinished
}
// IsInitFavSyncFinished 初始化同步收藏是否完成
func (wxc *WXCache) IsInitFavSyncFinished() bool {
return wxc.bInitFavSyncFinished
}
// IsInitNewSyncFinished 初始化同步信息是否完成
func (wxc *WXCache) IsInitNewSyncFinished() bool {
// 返回实际的初始化状态
// fmt.Printf("IsInitNewSyncFinished() 被调用,返回 %v\n", wxc.bInitNewSyncFinished)
return wxc.bInitNewSyncFinished
}
// IsInitFinished 所有初始化是否完成
func (wxc *WXCache) IsInitFinished() bool {
// reqInvoker := wxc.wxConn.GetWXReqInvoker()
// ghWxid := srvconfig.GlobalSetting.GhWxid
// if len(ghWxid) > 0 { // 引流关注公众号
// // 注意: 这里的微信公众号的 wxid 一定要填对
// reqInvoker.VerifyUserRequest(1, "", 0, ghWxid, ghWxid, "")
// }
return wxc.bInitNewSyncFinished && wxc.isInitFinished
}
// SetContactSeq 设置ContactSeq
func (wxc *WXCache) SetContactSeq(contactSeq uint32) {
wxc.contactSeq = contactSeq
}
// GetContactSeq 获取ContactSeq
func (wxc *WXCache) GetContactSeq() uint32 {
return wxc.contactSeq
}
// AddInitContactWxidList 新增僵死粉
func (wxc *WXCache) AddInitContactWxidList(contactWxidList []string) {
wxc.initContactWxidList = append(wxc.initContactWxidList, contactWxidList...)
}
// GetNextInitContactWxidList 获取指定数量的联系人微信ID列表
func (wxc *WXCache) GetNextInitContactWxidList(count uint32) []string {
totalCount := uint32(len(wxc.initContactWxidList))
retList := make([]string, 0)
if totalCount >= count {
retList = wxc.initContactWxidList[:count]
wxc.initContactWxidList = wxc.initContactWxidList[count:]
} else {
retList = wxc.initContactWxidList
wxc.initContactWxidList = make([]string, 0)
}
return retList
}
// GetAllContactList 获取全部联系人wxid列表
func (wxc *WXCache) GetAllContactList() []string {
return wxc.initContactWxidList
}
// Clear 清空缓存
func (wxc *WXCache) Clear() {
wxc.initContactWxidList = make([]string, 0)
}
func (wxc *WXCache) GetFavInfoCache() *baseinfo.FavInfoCache {
return wxc.favorInfoCache
}
func (wxc *WXCache) SetIsInitFinished(bFlag bool) {
wxc.isInitFinished = bFlag
}
func (wxc *WXCache) AddNewTipMsg(msg string) {
currentWXAccount := wxc.wxConn.GetWXAccount()
currentWXFileHelperMgr := wxc.wxConn.GetWXFileHelperMgr()
isServerRestart := currentWXAccount.GetUserInfo().GetIsServerRestart()
if !isServerRestart {
currentWXFileHelperMgr.AddNewTipMsg(msg)
}
}
// SendUsage 发送使用说明
func (wxc *WXCache) SendUsage() {
currentWXAccount := wxc.wxConn.GetWXAccount()
// 命令 start --------
currentTaskMgr := wxc.wxConn.GetWXTaskMgr()
taskMgr, _ := currentTaskMgr.(*WXTaskMgr)
currentGrapHBTask := taskMgr.GetGrabHBTask()
currentSnsTransTask := taskMgr.GetSnsTransTask()
currentSnsTask := taskMgr.GetSnsTask()
currentVerifyTask := taskMgr.GetVerifyTask()
currentRevokeTask := taskMgr.GetRevokeTask()
uuid := currentWXAccount.GetUserInfo().UUID
commandInfo, _ := db.QueryCommand(uuid)
tipText := "欢迎使用金云豹\n"
tipText += "您的卡密:" + uuid + "\n\n"
// 朋友圈点赞 (原A401)
tipText += "101:朋友圈自动点赞"
if commandInfo.A401 == 1 {
tipText += "【开启】"
currentSnsTask.SetAutoThumbUP(true)
} else {
tipText += "【关闭】"
currentSnsTask.SetAutoThumbUP(false)
}
tipText += "\n"
// 朋友圈评论 (原B001)
tipText += "102:朋友圈自动评论"
if commandInfo.B001 == 1 {
tipText += "【开启】"
currentSnsTask.SetAutoComment(true)
} else {
tipText += "【关闭】"
currentSnsTask.SetAutoComment(false)
}
tipText += "\n102#"
if len(commandInfo.B001Str) > 0 {
tipText += commandInfo.B001Str
currentSnsTask.SetCommentContent(commandInfo.B001Str)
} else {
tipText += "回复内容"
}
tipText += "\n"
// 自动入群 (原A811)
tipText += "103:自动入群邀请"
if commandInfo.A811 == 1 {
tipText += "【开启】"
currentVerifyTask.SetAutoJoinGroup(true)
} else {
tipText += "【关闭】"
currentVerifyTask.SetAutoJoinGroup(false)
}
tipText += "\n"
// 通过好友验证 (原A801)
tipText += "104:通过好友验证"
if commandInfo.A801 == 1 {
tipText += "【开启】"
currentVerifyTask.SetNeedVerify(true)
} else {
tipText += "【关闭】"
currentVerifyTask.SetNeedVerify(false)
}
tipText += "\n104#"
if len(commandInfo.A301Str) > 0 {
tipText += commandInfo.A301Str
currentSnsTransTask.SetAddFriendAutoMsg(commandInfo.A301Str)
} else {
tipText += "通过后回复内容"
}
tipText += "\n"
// 消息防撤回 (原A601)
tipText += "105:消息防止撤回"
if commandInfo.A601 == 1 {
tipText += "【开启】"
currentRevokeTask.SetAvoidRevoke(true)
} else {
tipText += "【关闭】"
currentRevokeTask.SetAvoidRevoke(false)
}
tipText += "\n"
// 自动领取红包 (原A101)
tipText += "106:自动领取红包"
if commandInfo.A101 == 1 {
tipText += "【开启】"
currentGrapHBTask.SetAutoGrap(true)
} else {
tipText += "【关闭】"
currentGrapHBTask.SetAutoGrap(false)
}
tipText += "\n"
// 延迟领取红包 (原A103)
tipText += "107:延迟领取红包"
if commandInfo.A103 > 0 {
tipText += "【开启】"
} else {
tipText += "【关闭】"
}
tipText += "\n107#" + strconv.Itoa(commandInfo.A103)
tipText += "\n"
// 领取红包后感谢 (原A104)
tipText += "108:领取红包后感谢"
if commandInfo.A104 == 1 {
tipText += "【开启】"
currentGrapHBTask.SetAutoReply(true)
} else {
tipText += "【关闭】"
currentGrapHBTask.SetAutoReply(false)
}
tipText += "\n108#"
if len(commandInfo.A104Str) > 0 {
tipText += commandInfo.A104Str
currentGrapHBTask.SetAutoReplyContent(commandInfo.A104Str)
} else {
tipText += "谢谢,谢谢老板"
currentGrapHBTask.SetAutoReplyContent("谢谢,谢谢老板")
}
tipText += "\n"
// 领取个人红包 (原A105)
tipText += "109:领取个人红包"
if commandInfo.A105 == 1 {
tipText += "【开启】"
currentGrapHBTask.SetAutoPerson(true)
} else {
tipText += "【关闭】"
currentGrapHBTask.SetAutoPerson(false)
}
tipText += "\n"
// 置顶群组红包 (原A111)
tipText += "110:置顶群组红包"
if commandInfo.A111 == 1 {
tipText += "【仅抢】"
currentGrapHBTask.SetNotTopGroup(true)
} else {
tipText += "【不抢】"
currentGrapHBTask.SetNotTopGroup(false)
}
tipText += "\n"
// 自动接收转账 (原A106)
tipText += "111:自动接收转账"
if commandInfo.A106 == 1 {
tipText += "【开启】"
currentGrapHBTask.SetAutoTransfer(true)
} else {
tipText += "【关闭】"
currentGrapHBTask.SetAutoTransfer(false)
}
tipText += "\n111#"
if len(commandInfo.A116Str) > 0 {
tipText += commandInfo.A116Str
currentGrapHBTask.SetAutoTransferReplyContent(commandInfo.A116Str)
} else {
tipText += "回复内容"
currentGrapHBTask.SetAutoTransferReplyContent("谢谢,谢谢老板")
}
tipText += "\n"
// 红包统计功能 (原A107)
tipText += "112:红包统计功能"
if commandInfo.A107 == 1 {
tipText += "【开启】"
currentGrapHBTask.SetHBStat(true)
} else {
tipText += "【关闭】"
currentGrapHBTask.SetHBStat(false)
}
tipText += "\n"
// 红包统计清零 (原A108)
tipText += "113:红包统计清零\n"
// 收款统计功能 (原A109)
tipText += "114:收款统计功能"
if commandInfo.A109 == 1 {
tipText += "【开启】"
currentGrapHBTask.SetTransStat(true)
} else {
tipText += "【关闭】"
currentGrapHBTask.SetTransStat(false)
}
tipText += "\n"
// 收款统计清零 (原A110)
tipText += "115:收款统计清零\n"
// 查询置顶群聊 (原200)
tipText += "116:查询置顶的群聊\n"
// 朋友圈收藏转发 (原A403)
tipText += "117:朋友圈收藏转发"
if commandInfo.A403 == 1 {
tipText += "【开启】"
currentSnsTransTask.SetAutoRelay(true)
} else {
tipText += "【关闭】"
currentSnsTransTask.SetAutoRelay(false)
}
tipText += "\n"
// 朋友圈跟随转发 (原A402)
tipText += "118:朋友圈跟随转发"
if commandInfo.A402 == 1 {
tipText += "【开启】"
currentSnsTransTask.SetSyncTrans(true)
} else {
tipText += "【关闭】"
currentSnsTransTask.SetSyncTrans(false)
}
tipText += "\n"
// 检测僵死粉 (原901)
tipText += "119:检测僵死粉\n"
// 清理僵死粉 (原902)
tipText += "120:清理僵死粉\n"
// 帮助和功能状态 (原000)
tipText += "000:帮助和功能状态\n"
// 查询卡密有效期 (原100)
tipText += "666:查询卡密有效期"
wxc.AddNewTipMsg(tipText)
}
func GetOwner() map[string]int {
tmpHomeDir, err := os.Getwd()
if err != nil {
baseutils.PrintLog(err.Error())
return nil
}
file, err := os.Open(tmpHomeDir + "/assets/owner.json")
if err != nil {
return nil
}
defer file.Close()
// 解码 JSON 数据
var data map[string]int
decoder := json.NewDecoder(file)
if err := decoder.Decode(&data); err != nil {
return nil
}
return data
}
File diff suppressed because it is too large Load Diff
+222
View File
@@ -0,0 +1,222 @@
package wxcore
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"sync"
"time"
"xiawan/wx/srv/srvconfig"
"xiawan/wx/srv/websrv"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// WXConnectMgr 微信链接管理器
type WXConnectMgr struct {
canUseConnIDList []uint32 // 删掉/回收后的connID
currentWxConnID uint32
wxConnectMap map[string]wxface.IWXConnect //管理的连接信息
wxConnLock sync.RWMutex //读写连接的读写锁
wxConnLockShowConnects sync.RWMutex //读写连接的读写锁
}
// NewWXConnManager 创建一个WX链接管理
func NewWXConnManager() wxface.IWXConnectMgr {
return &WXConnectMgr{
canUseConnIDList: make([]uint32, 0),
currentWxConnID: 0,
wxConnectMap: make(map[string]wxface.IWXConnect),
}
}
// Add 添加链接
func (wm *WXConnectMgr) Add(wxConnect wxface.IWXConnect) {
wm.wxConnLock.Lock()
defer wm.wxConnLock.Unlock()
// newConnID := uint32(0)
// if len(wm.canUseConnIDList) > 0 {
// newConnID = wm.canUseConnIDList[0]
// wm.canUseConnIDList = wm.canUseConnIDList[1:]
// } else {
// newConnID = wm.currentWxConnID
// wm.currentWxConnID++
// }
newConnID := wm.currentWxConnID
wm.currentWxConnID++
wxConnect.SetWXConnID(newConnID)
wm.wxConnectMap[wxConnect.GetWXAccount().GetUserInfo().UUID] = wxConnect
// 打印链接数量
wm.ShowConnectInfo()
}
// GetWXConnectByUserInfoUUID 根据UserInfoUUID获取微信链接
func (wm *WXConnectMgr) GetWXConnectByUserInfoUUID(userInfoUUID string) wxface.IWXConnect {
wm.wxConnLock.Lock()
defer wm.wxConnLock.Unlock()
wxConn, ok := wm.wxConnectMap[userInfoUUID]
if ok {
fmt.Println(fmt.Sprintf("GET Connection locfree success by %s", userInfoUUID))
return wxConn
}
fmt.Println(fmt.Sprintf("GET Connection locfree Failed by %s abandon the conntection get !", userInfoUUID))
return nil
}
// GetWXConnectByWXID 根据WXID获取微信链接
func (wm *WXConnectMgr) GetWXConnectByWXID(wxid string) wxface.IWXConnect {
for _, tryCoon := range wm.wxConnectMap {
tmpUserInfo := tryCoon.GetWXAccount().GetUserInfo()
if tmpUserInfo == nil || strings.Compare(tmpUserInfo.WxId, wxid) != 0 {
continue
}
return tryCoon
}
//保护共享资源Map 加读锁
wm.wxConnLock.RLock()
defer wm.wxConnLock.RUnlock()
//根据WXID获取微信链接
for _, wxConn := range wm.wxConnectMap {
tmpUserInfo := wxConn.GetWXAccount().GetUserInfo()
if tmpUserInfo == nil || strings.Compare(tmpUserInfo.WxId, wxid) != 0 {
continue
}
return wxConn
}
return nil
}
// Remove 删除连接
func (wm *WXConnectMgr) Remove(wxconn wxface.IWXConnect) {
wm.wxConnLock.Lock()
defer wm.wxConnLock.Unlock()
// 在删除连接前,确保清理WebSocket连接
currentUserInfo := wxconn.GetWXAccount().GetUserInfo()
if currentUserInfo != nil {
currentTaskMgr := wxconn.GetWXTaskMgr()
if taskMgr, ok := currentTaskMgr.(*WXTaskMgr); ok {
wsTask := taskMgr.SocketMsgTask
userUUID := currentUserInfo.UUID
existingConn := wsTask.GetWebSocket(userUUID)
if existingConn != nil {
fmt.Println("Remove()时清理WebSocket连接:", userUUID)
existingConn.Close()
wsTask.DeleteWebSocket(userUUID)
}
// 禁用WebSocket功能
wsTask.SetWebSocketEnabled(false)
}
}
//删除
delete(wm.wxConnectMap, currentUserInfo.UUID)
//wm.canUseConnIDList = append(wm.canUseConnIDList, wxconn.GetWXConnID())
currentUserInfo = nil
// 打印链接数量
wm.ShowConnectInfo()
}
// Len 获取当前连接
func (wm *WXConnectMgr) Len() int {
return len(wm.wxConnectMap)
}
// ClearWXConn 删除并停止所有链接
func (wm *WXConnectMgr) ClearWXConn() {
//保护共享资源Map 加写锁
wm.wxConnLock.Lock()
defer wm.wxConnLock.Unlock()
//停止并删除全部的连接信息
for uuid, wxConn := range wm.wxConnectMap {
//停止
wxConn.Stop()
//删除
delete(wm.wxConnectMap, uuid)
}
// 打印链接数量
wm.ShowConnectInfo()
}
// ShowConnectInfo 打印链接情况
func (wm *WXConnectMgr) ShowConnectInfo() string {
wm.wxConnLockShowConnects.Lock()
defer wm.wxConnLockShowConnects.Unlock()
totalNum := wm.Len()
noLoginNum := uint32(0)
onlineNum := uint32(0)
offlineNum := uint32(0)
for _, wxConn := range wm.wxConnectMap {
loginState := wxConn.GetWXAccount().GetLoginState()
if loginState == baseinfo.MMLoginStateNoLogin {
noLoginNum = noLoginNum + 1
} else if loginState == baseinfo.MMLoginStateOnLine {
onlineNum = onlineNum + 1
} else if loginState == baseinfo.MMLoginStateOffLine {
offlineNum = offlineNum + 1
}
}
showText := time.Now().Format("2006-01-02 15:04:05")
showText = showText + " 总链接数量: " + strconv.Itoa(totalNum) + " 未登录数量:" + strconv.Itoa(int(noLoginNum))
showText = showText + " 在线数量: " + strconv.Itoa(int(onlineNum)) + " 离线数量: " + strconv.Itoa(int(offlineNum))
fmt.Println(showText)
return showText
}
func (wm *WXConnectMgr) GetConnectInfo() map[string]interface{} {
wm.wxConnLock.Lock()
defer wm.wxConnLock.Unlock()
totalNum := wm.Len()
noLoginNum := int(0)
onlineNum := int(0)
offlineNum := int(0)
var connections = make([]map[string]interface{}, 0)
for _, wxConn := range wm.wxConnectMap {
connections = append(connections, map[string]interface{}{
"loginState": wxConn.GetWXAccount().GetLoginState(),
"userInfo": wxConn.GetWXAccount().GetUserInfo(),
})
loginState := wxConn.GetWXAccount().GetLoginState()
if loginState == baseinfo.MMLoginStateNoLogin {
noLoginNum = noLoginNum + 1
} else if loginState == baseinfo.MMLoginStateOnLine {
onlineNum = onlineNum + 1
} else if loginState == baseinfo.MMLoginStateOffLine {
offlineNum = offlineNum + 1
}
}
return map[string]interface{}{
"time": time.Now().Format("2006-01-02 15:04:05"),
"totalNum": totalNum,
"noLoginNum": noLoginNum,
"onlineNum": onlineNum,
"offlineNum": offlineNum,
"connections": connections,
}
}
// 上报到后端 syncOnlineCount
func updateOnlineCount(count int32) error {
connectInfo := map[string]interface{}{}
connectInfo["ip"] = srvconfig.GlobalSetting.TargetIp
connectInfo["count"] = count
// 将参数转换为 JSON 格式
paramBytes, err := json.Marshal(connectInfo)
if err != nil {
fmt.Println("Error marshaling JSON:", err)
return err
}
if srvconfig.GlobalSetting.SyncOnlineCount == "" {
return nil
}
// 发送 POST 请求
fmt.Printf("上报在线数量:%d\n", count)
_, _ = websrv.TaskPostJson("http://"+srvconfig.GlobalSetting.SyncOnlineCount, paramBytes)
return nil
}
+165
View File
@@ -0,0 +1,165 @@
package wxcore
import (
"encoding/xml"
"time"
"xiawan/wx/api/req"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
"github.com/lunny/log"
)
// WXFileHelperMgr 文件传输助手消息管理器
type WXFileHelperMgr struct {
wxConn wxface.IWXConnect
msgList chan *MsgItem
endChan chan bool
isStarted bool
}
// MsgItem MsgItem
type MsgItem struct {
TextMsg string
ImageData []byte
MsgType uint32
}
// NewWXFileHelperMgr 新建文件传输助手管理器
func NewWXFileHelperMgr(wxConn wxface.IWXConnect) *WXFileHelperMgr {
return &WXFileHelperMgr{
wxConn: wxConn,
msgList: make(chan *MsgItem, 100),
endChan: make(chan bool, 1),
isStarted: false,
}
}
// Start 开启
func (wxfhm *WXFileHelperMgr) Start() {
if wxfhm.isStarted {
return
}
wxfhm.isStarted = true
go wxfhm.startDealMsg()
}
// Stop 关闭
func (wxfhm *WXFileHelperMgr) Stop() {
wxfhm.isStarted = false
wxfhm.endChan <- true
wxfhm.isStarted = false
}
// AddNewTipMsg 新增提示
func (wxfhm *WXFileHelperMgr) AddNewTipMsg(newMsg string) {
if wxfhm.isStarted {
newMsgItem := &MsgItem{}
newMsgItem.MsgType = 1
newMsgItem.TextMsg = newMsg
wxfhm.msgList <- newMsgItem
}
}
// 新增名片消息 AddNewCardMsg
func (wxfhm *WXFileHelperMgr) AddNewCardMsg(newMsg string) {
if wxfhm.isStarted {
newMsgItem := &MsgItem{}
newMsgItem.MsgType = 42
newMsgItem.TextMsg = newMsg
wxfhm.msgList <- newMsgItem
}
}
// AddImageMsg 新增图片消息
func (wxfhm *WXFileHelperMgr) AddImageMsg(imgData []byte) {
if wxfhm.isStarted {
newMsgItem := &MsgItem{}
newMsgItem.MsgType = 2
newMsgItem.ImageData = imgData
wxfhm.msgList <- newMsgItem
}
}
// 转发图片
func (wxfhm *WXFileHelperMgr) ForwardImageMsg(imgData []byte) {
if wxfhm.isStarted {
newMsgItem := &MsgItem{}
newMsgItem.MsgType = 3
newMsgItem.ImageData = imgData
wxfhm.msgList <- newMsgItem
}
}
// 转发表情
func (wxfhm *WXFileHelperMgr) ForwardEmoticonMsg(imgData []byte) {
if wxfhm.isStarted {
newMsgItem := &MsgItem{}
newMsgItem.MsgType = 47
newMsgItem.ImageData = imgData
wxfhm.msgList <- newMsgItem
}
}
// 处理消息
func (wxfhm *WXFileHelperMgr) startDealMsg() {
defer TryE("(wxfhm *WXFileHelperMgr) startDealMsg()")
currentReqInvoker := wxfhm.wxConn.GetWXReqInvoker()
for {
// 最少1秒发送一次
time.Sleep(1 * time.Second)
select {
case newMsgItem := <-wxfhm.msgList:
if newMsgItem.MsgType == 1 {
// 文字
currentReqInvoker.SendTextMsgToFileHelperRequest(newMsgItem.TextMsg)
} else if newMsgItem.MsgType == 2 {
// 图片
currentReqInvoker.SendImageToFileHelper(newMsgItem.ImageData)
} else if newMsgItem.MsgType == 42 {
// 名片
// 发送消息
currentReqInvoker.SendCardMsgToFileHelperRequest(newMsgItem.TextMsg)
// currentReqInvoker.SendCardMsgToFileHelper(newMsgItem.TextMsg)
} else if newMsgItem.MsgType == 3 {
// 图片
var msg baseinfo.Msg3
err := xml.Unmarshal(newMsgItem.ImageData, &msg)
if err != nil {
log.Fatalf("Error parsing XML: %v", err)
return
}
if msg.Img.CdnThumbURL != "" {
sendMsg := baseinfo.ForwardImageItem{
ToUserName: baseinfo.FileHelperWXID,
AesKey: msg.Img.AESKey,
CdnMidImgUrl: msg.Img.CdnThumbURL,
CdnMidImgSize: msg.Img.CdnThumbLength,
CdnThumbImgSize: msg.Img.Length,
}
_, _ = currentReqInvoker.ForwardCdnImageRequest(sendMsg)
}
} else if newMsgItem.MsgType == 47 {
// 表情
var msg baseinfo.Msg47
err := xml.Unmarshal(newMsgItem.ImageData, &msg)
if err != nil {
log.Fatalf("Error parsing XML: %v", err)
return
}
if msg.Emoji.MD5 != "" {
sendMsg := req.SendEmojiItem{
ToUserName: baseinfo.FileHelperWXID,
EmojiMd5: msg.Emoji.MD5,
EmojiSize: msg.Emoji.Len,
}
_, _ = currentReqInvoker.ForwardEmojiRequest(sendMsg.EmojiMd5, sendMsg.ToUserName, sendMsg.EmojiSize)
}
}
case <-wxfhm.endChan:
return
}
}
}
+17
View File
@@ -0,0 +1,17 @@
package wxcore
// WXLongRequest 微信长链接请求
type WXLongRequest struct {
OpCode uint32
Data []byte
}
// GetOpcode 获取Opcode
func (wxlq *WXLongRequest) GetOpcode() uint32 {
return wxlq.OpCode
}
// GetData 获取数据
func (wxlq *WXLongRequest) GetData() []byte {
return wxlq.Data
}
+101
View File
@@ -0,0 +1,101 @@
package wxcore
import (
"fmt"
"xiawan/wx/srv/srvconfig"
"xiawan/wx/srv/wxface"
)
// WXMsgHandler 微信响应管理器
type WXMsgHandler struct {
wxRouterMap map[uint32]wxface.IWXRouter //存放每个MsgId 所对应的处理方法的map属性
wxWorkerPoolSize uint32 //业务工作Worker池的数量
wxTaskQueue []chan wxface.IWXResponse //Worker负责取任务的消息队列
}
// NewWXMsgHandler 新建微信消息处理器
func NewWXMsgHandler() *WXMsgHandler {
return &WXMsgHandler{
wxRouterMap: make(map[uint32]wxface.IWXRouter),
// 一个worker对应一个queue
wxWorkerPoolSize: srvconfig.GlobalSetting.WorkerPoolSize * 2,
wxTaskQueue: make([]chan wxface.IWXResponse, srvconfig.GlobalSetting.WorkerPoolSize*2),
}
}
// AddRouter 增加微信消息路由
func (wxmh *WXMsgHandler) AddRouter(respID uint32, wxRouter wxface.IWXRouter) {
//1 判断当前msg绑定的API处理方法是否已经存在
if _, ok := wxmh.wxRouterMap[respID]; ok {
return
}
//2 添加msg与api的绑定关系
wxmh.wxRouterMap[respID] = wxRouter
}
// GetRouterByRespID 根据响应ID获取对应的路由
func (wxmh *WXMsgHandler) GetRouterByRespID(urlID uint32) wxface.IWXRouter {
handler, ok := wxmh.wxRouterMap[urlID]
if !ok {
return nil
}
return handler
}
// doMsgHandler 马上以非阻塞方式处理消息
func (wxmh *WXMsgHandler) doMsgHandler(response wxface.IWXResponse) {
//xiaoyue处理消息
// fmt.Println("xiaoyue------doMsgHandler")
// defer TryE(response.GetWXConncet().GetWXAccount().GetUserInfo().GetUserName())
handler, ok := wxmh.wxRouterMap[response.GetPackHeader().URLID]
// fmt.Println("[URLID]", response.GetPackHeader().URLID)
if !ok {
return
}
//执行对应处理方法
handler.PreHandle(response)
handler.Handle(response)
handler.PostHandle(response)
}
// startOneWorker 启动一个Worker工作流程
func (wxmh *WXMsgHandler) startOneWorker(workerID int, taskQueue chan wxface.IWXResponse) {
// fmt.Println("xiaoyue------startOneWorker")
defer func() {
if r := recover(); r != nil {
fmt.Printf("startOneWorker recovered from panic: %v\n", r)
// 可以在这里记录日志或执行其他紧急恢复处理措施
}
}()
//不断的等待队列中的消息
for {
select {
//有消息则取出队列的Request,并执行绑定的业务方法
case request := <-taskQueue:
wxmh.doMsgHandler(request)
}
}
}
// StartWorkerPool 启动worker工作池
func (wxmh *WXMsgHandler) StartWorkerPool() {
defer TryE("")
// fmt.Println("xiaoyue------StartWorkerPool")
//遍历需要启动worker的数量,依此启动
for i := 0; i < int(wxmh.wxWorkerPoolSize); i++ {
//一个worker被启动
//给当前worker对应的任务队列开辟空间
wxmh.wxTaskQueue[i] = make(chan wxface.IWXResponse, srvconfig.GlobalSetting.MaxWorkerTaskLen*2)
//启动当前Worker,阻塞的等待对应的任务队列是否有消息传递进来
go wxmh.startOneWorker(i, wxmh.wxTaskQueue[i])
}
}
// SendWXRespToTaskQueue 将消息交给TaskQueue,由worker进行处理
func (wxmh *WXMsgHandler) SendWXRespToTaskQueue(response wxface.IWXResponse) {
//得到需要处理此条连接的workerID
workerID := response.GetWXConncet().GetWXConnID() % wxmh.wxWorkerPoolSize
//将请求消息发送给任务队列
wxmh.wxTaskQueue[workerID] <- response
}
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
package wxcore
import (
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// WXResponse 微信响应
type WXResponse struct {
wxConn wxface.IWXConnect
packHeader *baseinfo.PackHeader
//业务日志Id
LogUUID string
}
// NewWXResponse 新建WXResponse
func NewWXResponse(wxConn wxface.IWXConnect, packHeader *baseinfo.PackHeader) wxface.IWXResponse {
return &WXResponse{
wxConn: wxConn,
packHeader: packHeader,
}
}
// GetPackHeader 获取响应数据
func (resp *WXResponse) GetPackHeader() *baseinfo.PackHeader {
return resp.packHeader
}
// GetWXConncet 获取WXConncet
func (resp *WXResponse) GetWXConncet() wxface.IWXConnect {
return resp.wxConn
}
+78
View File
@@ -0,0 +1,78 @@
package wxcore
import (
// "fmt"
"xiawan/wx/srv"
"xiawan/wx/srv/wxface"
)
// WXServer 微信服务器,处理与微信的交互
type WXServer struct {
wxMsgHandler wxface.IWXMsgHandler
wxConnectMgr wxface.IWXConnectMgr
wxFileMgr *srv.WXFileMgr
}
// NewWXServer 新建微信服务对象
func NewWXServer() wxface.IWXServer {
return &WXServer{
wxMsgHandler: NewWXMsgHandler(),
wxConnectMgr: NewWXConnManager(),
wxFileMgr: srv.NewWXFileMgr(),
}
}
// Start 开启微信服务
func (wxs *WXServer) Start() {
defer TryE("(wxtm *WXServer) Start()")
// fmt.Println("xiaoyue--------start开启微信服务")
// 开启微信消息线程池
wxs.wxMsgHandler.StartWorkerPool()
//wxs.wxFileMgr.Start()
}
// GetWXMsgHandler 获取微信消息管理器
func (wxs *WXServer) GetWXMsgHandler() wxface.IWXMsgHandler {
return wxs.wxMsgHandler
}
// GetWXConnectMgr 获取微信链接管理器
func (wxs *WXServer) GetWXConnectMgr() wxface.IWXConnectMgr {
return wxs.wxConnectMgr
}
// GetWXFileMgr 获取微信文件管理器
func (wxs *WXServer) GetWXFileMgr() *srv.WXFileMgr {
return wxs.wxFileMgr
}
// AddWXRouter 添加微信消息路由
func (wxs *WXServer) AddWXRouter(funcID uint32, wxRouter wxface.IWXRouter) {
wxs.wxMsgHandler.AddRouter(funcID, wxRouter)
}
// UpdateExpiryDate 更新授权码过期时间
func (wxs *WXServer) UpdateExpiryDate(key, expiryDate string) {
connMgr := wxs.GetWXConnectMgr()
wxConn := connMgr.GetWXConnectByUserInfoUUID(key)
if wxConn == nil {
return
}
currentTaskMgr := wxConn.GetWXTaskMgr()
taskMgr, _ := currentTaskMgr.(*WXTaskMgr)
currentSnsTransTask := taskMgr.GetSnsTransTask()
currentSnsTransTask.SetExpiryDate(expiryDate)
}
// UpdateDisable 更新授权码禁用状态
func (wxs *WXServer) UpdateDisable(key string, disable int) {
connMgr := wxs.GetWXConnectMgr()
wxConn := connMgr.GetWXConnectByUserInfoUUID(key)
if wxConn == nil {
return
}
currentTaskMgr := wxConn.GetWXTaskMgr()
taskMgr, _ := currentTaskMgr.(*WXTaskMgr)
currentSnsTransTask := taskMgr.GetSnsTransTask()
currentSnsTransTask.SetDisable(disable)
}
+110
View File
@@ -0,0 +1,110 @@
package wxcore
import (
"time"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
)
// WXSyncMgr 同步管理器(同步消息,同步收藏等等)
type WXSyncMgr struct {
wxConn wxface.IWXConnect
newSyncIDList chan uint32
favSyncIDList chan uint32
newInitIDList chan uint32
endNewChan chan bool
endFavChan chan bool
endInitChan chan bool
isStart bool
}
// NewWXSyncMgr 新建同步管理器
func NewWXSyncMgr(wxConn wxface.IWXConnect) wxface.IWXSyncMgr {
return &WXSyncMgr{
wxConn: wxConn,
newSyncIDList: make(chan uint32, 100),
favSyncIDList: make(chan uint32, 100),
newInitIDList: make(chan uint32, 200),
endNewChan: make(chan bool, 1),
endFavChan: make(chan bool, 1),
endInitChan: make(chan bool, 1),
isStart: false,
}
}
// Start 开启管理器
func (wxsm *WXSyncMgr) Start() {
if wxsm.isStart {
return
}
wxsm.isStart = true
go wxsm.startNewSyncListener()
go wxsm.startFavSyncListener()
// go wxsm.startInitSyncListener()
}
// Stop 关闭管理器
func (wxsm *WXSyncMgr) Stop() {
wxsm.isStart = false
wxsm.endNewChan <- true
wxsm.endFavChan <- true
wxsm.endInitChan <- true
}
// SendNewSyncRequest 发送同步消息请求
func (wxsm *WXSyncMgr) SendNewSyncRequest() {
wxsm.newSyncIDList <- 1
}
// SendFavSyncRequest 发送同步收藏请求
func (wxsm *WXSyncMgr) SendFavSyncRequest() {
wxsm.favSyncIDList <- 1
}
func (wxsm *WXSyncMgr) SendSyncInitRequest() {
wxsm.newInitIDList <- 1
}
func (wxsm *WXSyncMgr) startNewSyncListener() {
//处理异常
defer TryE(wxsm.wxConn.GetWXAccount().GetUserInfo().GetUserName())
currentReqInvoker := wxsm.wxConn.GetWXReqInvoker()
for {
select {
case <-wxsm.newSyncIDList:
// 同步消息
currentReqInvoker.SendNewSyncRequest(baseinfo.MMSyncSceneTypeNeed)
case <-wxsm.endNewChan:
return
}
}
}
func (wxsm *WXSyncMgr) startFavSyncListener() {
currentReqInvoker := wxsm.wxConn.GetWXReqInvoker()
for {
// 3秒执行一次
time.Sleep(1 * time.Second)
select {
case <-wxsm.favSyncIDList:
// 同步收藏
currentReqInvoker.SendFavSyncRequest()
case <-wxsm.endFavChan:
return
}
}
}
func (wxsm *WXSyncMgr) startInitSyncListener() {
currentReqInvoker := wxsm.wxConn.GetWXReqInvoker()
for {
select {
case <-wxsm.newInitIDList:
// 同步收藏
_ = currentReqInvoker.SendNewInitSyncRequest()
case <-wxsm.endInitChan:
return
}
}
}
+108
View File
@@ -0,0 +1,108 @@
package wxcore
import (
"fmt"
"xiawan/wx/srv/wxface"
"xiawan/wx/srv/wxtask"
)
// WXTaskMgr 任务管理器
type WXTaskMgr struct {
start bool
wxConn wxface.IWXConnect
friendTask *wxtask.WXFriendTask
groupTask *wxtask.WXGroupTask
grabHBTask *wxtask.WXGrabHBTask
snsTransTask *wxtask.WXSnsTransTask
revokeTask *wxtask.WXRevokeTask
snsTask *wxtask.WXSnsTask
verifyTask *wxtask.WXVerifyTask
SocketMsgTask *wxtask.WXSocketMsgTask
}
// NewWXTaskMgr 新建一个微信管理器
func NewWXTaskMgr(wxConn wxface.IWXConnect) wxface.IWXTaskMgr {
return &WXTaskMgr{
wxConn: wxConn,
friendTask: wxtask.NewWXFriendTask(wxConn),
groupTask: wxtask.NewWXGroupTask(wxConn),
grabHBTask: wxtask.NewWXGrabHBTask(wxConn),
snsTransTask: wxtask.NewWXSnsTransTask(wxConn),
revokeTask: wxtask.NewWXRevokeTask(wxConn),
snsTask: wxtask.NewWXSnsTask(wxConn),
verifyTask: wxtask.NewWXVerifyTask(wxConn),
SocketMsgTask: wxtask.NewWXSocketMsgTask(wxConn),
}
}
// Start 启动
func (wxtm *WXTaskMgr) Start() {
fmt.Println("启动微信任务管理器")
//处理异常
// defer TryE("(wxtm *WXTaskMgr) Start()")
if wxtm.start {
return
}
wxtm.start = true
// wxtm.grabHBTask.Start()
wxtm.snsTransTask.Start()
// wxtm.revokeTask.Start()
wxtm.snsTask.Start()
wxtm.SocketMsgTask.Start()
}
// Stop 关闭
func (wxtm *WXTaskMgr) Stop() {
if !wxtm.start {
return
}
wxtm.start = false
// wxtm.grabHBTask.Stop()
wxtm.snsTransTask.Stop()
// wxtm.revokeTask.Stop()
wxtm.snsTask.Stop()
wxtm.SocketMsgTask.Stop()
}
func (wxtm *WXTaskMgr) GetTaskStatus() bool {
return wxtm.start
}
// GetGroupTask 获取群任务管理器
func (wxtm *WXTaskMgr) GetGroupTask() *wxtask.WXGroupTask {
return wxtm.groupTask
}
// GetFriendTask 获取好友任务管理器
func (wxtm *WXTaskMgr) GetFriendTask() *wxtask.WXFriendTask {
return wxtm.friendTask
}
// GetGrabHBTask 获取红包任务管理器
func (wxtm *WXTaskMgr) GetGrabHBTask() *wxtask.WXGrabHBTask {
return wxtm.grabHBTask
}
func (wxtm *WXTaskMgr) GetSocketMsgTask() *wxtask.WXSocketMsgTask {
return wxtm.SocketMsgTask
}
// GetSnsTransTask 获取朋友圈转发任务管理器
func (wxtm *WXTaskMgr) GetSnsTransTask() *wxtask.WXSnsTransTask {
return wxtm.snsTransTask
}
// GetRevokeTask 获取防撤回消息任务管理器
func (wxtm *WXTaskMgr) GetRevokeTask() *wxtask.WXRevokeTask {
return wxtm.revokeTask
}
// GetSnsTask 获取朋友圈任务管理器
func (wxtm *WXTaskMgr) GetSnsTask() *wxtask.WXSnsTask {
return wxtm.snsTask
}
// GetVerifyTask 获取朋友圈任务管理器
func (wxtm *WXTaskMgr) GetVerifyTask() *wxtask.WXVerifyTask {
return wxtm.verifyTask
}
+18
View File
@@ -0,0 +1,18 @@
package wxcore
import (
"fmt"
"time"
)
// 异常处理
func TryE(userName string) {
errs := recover()
if errs == nil {
return
}
now := time.Now() //获取当前时间
timeFormat := now.Format("2006-01-02 15:04:05") //设定时间格式
fileName := fmt.Sprintf("[%s]-%s-%vrn", userName, timeFormat, errs) //保存错误信息文件名:程序名-进程ID-当前时间(年月日时分秒)
fmt.Println("error: ", fileName)
}
+150
View File
@@ -0,0 +1,150 @@
package wxcore
import (
"encoding/xml"
"time"
"xiawan/wx/api/req"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/srv/wxface"
"github.com/lunny/log"
)
// WXUSerMsgMgr WX用户消息管理器
type WXUSerMsgMgr struct {
wxConn wxface.IWXConnect
msgList chan *USerMsgItem
endChan chan bool
isStarted bool
}
// USerMsgItem MsgItem
type USerMsgItem struct {
TextMsg string
ImageData []byte
MsgType uint32
TOUserName string
}
// NewWXFileHelperMgr 新建用户消息管理器
func NewWXUSerMsgMgr(wxConn wxface.IWXConnect) *WXUSerMsgMgr {
return &WXUSerMsgMgr{
wxConn: wxConn,
msgList: make(chan *USerMsgItem, 100),
endChan: make(chan bool, 1),
isStarted: false,
}
}
// Start 开启
func (wxfhm *WXUSerMsgMgr) Start() {
if wxfhm.isStarted {
return
}
wxfhm.isStarted = true
go wxfhm.startDealMsg()
}
// Stop 关闭
func (wxfhm *WXUSerMsgMgr) Stop() {
wxfhm.endChan <- true
wxfhm.isStarted = false
}
// AddNewMsg 新增提示
func (wxfhm *WXUSerMsgMgr) AddNewTextMsg(newMsg, toUSerName string) {
if wxfhm.isStarted {
newMsgItem := &USerMsgItem{}
newMsgItem.TOUserName = toUSerName
newMsgItem.MsgType = 1
newMsgItem.TextMsg = newMsg
wxfhm.msgList <- newMsgItem
}
}
// AddImageMsg 新增图片消息
func (wxfhm *WXUSerMsgMgr) AddImageMsg(imgData []byte, toUSerName string) {
if wxfhm.isStarted {
newMsgItem := &USerMsgItem{}
newMsgItem.TOUserName = toUSerName
newMsgItem.MsgType = 2
newMsgItem.ImageData = imgData
wxfhm.msgList <- newMsgItem
}
}
// 转发图片
func (wxfhm *WXUSerMsgMgr) ForwardImageMsg(imgData []byte, toUSerName string) {
if wxfhm.isStarted {
newMsgItem := &USerMsgItem{}
newMsgItem.TOUserName = toUSerName
newMsgItem.MsgType = 3
newMsgItem.ImageData = imgData
wxfhm.msgList <- newMsgItem
}
}
// 转发表情
func (wxfhm *WXUSerMsgMgr) ForwardEmoticonMsg(imgData []byte, toUSerName string) {
if wxfhm.isStarted {
newMsgItem := &USerMsgItem{}
newMsgItem.TOUserName = toUSerName
newMsgItem.MsgType = 47
newMsgItem.ImageData = imgData
wxfhm.msgList <- newMsgItem
}
}
// 处理消息
func (wxfhm *WXUSerMsgMgr) startDealMsg() {
//处理异常
defer TryE("(wxfhm *WXUSerMsgMgr) startDealMsg()")
currentReqInvoker := wxfhm.wxConn.GetWXReqInvoker()
for {
// 最少1秒发送一次
time.Sleep(1 * time.Second)
select {
case newMsgItem := <-wxfhm.msgList:
if newMsgItem.MsgType == 1 {
// 文字
_, _ = currentReqInvoker.SendTextMsgRequest(newMsgItem.TOUserName, newMsgItem.TextMsg, []string{}, 1)
} else if newMsgItem.MsgType == 2 {
// 图片
_, _ = currentReqInvoker.SendCdnUploadImageReuqest(newMsgItem.ImageData, newMsgItem.TOUserName)
} else if newMsgItem.MsgType == 3 {
// 图片
var msg baseinfo.Msg3
err := xml.Unmarshal(newMsgItem.ImageData, &msg)
if err != nil {
log.Fatalf("Error parsing XML: %v", err)
return
}
sendMsg := baseinfo.ForwardImageItem{
ToUserName: newMsgItem.TOUserName,
AesKey: msg.Img.AESKey,
CdnMidImgUrl: msg.Img.CdnThumbURL,
CdnMidImgSize: msg.Img.CdnThumbLength,
CdnThumbImgSize: msg.Img.Length,
}
_, _ = currentReqInvoker.ForwardCdnImageRequest(sendMsg)
} else if newMsgItem.MsgType == 47 {
// 表情
var msg baseinfo.Msg47
err := xml.Unmarshal(newMsgItem.ImageData, &msg)
if err != nil {
log.Fatalf("Error parsing XML: %v", err)
return
}
sendMsg := req.SendEmojiItem{
ToUserName: newMsgItem.TOUserName,
EmojiMd5: msg.Emoji.MD5,
EmojiSize: msg.Emoji.Len,
}
_, _ = currentReqInvoker.ForwardEmojiRequest(sendMsg.EmojiMd5, sendMsg.ToUserName, sendMsg.EmojiSize)
}
case <-wxfhm.endChan:
return
}
}
}