first commit
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
)
|
||||
|
||||
// MessageWrapper 消息包装结构体,用于WebSocket和callback消息同步时包含UUID信息
|
||||
type MessageWrapper struct {
|
||||
Key string `json:"key"` // UUID标识,用于区分是哪个微信收到的消息
|
||||
Message *wechat.AddMsg `json:"message"` // 原始消息内容
|
||||
Type string `json:"type"` // 消息类型,如"message"、"contact_sync"等
|
||||
}
|
||||
|
||||
// NewMessageWrapper 创建新的消息包装器
|
||||
func NewMessageWrapper(key string, message *wechat.AddMsg, msgType string) *MessageWrapper {
|
||||
return &MessageWrapper{
|
||||
Key: key,
|
||||
Message: message,
|
||||
Type: msgType,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXFriendTask 微信好友任务
|
||||
type WXFriendTask struct {
|
||||
wxConn wxface.IWXConnect
|
||||
friendForList []*wechat.ModContact
|
||||
friendForZombieFansList []*wechat.ModContact
|
||||
labels []*wechat.LabelPair
|
||||
waitTimes uint32 // 毫秒
|
||||
isZombieFansDet bool // 检测僵死粉任务
|
||||
isZombieFansDel bool // 删除僵死粉任务
|
||||
}
|
||||
|
||||
// NewWXFriendTask 新建一个好友任务
|
||||
func NewWXFriendTask(wxConn wxface.IWXConnect) *WXFriendTask {
|
||||
return &WXFriendTask{
|
||||
wxConn: wxConn,
|
||||
friendForList: make([]*wechat.ModContact, 0),
|
||||
friendForZombieFansList: make([]*wechat.ModContact, 0),
|
||||
labels: make([]*wechat.LabelPair, 0),
|
||||
isZombieFansDet: false,
|
||||
isZombieFansDel: false,
|
||||
waitTimes: uint32(1000), // 间隔 1000 毫秒
|
||||
}
|
||||
}
|
||||
|
||||
// 获取下一个待验证的好友
|
||||
func (gpt *WXFriendTask) getNextFriendForContact() *wechat.ModContact {
|
||||
if len(gpt.friendForList) <= 0 {
|
||||
return nil
|
||||
}
|
||||
retContact := gpt.friendForList[0]
|
||||
gpt.friendForList = gpt.friendForList[1:]
|
||||
return retContact
|
||||
}
|
||||
|
||||
// 获取 1500 - 2500 毫秒的随机数
|
||||
func (gpt *WXFriendTask) getRandWaitTimes() int {
|
||||
// 设置随机数种子
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
// 生成 [1500, 2500] 之间的随机数
|
||||
min := 1500
|
||||
max := 2500
|
||||
randomNumber := rand.Intn(max-min+1) + min
|
||||
return randomNumber
|
||||
}
|
||||
|
||||
// 获取 2000 - 4000 毫秒的随机数
|
||||
func (gpt *WXFriendTask) getRandWaitTimes2() int {
|
||||
// 设置随机数种子
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
// 生成 [2000, 4000] 之间的随机数
|
||||
min := 2000
|
||||
max := 4000
|
||||
randomNumber := rand.Intn(max-min+1) + min
|
||||
return randomNumber
|
||||
}
|
||||
|
||||
// 获取 5000 - 12000 毫秒的随机数(5秒 - 12秒)
|
||||
func (gpt *WXFriendTask) getRandWaitTimes3() int {
|
||||
// 设置随机数种子
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
// 生成 [5000, 12000] 之间的随机数
|
||||
min := 5000
|
||||
max := 12000
|
||||
randomNumber := rand.Intn(max-min+1) + min
|
||||
return randomNumber
|
||||
}
|
||||
|
||||
// 10 - 20秒 删除一个
|
||||
// 获取 10000 - 20000 毫秒的随机数
|
||||
func (gpt *WXFriendTask) getRandWaitTimes4() int {
|
||||
// 设置随机数种子
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
// 生成 [10000, 20000] 之间的随机数
|
||||
min := 10000
|
||||
max := 20000
|
||||
randomNumber := rand.Intn(max-min+1) + min
|
||||
return randomNumber
|
||||
}
|
||||
|
||||
// 添加至标签 删除我的人 拉黑我的人
|
||||
func (gpt *WXFriendTask) addTagForContact(labeName string, friendWxids []string) {
|
||||
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
|
||||
// 判断存在则删除,不存在则添加
|
||||
labels := gpt.getTagForList()
|
||||
// 当前标签
|
||||
currentLabel := make([]*wechat.LabelPair, 0)
|
||||
for _, label := range labels {
|
||||
if label.GetLabelName() == labeName {
|
||||
// 删除
|
||||
currentWXReqInvoker.SendDelContactLabelRequest(strconv.FormatUint(uint64(label.GetLabelId()), 10))
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(currentLabel) <= 0 {
|
||||
// 添加标签
|
||||
labelNames := make([]string, 0)
|
||||
labelNames = append(labelNames, labeName)
|
||||
resp, err := currentWXReqInvoker.SendAddContactLabelRequest(labelNames, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
currentLabel = resp.GetLabelPairList()
|
||||
}
|
||||
// 修改标签
|
||||
if len(currentLabel) > 0 {
|
||||
UserLabelList := make([]baseinfo.UserLabelInfoItem, 0)
|
||||
|
||||
for _, friendWxid := range friendWxids {
|
||||
userLabel := baseinfo.UserLabelInfoItem{
|
||||
UserName: friendWxid,
|
||||
LabelIDList: strconv.FormatUint(uint64(currentLabel[0].GetLabelId()), 10),
|
||||
}
|
||||
UserLabelList = append(UserLabelList, userLabel)
|
||||
}
|
||||
|
||||
currentWXReqInvoker.SendModifyLabelRequest(UserLabelList)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取全部标签
|
||||
func (gpt *WXFriendTask) getTagForList() []*wechat.LabelPair {
|
||||
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
|
||||
// 获取标签
|
||||
resp, err := currentWXReqInvoker.SendGetContactLabelListRequest(true)
|
||||
if err != nil {
|
||||
return make([]*wechat.LabelPair, 0)
|
||||
}
|
||||
return resp.GetLabelPairList()
|
||||
}
|
||||
|
||||
// 获取剩余僵死粉数量
|
||||
// GetLessCount 获取剩余群聊数量
|
||||
func (gpt *WXFriendTask) GetLessCount() uint32 {
|
||||
return uint32(len(gpt.friendForZombieFansList))
|
||||
}
|
||||
|
||||
// StartFriendTask 开启好友检测任务
|
||||
func (gpt *WXFriendTask) StartFriendTask(taskType int) bool {
|
||||
// currentWXAccount := gpt.wxConn.GetWXAccount()
|
||||
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
|
||||
currentWXFileHelperMgr := gpt.wxConn.GetWXFileHelperMgr()
|
||||
// 如果正在执行执行任务,则返回
|
||||
if gpt.isZombieFansDet {
|
||||
tipText := "正在检测僵死粉,请稍后"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
return false
|
||||
}
|
||||
// 如果正在执行删除任务,则返回
|
||||
if gpt.isZombieFansDel {
|
||||
tipText := "正在清理僵死粉,请稍后"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
return false
|
||||
}
|
||||
|
||||
if taskType == 1 {
|
||||
gpt.isZombieFansDet = true
|
||||
tmpTip := "执行检测僵死粉\n开始加载好友列表……"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tmpTip)
|
||||
}
|
||||
|
||||
if taskType == 2 {
|
||||
gpt.isZombieFansDel = true
|
||||
tmpTip := "执行清理僵死粉\n开始加载好友……"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tmpTip)
|
||||
}
|
||||
gpt.friendForList = make([]*wechat.ModContact, 0)
|
||||
gpt.friendForZombieFansList = make([]*wechat.ModContact, 0)
|
||||
|
||||
friendWxids := gpt.GetFriendWxidList()
|
||||
// friendList := make([]*wechat.ModContact, 0)
|
||||
|
||||
go func() {
|
||||
if len(friendWxids) <= 0 {
|
||||
tipText := "好友检索完成,总数 0 个,无需操作"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
gpt.isZombieFansDel = false
|
||||
gpt.isZombieFansDet = false
|
||||
return
|
||||
}
|
||||
|
||||
// 好友检索完成,好友总数:
|
||||
tipText := "好友加载完成!!\n开始检测好友,请耐心等待……"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
|
||||
for i := 0; i < len(friendWxids); i += 1 {
|
||||
// 获取详情
|
||||
friend := new(wechat.ModContact)
|
||||
friend.UserName = new(wechat.SKBuiltinString)
|
||||
friend.Remark = new(wechat.SKBuiltinString)
|
||||
friend.UserName.Str = new(string)
|
||||
*friend.UserName.Str = friendWxids[i]
|
||||
gpt.friendForList = append(gpt.friendForList, friend)
|
||||
}
|
||||
temFriendCount := 0
|
||||
for {
|
||||
// 先判断是否还处于链接当中
|
||||
if !gpt.wxConn.IsConnected() {
|
||||
gpt.isZombieFansDel = false
|
||||
gpt.isZombieFansDet = false
|
||||
return
|
||||
}
|
||||
// 获取下一个好友
|
||||
tmpModContact := gpt.getNextFriendForContact()
|
||||
temFriendCount++
|
||||
if tmpModContact == nil {
|
||||
zembieFansCount := len(gpt.friendForZombieFansList)
|
||||
friendForZombieFansList := make([]*wechat.ModContact, 0)
|
||||
friendNamesDel := ""
|
||||
friendWxidsDel := make([]string, 0)
|
||||
// 拉黑我的人
|
||||
friendFroBlack := ""
|
||||
friendWxidsBlack := make([]string, 0)
|
||||
|
||||
if zembieFansCount > 0 {
|
||||
// jsonStr0, _ := json.Marshal(gpt.friendForList)
|
||||
// fmt.Println(string(jsonStr0))
|
||||
for i := 0; i < zembieFansCount; i += 20 {
|
||||
end := i + 20
|
||||
if end > len(gpt.friendForZombieFansList) {
|
||||
end = len(gpt.friendForZombieFansList)
|
||||
}
|
||||
oldFriends := gpt.friendForZombieFansList[i:end]
|
||||
friendWxids := make([]string, 0)
|
||||
for _, tmpFriend := range oldFriends {
|
||||
friendWxids = append(friendWxids, tmpFriend.GetUserName().GetStr())
|
||||
}
|
||||
// 获取详情
|
||||
contactList, err := currentWXReqInvoker.SendGetContactRequestForList(friendWxids, nil)
|
||||
if err != nil {
|
||||
fmt.Println("获取好友详情失败:", err)
|
||||
continue
|
||||
}
|
||||
// 先判断是否还处于链接当中
|
||||
if !gpt.wxConn.IsConnected() {
|
||||
gpt.isZombieFansDel = false
|
||||
gpt.isZombieFansDet = false
|
||||
return
|
||||
}
|
||||
// friends := contactList.GetContactList()
|
||||
verifyUserList := contactList.GetVerifyUserValidTicketList()
|
||||
friends := contactList.GetContactList()
|
||||
// 转 json 并写入文件
|
||||
// jsonStr, _ := json.Marshal(friends)
|
||||
// fmt.Println(string(jsonStr))
|
||||
|
||||
// jsonStr2, _ := json.Marshal(verifyUserList)
|
||||
// fmt.Println(string(jsonStr2))
|
||||
count := len(friends)
|
||||
for index := 0; index < count; index++ {
|
||||
friendItem := friends[index]
|
||||
verifyUserItem := verifyUserList[index]
|
||||
CardWxId := friendItem.GetUserName().GetStr()
|
||||
CardNickName := friendItem.GetNickName().GetStr()
|
||||
// CardAlias := friendItem.GetAlias()
|
||||
// 联系人
|
||||
// 如果是僵死粉
|
||||
if strings.HasPrefix(verifyUserItem.GetAntispamticket(), "v4_") && friendItem.GetHeadImgMd5() != "" {
|
||||
if friendNamesDel != "" {
|
||||
friendNamesDel += "\n"
|
||||
}
|
||||
friendItem.Remark = new(wechat.SKBuiltinString)
|
||||
friendItem.Remark.Str = new(string)
|
||||
*friendItem.Remark.Str = "删除我的人"
|
||||
friendNamesDel += "删除我的人"
|
||||
friendNamesDel += ("【" + CardNickName + "】")
|
||||
friendWxidsDel = append(friendWxidsDel, CardWxId)
|
||||
// baseutils.PrintLog("僵尸粉:" + tmpContact.GetNickName().GetStr())
|
||||
} else {
|
||||
// 拉黑
|
||||
if friendFroBlack != "" {
|
||||
friendFroBlack += "\n"
|
||||
}
|
||||
friendItem.Remark = new(wechat.SKBuiltinString)
|
||||
friendItem.Remark.Str = new(string)
|
||||
*friendItem.Remark.Str = "拉黑我的人"
|
||||
friendFroBlack += "拉黑我的人"
|
||||
friendFroBlack += ("【" + CardNickName + "】")
|
||||
friendWxidsBlack = append(friendWxidsBlack, CardWxId)
|
||||
}
|
||||
friendForZombieFansList = append(friendForZombieFansList, friendItem)
|
||||
|
||||
}
|
||||
// 暂停 1.5 - 2.5 秒
|
||||
randWaitTime := gpt.getRandWaitTimes()
|
||||
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到标签
|
||||
// 发送名单列表
|
||||
if friendNamesDel != "" {
|
||||
gpt.addTagForContact("删除我的人", friendWxidsDel)
|
||||
currentWXFileHelperMgr.AddNewTipMsg(friendNamesDel)
|
||||
}
|
||||
if friendFroBlack != "" {
|
||||
gpt.addTagForContact("拉黑我的人", friendWxidsBlack)
|
||||
currentWXFileHelperMgr.AddNewTipMsg(friendFroBlack)
|
||||
}
|
||||
|
||||
tipText := "检测完成 \n"
|
||||
tipText += "删除我的人 - 【" + strconv.Itoa(len(friendWxidsDel)) + "】个\n"
|
||||
tipText += "拉黑我的人 - 【" + strconv.Itoa(len(friendWxidsBlack)) + "】个\n"
|
||||
tipText += "僵死粉已标记到标签中,以便查看"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
|
||||
gpt.isZombieFansDet = false
|
||||
if gpt.isZombieFansDel {
|
||||
tipText := "由于官方限制,删除好友所需时间较长,请耐心等待……,请勿退出 Ipad 登录!!"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
// 暂停 1 - 2 分钟
|
||||
randWaitTime := gpt.getRandWaitTimes3()
|
||||
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
|
||||
// 删除僵死粉
|
||||
for _, friendWxid := range friendWxidsDel {
|
||||
// 删除
|
||||
err := currentWXReqInvoker.SendDelContactRequest(friendWxid)
|
||||
if err != nil {
|
||||
gpt.isZombieFansDet = false
|
||||
gpt.isZombieFansDel = false
|
||||
fmt.Printf("删除好友 del friend err %+v", err)
|
||||
return
|
||||
}
|
||||
for _, friendRemak := range friendForZombieFansList {
|
||||
if friendRemak.GetUserName().GetStr() == friendWxid {
|
||||
tipText := "删除-删除我的人【" + friendRemak.GetNickName().GetStr() + "】"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
}
|
||||
}
|
||||
// 暂停 10s - 20s
|
||||
randWaitTime := gpt.getRandWaitTimes4()
|
||||
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
|
||||
}
|
||||
for _, friendWxid := range friendWxidsBlack {
|
||||
// 删除
|
||||
err := currentWXReqInvoker.SendDelContactRequest(friendWxid)
|
||||
if err != nil {
|
||||
gpt.isZombieFansDet = false
|
||||
gpt.isZombieFansDel = false
|
||||
fmt.Printf("删除好友 del friend err %+v", err)
|
||||
return
|
||||
}
|
||||
for _, friendRemak := range friendForZombieFansList {
|
||||
if friendRemak.GetUserName().GetStr() == friendWxid {
|
||||
tipText := "删除-拉黑我的人【" + friendRemak.GetNickName().GetStr() + "】"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
}
|
||||
}
|
||||
|
||||
// 暂停 2 - 5 分钟
|
||||
randWaitTime := gpt.getRandWaitTimes3()
|
||||
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
|
||||
}
|
||||
gpt.isZombieFansDet = false
|
||||
gpt.isZombieFansDel = false
|
||||
tipText = "清理完成【已清理】:" + strconv.Itoa(len(friendWxidsDel)+len(friendWxidsBlack))
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 判断每次超过 25 个好友,则返回%分比进度
|
||||
if temFriendCount%25 == 0 {
|
||||
// 取整 temFriendCount / len(friendWxids) * 100 去掉小数点
|
||||
numCount := int(float64(temFriendCount) / float64(len(friendWxids)) * 100)
|
||||
tipText := "已检测【" + strconv.Itoa(numCount) + "%】好友"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
}
|
||||
// 获取好友关系请求
|
||||
friendUserName := tmpModContact.GetUserName().GetStr()
|
||||
// 微信团队跳过
|
||||
if friendUserName == "Weixin" {
|
||||
continue
|
||||
}
|
||||
// 判断是否是僵死粉
|
||||
resp, err := currentWXReqInvoker.SendGetFriendRelationRequest(friendUserName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if resp.GetFriendRelation() == 0 {
|
||||
continue
|
||||
}
|
||||
// 1:删除 4:自己拉黑 5:被拉黑
|
||||
if resp.GetFriendRelation() == 1 {
|
||||
tmpModContact.Remark.Str = new(string)
|
||||
*tmpModContact.Remark.Str = "删除我的人"
|
||||
// 添加到僵尸粉列表
|
||||
gpt.friendForZombieFansList = append(gpt.friendForZombieFansList, tmpModContact)
|
||||
}
|
||||
if resp.GetFriendRelation() == 5 {
|
||||
tmpModContact.Remark.Str = new(string)
|
||||
*tmpModContact.Remark.Str = "拉黑我的人"
|
||||
// 添加到僵尸粉列表
|
||||
gpt.friendForZombieFansList = append(gpt.friendForZombieFansList, tmpModContact)
|
||||
}
|
||||
// 暂停 1.5 - 2.5 秒
|
||||
randWaitTime := gpt.getRandWaitTimes()
|
||||
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取联系人
|
||||
func (gpt *WXFriendTask) GetFriendWxidList() []string {
|
||||
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
|
||||
currentWXFileHelperMgr := gpt.wxConn.GetWXFileHelperMgr()
|
||||
CurrentWxcontactSeq := uint32(0)
|
||||
CurrentChatRoomContactSeq := uint32(0)
|
||||
friendUserNames := make([]string, 0)
|
||||
pages := 0
|
||||
// 死循环
|
||||
for {
|
||||
pages++
|
||||
resp, err := currentWXReqInvoker.SendGetContactListPageRequest(CurrentWxcontactSeq, CurrentChatRoomContactSeq)
|
||||
if err != nil {
|
||||
return friendUserNames
|
||||
}
|
||||
UserNameList := resp.GetContactUsernameList()
|
||||
if resp.GetContactUsernameList() == nil {
|
||||
return friendUserNames
|
||||
}
|
||||
if len(UserNameList) == 0 {
|
||||
return friendUserNames
|
||||
}
|
||||
|
||||
tipText := "正在加载第 " + strconv.Itoa(pages) + " 页"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
|
||||
for _, contactUserName := range UserNameList {
|
||||
if contactUserName == "weixin" ||
|
||||
contactUserName == "fmessage" ||
|
||||
contactUserName == "medianote" ||
|
||||
contactUserName == "floatbottle" ||
|
||||
contactUserName == "qqmail" ||
|
||||
contactUserName == "filehelper" ||
|
||||
contactUserName == "mphelper" ||
|
||||
contactUserName == "qmessage" {
|
||||
continue
|
||||
}
|
||||
// 判断 gh 开头
|
||||
if strings.HasPrefix(contactUserName, "gh_") {
|
||||
continue
|
||||
}
|
||||
// 判断 @chatroom 结尾
|
||||
if strings.HasSuffix(contactUserName, "@chatroom") {
|
||||
continue
|
||||
}
|
||||
friendUserNames = append(friendUserNames, contactUserName)
|
||||
}
|
||||
CurrentWxcontactSeq = resp.GetCurrentWxcontactSeq()
|
||||
CurrentChatRoomContactSeq = resp.GetCurrentChatRoomContactSeq()
|
||||
// 暂停 1.5 - 2.5 秒
|
||||
randWaitTime := gpt.getRandWaitTimes()
|
||||
time.Sleep(time.Duration(randWaitTime) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXGrabHBTask 抢红包管理器
|
||||
type WXGrabHBTask struct {
|
||||
wxConn wxface.IWXConnect
|
||||
// 待领红包项列表
|
||||
hongBaoItemChan chan *baseinfo.HongBaoItem
|
||||
// 可不可以抢红包
|
||||
canDoNext chan bool
|
||||
// 结束标志
|
||||
endChan chan bool
|
||||
// 是否正在运行
|
||||
isRunning bool
|
||||
// 当前在抢的红包
|
||||
currentHBItem *baseinfo.HongBaoItem
|
||||
// autoGrap
|
||||
autoGropFlag bool
|
||||
//延迟抢红包
|
||||
delayOpen int
|
||||
//是否自动回复感谢
|
||||
autoReply bool
|
||||
//感谢内容
|
||||
autoReplyContent string
|
||||
//是否过滤测挂
|
||||
filterCheats bool
|
||||
// 过滤测挂关键字
|
||||
filterCheatsKey string
|
||||
//是否过滤文字/字母包
|
||||
filterText bool
|
||||
// 接收个人红包
|
||||
autoPerson bool
|
||||
// 接收转账
|
||||
autoTransfer bool
|
||||
//接收转账后是否自动回复
|
||||
autoTransferReply bool
|
||||
//接收转账后自动回复的内容
|
||||
autoTransferReplyContent string
|
||||
//群是否置顶
|
||||
topGroup map[string]string
|
||||
// 红包统计开关
|
||||
hbStat bool
|
||||
// 转账统计开关
|
||||
transStat bool
|
||||
// 是否只抢置顶群(false 不抢置顶群, true 只抢置顶群)
|
||||
notTopGroup bool
|
||||
mu sync.Mutex // 互斥锁
|
||||
// 是否开启
|
||||
isStart bool
|
||||
}
|
||||
|
||||
// NewWXGrabHBTask 新建抢红包管理器
|
||||
func NewWXGrabHBTask(wxConn wxface.IWXConnect) *WXGrabHBTask {
|
||||
return &WXGrabHBTask{
|
||||
wxConn: wxConn,
|
||||
hongBaoItemChan: make(chan *baseinfo.HongBaoItem, 200),
|
||||
canDoNext: make(chan bool, 1),
|
||||
endChan: make(chan bool, 1),
|
||||
isRunning: false,
|
||||
autoGropFlag: false,
|
||||
delayOpen: 0,
|
||||
autoReply: true,
|
||||
autoReplyContent: "",
|
||||
filterCheats: false,
|
||||
filterText: false,
|
||||
autoPerson: false,
|
||||
autoTransfer: false,
|
||||
filterCheatsKey: "测,挂,cg,死,罚,踢,专",
|
||||
autoTransferReply: true,
|
||||
autoTransferReplyContent: "",
|
||||
topGroup: make(map[string]string),
|
||||
hbStat: false,
|
||||
transStat: false,
|
||||
notTopGroup: false,
|
||||
mu: sync.Mutex{},
|
||||
isStart: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (ghbm *WXGrabHBTask) grapHB() {
|
||||
for {
|
||||
select {
|
||||
case ghbm.currentHBItem = <-ghbm.hongBaoItemChan:
|
||||
// 直接发送抢红包请求,不等待响应
|
||||
go ghbm.wxConn.GetWXReqInvoker().SendOpenRedEnvelopesRequest(ghbm.currentHBItem)
|
||||
// 立即准备抢下一个红包,不等待当前红包处理完成
|
||||
ghbm.GrapNext()
|
||||
return
|
||||
case <-ghbm.endChan:
|
||||
//ghbm.endChan <- true
|
||||
//close(ghbm.endChan)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// startGrap 开始抢红包
|
||||
func (ghbm *WXGrabHBTask) startGrap() {
|
||||
for {
|
||||
select {
|
||||
case <-ghbm.canDoNext:
|
||||
ghbm.grapHB()
|
||||
case <-ghbm.endChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start 开始抢红包协程
|
||||
func (ghbm *WXGrabHBTask) Start() {
|
||||
ghbm.mu.Lock()
|
||||
defer ghbm.mu.Unlock()
|
||||
if ghbm.isStart {
|
||||
return
|
||||
}
|
||||
ghbm.isStart = true
|
||||
go ghbm.startGrap()
|
||||
ghbm.canDoNext <- true
|
||||
}
|
||||
|
||||
// Stop 结束抢红包协程
|
||||
func (ghbm *WXGrabHBTask) Stop() {
|
||||
ghbm.mu.Lock()
|
||||
defer ghbm.mu.Unlock()
|
||||
if !ghbm.isStart {
|
||||
return
|
||||
}
|
||||
ghbm.isStart = false
|
||||
ghbm.endChan <- true
|
||||
//close(ghbm.endChan)
|
||||
}
|
||||
|
||||
// GrapNext 抢下一个红包
|
||||
func (ghbm *WXGrabHBTask) GrapNext() {
|
||||
ghbm.canDoNext <- true
|
||||
}
|
||||
|
||||
// AddHBItem 添加红包项
|
||||
func (ghbm *WXGrabHBTask) AddHBItem(hbItem *baseinfo.HongBaoItem) {
|
||||
// 抢红包操作
|
||||
// ghbm.wxConn.GetWXReqInvoker().SendOpenRedEnvelopesRequest(hbItem)
|
||||
ghbm.hongBaoItemChan <- hbItem
|
||||
if !ghbm.isStart {
|
||||
ghbm.Start()
|
||||
}
|
||||
}
|
||||
|
||||
// 直接接收转账
|
||||
func (ghbm *WXGrabHBTask) DirectTransfer(transferItem *baseinfo.TenPayReqItem, wcPayInfo *baseinfo.WCPayInfo2) {
|
||||
ghbm.wxConn.GetWXReqInvoker().SendReceiveZZ(transferItem, wcPayInfo)
|
||||
}
|
||||
|
||||
// GetCurrentHBItem 获取当前正在抢的红包项
|
||||
func (ghbm *WXGrabHBTask) GetCurrentHBItem() *baseinfo.HongBaoItem {
|
||||
return ghbm.currentHBItem
|
||||
}
|
||||
|
||||
// IsAutoGrap 是否开启了自动抢红包功能
|
||||
func (ghbm *WXGrabHBTask) IsAutoGrap() bool {
|
||||
return ghbm.autoGropFlag
|
||||
}
|
||||
func (ghbm *WXGrabHBTask) IsFilterCheats() bool {
|
||||
return ghbm.filterCheats
|
||||
}
|
||||
func (ghbm *WXGrabHBTask) IsFilterText() bool {
|
||||
return ghbm.filterText
|
||||
}
|
||||
|
||||
// 是否自动接收个人红包
|
||||
func (ghbm *WXGrabHBTask) IsAutoPerson() bool {
|
||||
return ghbm.autoPerson
|
||||
}
|
||||
|
||||
// 是否自动接收转账
|
||||
func (ghbm *WXGrabHBTask) IsAutoTransfer() bool {
|
||||
return ghbm.autoTransfer
|
||||
}
|
||||
|
||||
// 设置是否自动接收个人红包
|
||||
func (ghbm *WXGrabHBTask) SetAutoPerson(bFlag bool) {
|
||||
ghbm.autoPerson = bFlag
|
||||
}
|
||||
|
||||
// 设置是否自动接收转账
|
||||
func (ghbm *WXGrabHBTask) SetAutoTransfer(bFlag bool) {
|
||||
ghbm.autoTransfer = bFlag
|
||||
}
|
||||
|
||||
// SetFilterCheats 过滤测挂开关
|
||||
func (ghbm *WXGrabHBTask) SetFilterCheats(bFlag bool) {
|
||||
ghbm.filterCheats = bFlag
|
||||
}
|
||||
|
||||
// SetFilterCheatsKey 设置过滤测挂关键字
|
||||
func (ghbm *WXGrabHBTask) SetFilterCheatsKey(key string) {
|
||||
ghbm.filterCheatsKey = key
|
||||
}
|
||||
|
||||
// 获取过滤测挂关键字
|
||||
func (ghbm *WXGrabHBTask) GetFilterCheatsKey() string {
|
||||
return ghbm.filterCheatsKey
|
||||
}
|
||||
|
||||
// SetFilterText 过滤文字/字母包开关
|
||||
func (ghbm *WXGrabHBTask) SetFilterText(bFlag bool) {
|
||||
ghbm.filterText = bFlag
|
||||
}
|
||||
|
||||
// 红包统计开关
|
||||
func (ghbm *WXGrabHBTask) SetHBStat(bFlag bool) {
|
||||
ghbm.hbStat = bFlag
|
||||
}
|
||||
|
||||
// 获取红包统计开关
|
||||
func (ghbm *WXGrabHBTask) IsHBStat() bool {
|
||||
return ghbm.hbStat
|
||||
}
|
||||
|
||||
// 转账统计开关
|
||||
func (ghbm *WXGrabHBTask) SetTransStat(bFlag bool) {
|
||||
ghbm.transStat = bFlag
|
||||
}
|
||||
|
||||
// 获取转账统计开关
|
||||
func (ghbm *WXGrabHBTask) IsTransStat() bool {
|
||||
return ghbm.transStat
|
||||
}
|
||||
|
||||
// SetAutoGrap 设置自动抢开关
|
||||
func (ghbm *WXGrabHBTask) SetAutoGrap(bFlag bool) {
|
||||
ghbm.autoGropFlag = bFlag
|
||||
}
|
||||
|
||||
// 设置抢红包自动回复
|
||||
func (ghbm *WXGrabHBTask) SetAutoReply(bFlag bool) {
|
||||
ghbm.autoReply = bFlag
|
||||
}
|
||||
|
||||
// notTopGroup
|
||||
func (ghbm *WXGrabHBTask) SetNotTopGroup(bFlag bool) {
|
||||
ghbm.notTopGroup = bFlag
|
||||
}
|
||||
|
||||
// is
|
||||
func (ghbm *WXGrabHBTask) IsNotTopGroup() bool {
|
||||
return ghbm.notTopGroup
|
||||
}
|
||||
|
||||
// 感谢内容
|
||||
func (ghbm *WXGrabHBTask) SetAutoReplyContent(content string) {
|
||||
ghbm.autoReplyContent = content
|
||||
}
|
||||
|
||||
// 接收转账后自动回复
|
||||
func (ghbm *WXGrabHBTask) SetAutoTransferReply(bFlag bool) {
|
||||
ghbm.autoTransferReply = bFlag
|
||||
}
|
||||
|
||||
// 接收转账后自动回复的内容
|
||||
func (ghbm *WXGrabHBTask) SetAutoTransferReplyContent(content string) {
|
||||
ghbm.autoTransferReplyContent = content
|
||||
}
|
||||
|
||||
// 获取
|
||||
func (ghbm *WXGrabHBTask) GetAutoReplyContent() string {
|
||||
return ghbm.autoReplyContent
|
||||
}
|
||||
|
||||
// 接收转账后自动回复的内容
|
||||
func (ghbm *WXGrabHBTask) GetAutoTransferReplyContent() string {
|
||||
return ghbm.autoTransferReplyContent
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// 是否开启 接收转账后自动回复
|
||||
func (ghbm *WXGrabHBTask) IsAutoTransferReply() bool {
|
||||
return ghbm.autoTransferReply
|
||||
}
|
||||
|
||||
// IsAutoReply 是否开启了自动感谢红包功能
|
||||
func (ghbm *WXGrabHBTask) IsAutoReply() bool {
|
||||
return ghbm.autoReply
|
||||
}
|
||||
|
||||
// 设置延迟抢红包时间
|
||||
func (ghbm *WXGrabHBTask) SetDelayOpen(bFlag int) {
|
||||
ghbm.delayOpen = bFlag
|
||||
}
|
||||
|
||||
// 获取延迟时间
|
||||
func (ghbm *WXGrabHBTask) GetDelayOpen() int {
|
||||
return ghbm.delayOpen
|
||||
}
|
||||
|
||||
// 判断群是否置顶
|
||||
func (ghbm *WXGrabHBTask) IsTopGroup(grouid string) bool {
|
||||
ghbm.mu.Lock()
|
||||
defer ghbm.mu.Unlock()
|
||||
_, exists := ghbm.topGroup[grouid]
|
||||
return exists
|
||||
}
|
||||
|
||||
func (ghbm *WXGrabHBTask) InitTopGroup(uuid string) {
|
||||
ghbm.mu.Lock()
|
||||
defer ghbm.mu.Unlock()
|
||||
topGroup := make(map[string]string)
|
||||
ghbm.topGroup = topGroup
|
||||
|
||||
error := db.GETObj(uuid+"_topGroup", &ghbm.topGroup)
|
||||
if error != nil {
|
||||
}
|
||||
}
|
||||
|
||||
// 记录置顶的群
|
||||
func (ghbm *WXGrabHBTask) RecordTopGroup(grouid string, grouName string) {
|
||||
ghbm.mu.Lock()
|
||||
defer ghbm.mu.Unlock()
|
||||
if ghbm.topGroup == nil {
|
||||
ghbm.topGroup = make(map[string]string)
|
||||
}
|
||||
ghbm.topGroup[grouid] = grouName
|
||||
// 存 redis
|
||||
db.SETExpirationObj(ghbm.wxConn.GetWXAccount().GetUserInfo().UUID+"_topGroup", ghbm.topGroup, -1)
|
||||
}
|
||||
|
||||
// 删除置顶的群
|
||||
func (ghbm *WXGrabHBTask) DelTopGroup(grouid string) {
|
||||
ghbm.mu.Lock()
|
||||
defer ghbm.mu.Unlock()
|
||||
// 如果 topGroup 为 nil,不进行操作
|
||||
if ghbm.topGroup == nil {
|
||||
return
|
||||
}
|
||||
// 删除指定键
|
||||
delete(ghbm.topGroup, grouid)
|
||||
// 存 redis
|
||||
db.SETExpirationObj(ghbm.wxConn.GetWXAccount().GetUserInfo().UUID+"_topGroup", ghbm.topGroup, -1)
|
||||
}
|
||||
|
||||
// 获取全部群名称
|
||||
func (ghbm *WXGrabHBTask) GetTopGroup() string {
|
||||
ghbm.mu.Lock()
|
||||
defer ghbm.mu.Unlock()
|
||||
group := ghbm.topGroup
|
||||
var groupNames string
|
||||
for _, name := range group {
|
||||
groupNames += name + "\n"
|
||||
}
|
||||
return groupNames
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/srvconfig"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXGroupTask 群任务
|
||||
type WXGroupTask struct {
|
||||
wxConn wxface.IWXConnect
|
||||
groupForQrcodeList []*wechat.ModContact
|
||||
groupForAddressBookList []*wechat.ModContact
|
||||
waitTimes uint32 // 毫秒
|
||||
inQrcodeTask bool // 下载群二维码
|
||||
inAddressBookTask bool // 保存群到通讯录任务状态
|
||||
}
|
||||
|
||||
// NewWXGroupTask 新建一个群任务
|
||||
func NewWXGroupTask(wxConn wxface.IWXConnect) *WXGroupTask {
|
||||
return &WXGroupTask{
|
||||
wxConn: wxConn,
|
||||
groupForQrcodeList: make([]*wechat.ModContact, 0),
|
||||
groupForAddressBookList: make([]*wechat.ModContact, 0),
|
||||
inQrcodeTask: false,
|
||||
inAddressBookTask: false,
|
||||
waitTimes: srvconfig.TaskExecWaitTimes,
|
||||
}
|
||||
}
|
||||
|
||||
// 获取下一个待下载的获取二维码的群
|
||||
func (gpt *WXGroupTask) getNextGroupForQrcodeContact() *wechat.ModContact {
|
||||
if len(gpt.groupForQrcodeList) <= 0 {
|
||||
return nil
|
||||
}
|
||||
retContact := gpt.groupForQrcodeList[0]
|
||||
gpt.groupForQrcodeList = gpt.groupForQrcodeList[1:]
|
||||
return retContact
|
||||
}
|
||||
|
||||
// 获取下一个待保存到通讯录到群
|
||||
func (gpt *WXGroupTask) getNextGroupListForAddressBookContact(count uint32) []*wechat.ModContact {
|
||||
size := uint32(len(gpt.groupForAddressBookList))
|
||||
if size <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
retList := make([]*wechat.ModContact, 0)
|
||||
if size > count {
|
||||
retList = append(retList, gpt.groupForAddressBookList[:count]...)
|
||||
gpt.groupForAddressBookList = gpt.groupForAddressBookList[count:]
|
||||
} else {
|
||||
retList = append(retList, gpt.groupForAddressBookList[0:]...)
|
||||
gpt.groupForAddressBookList = []*wechat.ModContact{}
|
||||
}
|
||||
return retList
|
||||
}
|
||||
|
||||
// GetLessCount 获取剩余群聊数量
|
||||
func (gpt *WXGroupTask) GetLessCount() uint32 {
|
||||
return uint32(len(gpt.groupForAddressBookList))
|
||||
}
|
||||
|
||||
// StartDownQrcode 开启下载群二维码任务
|
||||
// lessMembers: 最少成员数量
|
||||
func (gpt *WXGroupTask) StartDownQrcode(lessMembers uint32) {
|
||||
currentWXAccount := gpt.wxConn.GetWXAccount()
|
||||
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
|
||||
// 如果正在执行下载任务,则返回
|
||||
if gpt.inQrcodeTask {
|
||||
return
|
||||
}
|
||||
// 如果上一次的还没
|
||||
if len(gpt.groupForQrcodeList) <= 0 {
|
||||
gpt.groupForQrcodeList = currentWXAccount.GetWXGroupList()
|
||||
}
|
||||
// 先构建当前目录
|
||||
gpt.inQrcodeTask = true
|
||||
go func() {
|
||||
for {
|
||||
// 先判断是否还处于链接当中
|
||||
if !gpt.wxConn.IsConnected() {
|
||||
gpt.inQrcodeTask = false
|
||||
return
|
||||
}
|
||||
|
||||
// 获取下一个群聊
|
||||
tmpModContact := gpt.getNextGroupForQrcodeContact()
|
||||
if tmpModContact == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 群成员数量要大于20, 超过200人的群聊必须要邀请才能入群
|
||||
memberCount := tmpModContact.NewChatroomData.GetMemberCount()
|
||||
if memberCount < lessMembers || memberCount >= 200 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 进群验证
|
||||
if tmpModContact.GetChatroomAccessType() != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取群二维码请求
|
||||
groupUserName := tmpModContact.GetUserName().GetStr()
|
||||
err := currentWXReqInvoker.SendGetQRCodeRequest(groupUserName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// 暂停 2000 毫秒
|
||||
time.Sleep(2000 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// StartSaveToAddressBook 开启保存到通讯录
|
||||
// bSave: true:保存, false:取消保存
|
||||
func (gpt *WXGroupTask) StartSaveToAddressBook(bSave bool) bool {
|
||||
tmpOptionName := "保存"
|
||||
if !bSave {
|
||||
tmpOptionName = "取消保存"
|
||||
}
|
||||
currentWXAccount := gpt.wxConn.GetWXAccount()
|
||||
currentWXReqInvoker := gpt.wxConn.GetWXReqInvoker()
|
||||
currentWXFileHelperMgr := gpt.wxConn.GetWXFileHelperMgr()
|
||||
// 如果正在执行下载任务,则返回
|
||||
if gpt.inAddressBookTask {
|
||||
tipText := "正在" + tmpOptionName + "中请稍后, 剩余(" + strconv.Itoa(len(gpt.groupForAddressBookList)) + ")个群"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
return false
|
||||
}
|
||||
|
||||
// 如果上一次的还没
|
||||
if len(gpt.groupForAddressBookList) <= 0 {
|
||||
gpt.groupForAddressBookList = currentWXAccount.GetWXGroupList()
|
||||
}
|
||||
gpt.inAddressBookTask = true
|
||||
go func() {
|
||||
for {
|
||||
// 先判断是否还处于链接当中
|
||||
if !gpt.wxConn.IsConnected() {
|
||||
gpt.inAddressBookTask = false
|
||||
return
|
||||
}
|
||||
|
||||
// 获取接下来的10个群聊
|
||||
tmpModContactList := gpt.getNextGroupListForAddressBookContact(10)
|
||||
count := len(tmpModContactList)
|
||||
if count <= 0 {
|
||||
gpt.inAddressBookTask = false
|
||||
tipText := "执行 " + tmpOptionName + "群聊任务 完成"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tipText)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建Item列表
|
||||
items := make([]*baseinfo.ModifyItem, 0)
|
||||
for index := 0; index < count; index++ {
|
||||
tmpModContact := tmpModContactList[index]
|
||||
// 如果状态一致则不用操作
|
||||
bitVal := tmpModContact.GetBitVal()
|
||||
hasSaved := false
|
||||
if bitVal&baseinfo.MMBitValGroupSaveInAddressBook == 1 {
|
||||
hasSaved = true
|
||||
}
|
||||
if (bSave && hasSaved) || (!bSave && !hasSaved) {
|
||||
continue
|
||||
}
|
||||
tmpItem := clientsdk.CreateSaveGroupToAddressBookField(tmpModContact, bSave)
|
||||
items = append(items, tmpItem)
|
||||
}
|
||||
if len(items) <= 0 {
|
||||
continue
|
||||
}
|
||||
err := currentWXReqInvoker.SendOplogRequest(items)
|
||||
if err != nil {
|
||||
gpt.inAddressBookTask = false
|
||||
return
|
||||
}
|
||||
// 暂停 waitTimes 毫秒
|
||||
time.Sleep(time.Duration(gpt.waitTimes) * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
tmpTip := "开始" + tmpOptionName + "群聊任务"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(tmpTip)
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/db"
|
||||
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXRevokeTask 消息防撤回管理器
|
||||
type WXRevokeTask struct {
|
||||
wxConn wxface.IWXConnect
|
||||
// 防撤回开关
|
||||
bAvoidRevoke bool
|
||||
// 读写数据的读写锁
|
||||
revokeLock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewWXRevokeTask 新建消息防撤回任务管理器
|
||||
func NewWXRevokeTask(wxConn wxface.IWXConnect) *WXRevokeTask {
|
||||
return &WXRevokeTask{
|
||||
wxConn: wxConn,
|
||||
bAvoidRevoke: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Start 开启防消息撤回任务
|
||||
func (wxrt *WXRevokeTask) Start() {
|
||||
}
|
||||
|
||||
// Stop 停止防消息撤回任务
|
||||
func (wxrt *WXRevokeTask) Stop() {
|
||||
}
|
||||
|
||||
// AddNewMsg 新增缓存消息
|
||||
func (wxrt *WXRevokeTask) AddNewMsg(addMsg *wechat.AddMsg, uuid string) {
|
||||
wxrt.revokeLock.Lock()
|
||||
defer wxrt.revokeLock.Unlock()
|
||||
_ = db.SaveMsg(*addMsg, uuid)
|
||||
}
|
||||
|
||||
// OnRevokeMsg 某人移除了消息
|
||||
func (wxrt *WXRevokeTask) OnRevokeMsg(revokeMsg baseinfo.RevokeMsg, groupWXID string, toGroupWXID string, uuid string) {
|
||||
wxrt.revokeLock.Lock()
|
||||
defer wxrt.revokeLock.Unlock()
|
||||
// fmt.Printf("撤回消息:groupWXID %s\n", groupWXID)
|
||||
currentReqInvoker := wxrt.wxConn.GetWXReqInvoker()
|
||||
now := time.Now()
|
||||
timeStr := now.Format("2006-01-02 15:04:05")
|
||||
groupName := ""
|
||||
if groupWXID != "" {
|
||||
groupInfo, _, _ := currentReqInvoker.SendGetContactRequestForCache(groupWXID, true)
|
||||
if groupInfo != nil {
|
||||
groupName = groupInfo.GetNickName().GetStr()
|
||||
}
|
||||
}
|
||||
if groupName != "" {
|
||||
groupName = "【" + groupName + "】\n"
|
||||
}
|
||||
groupName = timeStr + "\n" + groupName
|
||||
|
||||
currentWXFileHelperMgr := wxrt.wxConn.GetWXFileHelperMgr()
|
||||
|
||||
tmpAddMsg := db.GetAndDeleteMsg(revokeMsg.NewMsgID, uuid)
|
||||
if tmpAddMsg == nil {
|
||||
return
|
||||
}
|
||||
strMsg := tmpAddMsg.GetContent().GetStr()
|
||||
// fmt.Println("撤回消息 MsgType:" + fmt.Sprintf("%d", tmpAddMsg.GetMsgType()))
|
||||
if tmpAddMsg.GetMsgType() == 1 {
|
||||
if groupWXID != "" && toGroupWXID == "" && strings.Contains(strMsg, ":") {
|
||||
// 群聊,去掉第一个冒号之前的内容
|
||||
strMsg = strings.Split(strMsg, ":")[1]
|
||||
}
|
||||
showMsg := groupName + revokeMsg.ReplaceMsg + ":" + strMsg
|
||||
currentWXFileHelperMgr.AddNewTipMsg(showMsg)
|
||||
}
|
||||
|
||||
if tmpAddMsg.GetMsgType() == baseinfo.MMAddMsgTypeRefer && strings.Contains(strMsg, "<type>57</type>") {
|
||||
// 引用消息,只可能是文本
|
||||
// <title>了解一下</title>
|
||||
titleRegex := regexp.MustCompile(`<title>([\s\S]*?)<\/title>`)
|
||||
match := titleRegex.FindStringSubmatch(strMsg)
|
||||
if len(match) > 1 {
|
||||
strMsg = match[1]
|
||||
showMsg := groupName + revokeMsg.ReplaceMsg + ":" + strMsg
|
||||
currentWXFileHelperMgr.AddNewTipMsg(showMsg)
|
||||
}
|
||||
}
|
||||
// 图片消息
|
||||
if tmpAddMsg.GetMsgType() == baseinfo.MMAddMsgTypeImage {
|
||||
strMsgByte := []byte(strMsg)
|
||||
showMsg := groupName + revokeMsg.ReplaceMsg + ":[图片]"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(showMsg)
|
||||
currentWXFileHelperMgr.ForwardImageMsg(strMsgByte)
|
||||
|
||||
}
|
||||
// 表情消息
|
||||
if tmpAddMsg.GetMsgType() == baseinfo.MMAddMsgTypePic {
|
||||
strMsgByte := []byte(strMsg)
|
||||
showMsg := groupName + revokeMsg.ReplaceMsg + ":[表情]"
|
||||
currentWXFileHelperMgr.AddNewTipMsg(showMsg)
|
||||
currentWXFileHelperMgr.ForwardEmoticonMsg(strMsgByte)
|
||||
}
|
||||
}
|
||||
|
||||
// SetAvoidRevoke 设置是否防消息撤回
|
||||
func (wxrt *WXRevokeTask) SetAvoidRevoke(bFlag bool) {
|
||||
wxrt.bAvoidRevoke = bFlag
|
||||
}
|
||||
|
||||
// IsAvoidRevoke 是否防消息撤回
|
||||
func (wxrt *WXRevokeTask) IsAvoidRevoke() bool {
|
||||
return wxrt.bAvoidRevoke
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXSnsTask 朋友圈任务
|
||||
type WXSnsTask struct {
|
||||
wxConn wxface.IWXConnect
|
||||
// 需要自动点赞到朋友圈列表
|
||||
snsObjChan chan *wechat.SnsObject
|
||||
// 评论
|
||||
snsObjChancomment chan *wechat.SnsObject
|
||||
// 朋友圈刷新时间
|
||||
snsFlushTimeChan chan uint32
|
||||
// 标记当前最新的朋友圈创建时间
|
||||
currentSnsCreateTime uint32
|
||||
// 自动点赞开启标志
|
||||
bAutoThumbUP bool
|
||||
// 评论
|
||||
bAutoComment bool
|
||||
// 评论
|
||||
commentContent string
|
||||
// 结束标志
|
||||
endChan chan bool
|
||||
// 结束标志
|
||||
isRunning bool
|
||||
//
|
||||
isStart bool
|
||||
}
|
||||
|
||||
// NewWXSnsTask 新建朋友圈任务管理器
|
||||
func NewWXSnsTask(wxConn wxface.IWXConnect) *WXSnsTask {
|
||||
return &WXSnsTask{
|
||||
wxConn: wxConn,
|
||||
snsObjChan: make(chan *wechat.SnsObject, 100),
|
||||
snsObjChancomment: make(chan *wechat.SnsObject, 100),
|
||||
snsFlushTimeChan: make(chan uint32, 5),
|
||||
currentSnsCreateTime: 0,
|
||||
bAutoThumbUP: false,
|
||||
bAutoComment: false,
|
||||
isRunning: false,
|
||||
isStart: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Start 开启任务
|
||||
func (wxst *WXSnsTask) Start() {
|
||||
if wxst.isStart {
|
||||
return
|
||||
}
|
||||
wxst.isStart = true
|
||||
wxst.endChan = make(chan bool, 1)
|
||||
// 定时刷新朋友圈
|
||||
go wxst.startFlushSns()
|
||||
// 开启自动点赞线程
|
||||
go wxst.startThumbUP()
|
||||
// 开启自动评论线程
|
||||
go wxst.startComment()
|
||||
}
|
||||
|
||||
// Stop 关闭任务
|
||||
func (wxst *WXSnsTask) Stop() {
|
||||
wxst.isStart = false
|
||||
//wxst.endChan <- true
|
||||
close(wxst.endChan)
|
||||
}
|
||||
|
||||
// SetAutoThumbUP 设置是否自动点赞朋友圈
|
||||
func (wxst *WXSnsTask) SetAutoThumbUP(bFlag bool) {
|
||||
wxst.bAutoThumbUP = bFlag
|
||||
if !bFlag {
|
||||
wxst.currentSnsCreateTime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// 评论
|
||||
func (wxst *WXSnsTask) SetAutoComment(bFlag bool) {
|
||||
wxst.bAutoComment = bFlag
|
||||
if !bFlag {
|
||||
wxst.currentSnsCreateTime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// 设置评论内容
|
||||
func (wxst *WXSnsTask) SetCommentContent(content string) {
|
||||
wxst.commentContent = content
|
||||
}
|
||||
|
||||
// 获取评论
|
||||
func (wxst *WXSnsTask) GetCommentContent() string {
|
||||
return wxst.commentContent
|
||||
}
|
||||
|
||||
// IsAutoThumbUP 是否开启了自动点赞朋友圈
|
||||
func (wxst *WXSnsTask) IsAutoThumbUP() bool {
|
||||
return wxst.bAutoThumbUP
|
||||
}
|
||||
|
||||
// 自动评论
|
||||
func (wxst *WXSnsTask) IsAutoComment() bool {
|
||||
return wxst.bAutoComment
|
||||
}
|
||||
|
||||
// SetCurrentCreateTime 设置最新的朋友圈创建时间
|
||||
func (wxst *WXSnsTask) SetCurrentCreateTime(tmpTime uint32) {
|
||||
wxst.currentSnsCreateTime = tmpTime
|
||||
}
|
||||
|
||||
// GetCurrentCreateTime 获取最新的朋友圈创建时间
|
||||
func (wxst *WXSnsTask) GetCurrentCreateTime() uint32 {
|
||||
return wxst.currentSnsCreateTime
|
||||
}
|
||||
|
||||
// AddCommentItemObj 新增自动点赞项
|
||||
func (wxst *WXSnsTask) AddCommentItemObj(snsObj *wechat.SnsObject) {
|
||||
wxst.snsObjChan <- snsObj
|
||||
}
|
||||
|
||||
// 新增自动评论
|
||||
func (wxst *WXSnsTask) AddCommentItemObjcomment(snsObj *wechat.SnsObject) {
|
||||
wxst.snsObjChancomment <- snsObj
|
||||
}
|
||||
|
||||
// 定时刷新朋友圈
|
||||
func (wxst *WXSnsTask) startFlushSns() {
|
||||
currentReqInvoker := wxst.wxConn.GetWXReqInvoker()
|
||||
// 1分钟刷新一次
|
||||
wxst.snsFlushTimeChan <- 60
|
||||
for {
|
||||
select {
|
||||
case waitTimes := <-wxst.snsFlushTimeChan:
|
||||
time.Sleep(time.Second * time.Duration(waitTimes))
|
||||
// 如果开启了自动转发
|
||||
if wxst.bAutoThumbUP || wxst.bAutoComment{
|
||||
// 刷新朋友圈首页
|
||||
currentReqInvoker.SendSnsTimeLineRequest("", 0)
|
||||
}
|
||||
wxst.snsFlushTimeChan <- 60
|
||||
continue
|
||||
case <-wxst.endChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自动点赞朋友圈
|
||||
func (wxst *WXSnsTask) startThumbUP() {
|
||||
currentReqInvoker := wxst.wxConn.GetWXReqInvoker()
|
||||
for {
|
||||
time.Sleep(time.Second * 1)
|
||||
select {
|
||||
case snsObj := <-wxst.snsObjChan:
|
||||
commentLikeItem := clientsdk.CreateSnsCommentLikeItem(snsObj.GetId(), snsObj.GetUsername())
|
||||
currentReqInvoker.SendSnsCommentRequest(commentLikeItem)
|
||||
case <-wxst.endChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自动评论
|
||||
func (wxst *WXSnsTask) startComment() {
|
||||
currentReqInvoker := wxst.wxConn.GetWXReqInvoker()
|
||||
for {
|
||||
time.Sleep(time.Second * 1)
|
||||
select {
|
||||
case snsObj := <-wxst.snsObjChancomment:
|
||||
fmt.Println(wxst.commentContent)
|
||||
commentLikeItem := clientsdk.CreateSnsCommentItem(snsObj.GetId(), snsObj.GetUsername(), wxst.commentContent, nil)
|
||||
currentReqInvoker.SendSnsCommentRequest(commentLikeItem)
|
||||
case <-wxst.endChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetRunningFlag 设置运行状态
|
||||
func (wxst *WXSnsTask) setRunningFlag(isRunning bool) {
|
||||
wxst.isRunning = isRunning
|
||||
}
|
||||
|
||||
// DeleteTenSnsObject 删除30条朋友圈
|
||||
func (wxst *WXSnsTask) DeleteTenSnsObject() {
|
||||
currentWXFileHelperMgr := wxst.wxConn.GetWXFileHelperMgr()
|
||||
// 如果正在执行
|
||||
if wxst.isRunning {
|
||||
currentWXFileHelperMgr.AddNewTipMsg("正在清理朋友圈请稍等")
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
wxst.setRunningFlag(true)
|
||||
defer wxst.setRunningFlag(false)
|
||||
currentWXFileHelperMgr.AddNewTipMsg("开始清理朋友圈...")
|
||||
// 获取30条朋友圈
|
||||
objIDList, err := wxst.getTenSnsObjectByCount(30)
|
||||
if err != nil {
|
||||
currentWXFileHelperMgr.AddNewTipMsg("清空朋友圈太频繁,稍后再试")
|
||||
return
|
||||
}
|
||||
|
||||
// 清理朋友圈
|
||||
count := len(objIDList)
|
||||
for index := 0; index < count; index++ {
|
||||
resp, err := wxst.DeleteSnsByID(strconv.Itoa(int(objIDList[index])))
|
||||
if err != nil {
|
||||
currentWXFileHelperMgr.AddNewTipMsg("清理太频繁,成功清理" + strconv.Itoa(index) + "条朋友圈")
|
||||
return
|
||||
}
|
||||
|
||||
// 如果返回出错
|
||||
if resp.GetBaseResponse().GetRet() != 0 {
|
||||
currentWXFileHelperMgr.AddNewTipMsg("清理太频繁,成功清理" + strconv.Itoa(index) + "条朋友圈")
|
||||
return
|
||||
}
|
||||
// 500毫秒清理一次
|
||||
time.Sleep(time.Millisecond * 600)
|
||||
}
|
||||
currentWXFileHelperMgr.AddNewTipMsg("清理完成, 成功清理" + strconv.Itoa(count) + "条朋友圈")
|
||||
return
|
||||
}()
|
||||
}
|
||||
|
||||
// DeleteSnsByID 根据朋友圈ID删除朋友圈
|
||||
func (wxst *WXSnsTask) DeleteSnsByID(snsIDList string) (*wechat.SnsObjectOpResponse, error) {
|
||||
currentReqInvoker := wxst.wxConn.GetWXReqInvoker()
|
||||
items := make([]*baseinfo.SnsObjectOpItem, 0)
|
||||
deleteItem := clientsdk.CreateSnsDeleteItem(snsIDList)
|
||||
items = append(items, deleteItem)
|
||||
return currentReqInvoker.SendSnsObjectOpRequest(items)
|
||||
}
|
||||
|
||||
// getAllSnsObject 获取所有的朋友圈
|
||||
func (wxst *WXSnsTask) getTenSnsObjectByCount(needCount uint32) ([]uint64, error) {
|
||||
currentReqInvoker := wxst.wxConn.GetWXReqInvoker()
|
||||
currentWXAccount := wxst.wxConn.GetWXAccount()
|
||||
tmpUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
retList := make([]uint64, 0)
|
||||
currentCount := uint32(0)
|
||||
tmpMaxID := uint64(0)
|
||||
for currentCount < needCount {
|
||||
// 获取10条朋友圈
|
||||
resp, err := currentReqInvoker.SendSnsUserPageRequest(tmpUserInfo.WxId, "", tmpMaxID, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
objectList := resp.GetObjectList()
|
||||
count := len(objectList)
|
||||
for index := 0; index < count; index++ {
|
||||
tmpObject := objectList[index]
|
||||
retList = append(retList, tmpObject.GetId())
|
||||
}
|
||||
if count < 10 {
|
||||
break
|
||||
}
|
||||
currentCount = currentCount + uint32(count)
|
||||
tmpMaxID = objectList[count-1].GetId()
|
||||
}
|
||||
return retList, nil
|
||||
}
|
||||
@@ -0,0 +1,696 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"xiawan/wx/db"
|
||||
|
||||
"github.com/lunny/log"
|
||||
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
"xiawan/wx/clientsdk/xmltool"
|
||||
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/srv/defines"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXSnsTransTask 朋友圈转发管理器
|
||||
type WXSnsTransTask struct {
|
||||
wxConn wxface.IWXConnect
|
||||
// 待转发的收藏
|
||||
favItemChan chan *baseinfo.FavItem
|
||||
// 同步转发
|
||||
syncItemChan chan *wechat.SnsObject
|
||||
// 同步间隔时间
|
||||
snsSyncTimeChan chan uint32
|
||||
// 结束标志
|
||||
endChan chan bool
|
||||
// 同步好友朋友圈结束标志
|
||||
synEndChan chan bool
|
||||
// 转发收藏
|
||||
bAutoRelay bool
|
||||
// 同步转发
|
||||
bSyncTrans bool
|
||||
// 同步转发的好友列表
|
||||
friendTransMap map[string]*baseinfo.FriendTransItem
|
||||
// 同步锁
|
||||
wxCurrentLock sync.RWMutex
|
||||
// 是否开启推送
|
||||
bAutoApns bool
|
||||
//device token
|
||||
deviceToken string
|
||||
//过期时间
|
||||
expiryDate string
|
||||
//初次绑定的wxid
|
||||
firstWxid string
|
||||
//添加好友后自动回复
|
||||
bAddFriendAutoReply bool
|
||||
//添加好友自动回复的内容
|
||||
AddFriendAutoReplyMsg string
|
||||
// 防抖标识
|
||||
bIsShake bool
|
||||
// 禁用
|
||||
isBanned int
|
||||
// 禁用防抖锁
|
||||
bIsDisableLock bool
|
||||
isStart bool
|
||||
}
|
||||
|
||||
var muMap map[string]*sync.Mutex = make(map[string]*sync.Mutex)
|
||||
var mapMutex sync.Mutex = sync.Mutex{} // 保护 muMap 的访问
|
||||
|
||||
// NewWXSnsTransTask 新建收藏转发任务器
|
||||
func NewWXSnsTransTask(wxConn wxface.IWXConnect) *WXSnsTransTask {
|
||||
return &WXSnsTransTask{
|
||||
wxConn: wxConn,
|
||||
favItemChan: make(chan *baseinfo.FavItem, 100),
|
||||
syncItemChan: make(chan *wechat.SnsObject, 100),
|
||||
friendTransMap: make(map[string]*baseinfo.FriendTransItem),
|
||||
snsSyncTimeChan: make(chan uint32, 5),
|
||||
endChan: make(chan bool, 1),
|
||||
synEndChan: make(chan bool, 1),
|
||||
bAutoRelay: false,
|
||||
bSyncTrans: false,
|
||||
bAutoApns: false,
|
||||
deviceToken: "",
|
||||
expiryDate: "",
|
||||
bIsShake: false,
|
||||
isBanned: 0,
|
||||
bIsDisableLock: false,
|
||||
isStart: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Start 开启任务
|
||||
func (transTask *WXSnsTransTask) Start() {
|
||||
if transTask.isStart {
|
||||
return
|
||||
}
|
||||
transTask.isStart = true
|
||||
// 开启任务
|
||||
go transTask.startTransTask()
|
||||
go transTask.startSnsSyncFriend()
|
||||
go transTask.KeyBindWxId()
|
||||
go transTask.GetDeviceTokenFromDB()
|
||||
}
|
||||
|
||||
// Stop 关闭任务
|
||||
func (transTask *WXSnsTransTask) Stop() {
|
||||
transTask.isStart = false
|
||||
transTask.endChan <- true
|
||||
//transTask.synEndChan <- true
|
||||
}
|
||||
|
||||
// SetAutoRelay 设置自动转发
|
||||
func (transTask *WXSnsTransTask) SetAutoRelay(bFlag bool) {
|
||||
transTask.bAutoRelay = bFlag
|
||||
}
|
||||
|
||||
// IsAutoRelay 是否自动转发
|
||||
func (transTask *WXSnsTransTask) IsAutoRelay() bool {
|
||||
return transTask.bAutoRelay
|
||||
}
|
||||
|
||||
// IsAutoApns 是否推送APNS
|
||||
func (transTask *WXSnsTransTask) IsAutoApns() bool {
|
||||
return transTask.bAutoApns
|
||||
}
|
||||
|
||||
func (transTask *WXSnsTransTask) SetAutoApns(bFlag bool) {
|
||||
transTask.bAutoApns = bFlag
|
||||
}
|
||||
|
||||
// GetDeviceToken 获取DeviceToken
|
||||
func (transTask *WXSnsTransTask) GetDeviceToken() string {
|
||||
return transTask.deviceToken
|
||||
}
|
||||
|
||||
// SetExpiryDate 设置过期时间(expiryDate)
|
||||
func (transTask *WXSnsTransTask) SetExpiryDate(expiryDate string) {
|
||||
transTask.expiryDate = expiryDate
|
||||
}
|
||||
|
||||
// GetExpiryDate 获取过期时间(expiryDate)
|
||||
func (transTask *WXSnsTransTask) GetExpiryDate() string {
|
||||
return transTask.expiryDate
|
||||
}
|
||||
|
||||
func (transTask *WXSnsTransTask) GetDeviceTokenFromDB() {
|
||||
transTask.KeyBindWxId()
|
||||
isBind, _ := db.IsLicenseBind(transTask.wxConn.GetWXAccount().GetUserInfo().UUID)
|
||||
if isBind == nil || &isBind.DeviceToken == nil {
|
||||
transTask.deviceToken = ""
|
||||
transTask.firstWxid = ""
|
||||
transTask.expiryDate = "2023-05-18"
|
||||
return
|
||||
}
|
||||
transTask.deviceToken = isBind.DeviceToken
|
||||
transTask.expiryDate = isBind.ExpiryDate
|
||||
transTask.firstWxid = isBind.WxId
|
||||
transTask.isBanned = isBind.IsBanned
|
||||
}
|
||||
|
||||
// key绑定vxid
|
||||
func (transTask *WXSnsTransTask) KeyBindWxId() {
|
||||
db.UpdateLicenseBindWxid(transTask.wxConn.GetWXAccount().GetUserInfo().WxId, transTask.wxConn.GetWXAccount().GetUserInfo().NickName, transTask.wxConn.GetWXAccount().GetUserInfo().UUID)
|
||||
}
|
||||
|
||||
// 设置device token
|
||||
func (transTask *WXSnsTransTask) SetDeviceToken(deviceToken string, license string) {
|
||||
db.UpdateLicenseBindStatus(deviceToken, license)
|
||||
transTask.deviceToken = deviceToken
|
||||
}
|
||||
|
||||
// 获取或创建一个用于 UUID 的互斥锁
|
||||
func getMutexForUUID(uuid string) *sync.Mutex {
|
||||
mapMutex.Lock()
|
||||
defer mapMutex.Unlock()
|
||||
|
||||
if _, exists := muMap[uuid]; !exists {
|
||||
muMap[uuid] = &sync.Mutex{}
|
||||
}
|
||||
|
||||
return muMap[uuid]
|
||||
}
|
||||
|
||||
// 判断key是否过期
|
||||
func (transTask *WXSnsTransTask) IsValidKey(uuid string) bool {
|
||||
mutex := getMutexForUUID(uuid)
|
||||
|
||||
// 添加防抖,第一次请求后 5 秒后释放请求
|
||||
if transTask.bIsShake {
|
||||
// 默认返回:true,没过期
|
||||
return true
|
||||
}
|
||||
transTask.bIsShake = true
|
||||
// 函数执行结束后等 10 秒后释放请求
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
defer func() {
|
||||
time.Sleep(10 * time.Second)
|
||||
transTask.bIsShake = false
|
||||
}()
|
||||
|
||||
if transTask.firstWxid == "" {
|
||||
transTask.GetDeviceTokenFromDB()
|
||||
}
|
||||
if transTask.expiryDate == "" || transTask.expiryDate == "2023-05-18" {
|
||||
resultObj, _ := db.UpdateLicenseExpiryDate(uuid)
|
||||
log.Println("resultObj:", resultObj.ExpiryDate)
|
||||
|
||||
if resultObj.ExpiryDate != "" {
|
||||
transTask.expiryDate = resultObj.ExpiryDate
|
||||
transTask.SetExpiryDate(transTask.expiryDate)
|
||||
}
|
||||
db.PublishLicenseKey(resultObj)
|
||||
}
|
||||
return !db.CheckExpiry(transTask.expiryDate, 0) && (transTask.firstWxid == transTask.wxConn.GetWXAccount().GetUserInfo().WxId || transTask.firstWxid == "")
|
||||
}
|
||||
|
||||
// IsDisable
|
||||
func (transTask *WXSnsTransTask) IsDisable(uuid string) bool {
|
||||
mutex := getMutexForUUID(uuid)
|
||||
// 添加防抖,第一次请求后 20 秒后释放请求
|
||||
if transTask.bIsDisableLock {
|
||||
// 是否禁用默认返回:false,没禁用
|
||||
return false
|
||||
}
|
||||
transTask.bIsDisableLock = true
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
defer func() {
|
||||
time.Sleep(20 * time.Second)
|
||||
transTask.bIsDisableLock = false
|
||||
}()
|
||||
return transTask.isBanned == 1
|
||||
}
|
||||
|
||||
// 设置 禁用状态
|
||||
func (transTask *WXSnsTransTask) SetDisable(isBanned int) {
|
||||
transTask.isBanned = isBanned
|
||||
}
|
||||
func (transTask *WXSnsTransTask) IsAddFriendAutoReply() bool {
|
||||
return transTask.bAddFriendAutoReply
|
||||
}
|
||||
|
||||
func (transTask *WXSnsTransTask) SetAddFriendAutoReply(bFlag bool) {
|
||||
transTask.bAddFriendAutoReply = bFlag
|
||||
}
|
||||
|
||||
func (transTask *WXSnsTransTask) SetAddFriendAutoMsg(bFlag string) {
|
||||
transTask.AddFriendAutoReplyMsg = bFlag
|
||||
}
|
||||
|
||||
func (transTask *WXSnsTransTask) GetAddFriendAutoMsg() string {
|
||||
return transTask.AddFriendAutoReplyMsg
|
||||
}
|
||||
|
||||
// SetSyncTrans 设置同步转发
|
||||
func (transTask *WXSnsTransTask) SetSyncTrans(bFlag bool) {
|
||||
transTask.bSyncTrans = bFlag
|
||||
if !bFlag {
|
||||
transTask.ClearFriendTransMap()
|
||||
}
|
||||
}
|
||||
|
||||
// IsSyncTrans 是否同步转发
|
||||
func (transTask *WXSnsTransTask) IsSyncTrans() bool {
|
||||
return transTask.bSyncTrans
|
||||
}
|
||||
|
||||
// 初始化同步转发的好友
|
||||
func (transTask *WXSnsTransTask) InitFriendTransMap() {
|
||||
transTask.wxCurrentLock.Lock()
|
||||
defer transTask.wxCurrentLock.Unlock()
|
||||
redisKey := transTask.wxConn.GetWXAccount().GetUserInfo().UUID + "_syncTransFriend"
|
||||
transTask.friendTransMap = make(map[string]*baseinfo.FriendTransItem)
|
||||
db.GETObj(redisKey, &transTask.friendTransMap)
|
||||
}
|
||||
|
||||
// AddSyncTransFriend 增加同步转发的好友
|
||||
func (transTask *WXSnsTransTask) AddSyncTransFriend(friendWXID string) bool {
|
||||
transTask.wxCurrentLock.Lock()
|
||||
defer transTask.wxCurrentLock.Unlock()
|
||||
|
||||
_, ok := transTask.friendTransMap[friendWXID]
|
||||
if !ok {
|
||||
// 不存在就添加
|
||||
friendTransItem := &baseinfo.FriendTransItem{}
|
||||
friendTransItem.FriendWXID = friendWXID
|
||||
friendTransItem.FirstPageMd5 = ""
|
||||
friendTransItem.CreateTime = 0
|
||||
friendTransItem.IsInited = false
|
||||
transTask.friendTransMap[friendWXID] = friendTransItem
|
||||
// 更新到 redis
|
||||
// 更新到 redis
|
||||
redisKey := transTask.wxConn.GetWXAccount().GetUserInfo().UUID + "_syncTransFriend"
|
||||
go db.SETExpirationObj(redisKey, transTask.friendTransMap, -1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 删除同步转发的好友
|
||||
func (transTask *WXSnsTransTask) DelSyncTransFriend(friendWXID string) {
|
||||
transTask.wxCurrentLock.Lock()
|
||||
defer transTask.wxCurrentLock.Unlock()
|
||||
_, ok := transTask.friendTransMap[friendWXID]
|
||||
if ok {
|
||||
// 存在就删除
|
||||
delete(transTask.friendTransMap, friendWXID)
|
||||
// 更新到 redis
|
||||
redisKey := transTask.wxConn.GetWXAccount().GetUserInfo().UUID + "_syncTransFriend"
|
||||
go db.SETExpirationObj(redisKey, transTask.friendTransMap, -1)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTransFriendItem 根据微信 ID 同步转发好友项
|
||||
func (transTask *WXSnsTransTask) GetTransFriendItem(friendWXID string) *baseinfo.FriendTransItem {
|
||||
transTask.wxCurrentLock.Lock()
|
||||
defer transTask.wxCurrentLock.Unlock()
|
||||
|
||||
friendTransItem, ok := transTask.friendTransMap[friendWXID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return friendTransItem
|
||||
}
|
||||
|
||||
// GetTransFriendCount 返回个数
|
||||
func (transTask *WXSnsTransTask) GetTransFriendCount() int {
|
||||
transTask.wxCurrentLock.Lock()
|
||||
defer transTask.wxCurrentLock.Unlock()
|
||||
return len(transTask.friendTransMap)
|
||||
}
|
||||
|
||||
// ClearFriendTransMap 清空同步转发的好友列表
|
||||
func (transTask *WXSnsTransTask) ClearFriendTransMap() {
|
||||
transTask.wxCurrentLock.Lock()
|
||||
defer transTask.wxCurrentLock.Unlock()
|
||||
// 清空所有元素
|
||||
transTask.friendTransMap = make(map[string]*baseinfo.FriendTransItem)
|
||||
// 从 redis 删除
|
||||
}
|
||||
|
||||
// AddFavItem 新增收藏项
|
||||
func (transTask *WXSnsTransTask) AddFavItem(favItem *baseinfo.FavItem) {
|
||||
transTask.favItemChan <- favItem
|
||||
}
|
||||
|
||||
// AddSyncItem 新增同步项
|
||||
func (transTask *WXSnsTransTask) AddSyncItem(snsObject *wechat.SnsObject) {
|
||||
transTask.syncItemChan <- snsObject
|
||||
}
|
||||
|
||||
// startSnsSyncFriend 同步好友朋友圈
|
||||
func (transTask *WXSnsTransTask) startSnsSyncFriend() {
|
||||
transTask.snsSyncTimeChan <- 60
|
||||
for {
|
||||
select {
|
||||
case waitTimes := <-transTask.snsSyncTimeChan:
|
||||
time.Sleep(time.Second * time.Duration(waitTimes))
|
||||
// 如果开启了自动转发
|
||||
if transTask.bSyncTrans {
|
||||
// 遍历看是否又跟新朋友圈
|
||||
transTask.checkSnsFriendList()
|
||||
}
|
||||
transTask.snsSyncTimeChan <- 60
|
||||
continue
|
||||
case <-transTask.synEndChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (transTask *WXSnsTransTask) checkSnsFriendList() {
|
||||
transTask.wxCurrentLock.Lock()
|
||||
defer transTask.wxCurrentLock.Unlock()
|
||||
// 遍历朋友圈
|
||||
currentReqInvoker := transTask.wxConn.GetWXReqInvoker()
|
||||
for _, friendItem := range transTask.friendTransMap {
|
||||
_, err := currentReqInvoker.SendSnsUserPageRequest(friendItem.FriendWXID, "", 0, false)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// starttransTask 任务线程
|
||||
func (transTask *WXSnsTransTask) startTransTask() {
|
||||
for {
|
||||
select {
|
||||
case currentFavItem := <-transTask.favItemChan:
|
||||
err := transTask.doFavTask(currentFavItem)
|
||||
if err != nil {
|
||||
baseutils.PrintLog("转发收藏失败")
|
||||
}
|
||||
continue
|
||||
case snsObject := <-transTask.syncItemChan:
|
||||
location := baseinfo.Location{}
|
||||
err := transTask.DoSnsTransTask(snsObject, defines.MTaskTypeSyncTrans, nil, location, 0)
|
||||
if err != nil {
|
||||
baseutils.PrintLog("同步转发失败")
|
||||
}
|
||||
continue
|
||||
case <-transTask.endChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// doTask 执行收藏转发任务
|
||||
func (transTask *WXSnsTransTask) doFavTask(favItem *baseinfo.FavItem) error {
|
||||
// 先获取收藏的那条朋友圈详情
|
||||
currentReqInvoker := transTask.wxConn.GetWXReqInvoker()
|
||||
// 获取指定的朋友圈
|
||||
objIDString := baseutils.GetNumberString(favItem.Source.SourceID)
|
||||
snsObjID, _ := strconv.ParseUint(objIDString, 10, 64)
|
||||
snsObject, err := currentReqInvoker.SendSnsObjectDetailRequest(snsObjID)
|
||||
if err != nil {
|
||||
baseutils.PrintLog("WXSnsTransTask.doFavTask - SendSnsObjectDetailRequest err: " + err.Error())
|
||||
return err
|
||||
}
|
||||
location := baseinfo.Location{}
|
||||
// 转发朋友圈
|
||||
err = transTask.DoSnsTransTask(snsObject, defines.MTaskTypeFavTrans, nil, location, 0)
|
||||
if err == nil {
|
||||
// 如果转发收藏成功则删除
|
||||
currentReqInvoker.SendBatchDelFavItemRequest(favItem.FavItemID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 转发朋友圈
|
||||
func (transTask *WXSnsTransTask) DoSnsTransTask(snsObject *wechat.SnsObject, taskType uint32, blackList []string, location baseinfo.Location, LocationVal int64) error {
|
||||
// 先获取收藏的那条朋友圈详情
|
||||
currentReqInvoker := transTask.wxConn.GetWXReqInvoker()
|
||||
currentWXAccount := transTask.wxConn.GetWXAccount()
|
||||
|
||||
// 没有获取到朋友圈信息
|
||||
if snsObject.GetObjectDesc().GetLen() <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 先反序列化TimeLineXML
|
||||
tmpTimeLineObj := &baseinfo.TimelineObject{}
|
||||
err := xmltool.Unmarshal(snsObject.GetObjectDesc().GetBuffer(), tmpTimeLineObj)
|
||||
if err != nil {
|
||||
baseutils.PrintBytesHex(snsObject.GetObjectDesc().GetBuffer(), "tmpTimeLineDesc")
|
||||
baseutils.PrintLog("tmpTimeLine = " + string(snsObject.GetObjectDesc().GetBuffer()))
|
||||
baseutils.PrintLog("WXSnsTransTask.doTask - xml.Unmarshal err: " + err.Error())
|
||||
return err
|
||||
}
|
||||
//转发不带位置
|
||||
if LocationVal == 1 {
|
||||
tmpTimeLineObj.Location = baseinfo.Location{}
|
||||
} else if LocationVal == 2 {
|
||||
//转发自定义位置
|
||||
if location.Latitude != "" && location.Longitude != "" {
|
||||
tmpTimeLineObj.Location = location
|
||||
}
|
||||
}
|
||||
|
||||
// data, _ := json.Marshal(tmpTimeLineObj)
|
||||
// fmt.Println(string(data))
|
||||
|
||||
// 根据评论修改内容
|
||||
myCommentInfo := transTask.getMyCommentInfo(snsObject)
|
||||
if myCommentInfo != nil {
|
||||
tmpTimeLineObj.ContentDesc = myCommentInfo.GetContent()
|
||||
// 删除评论
|
||||
_, err := transTask.deleteMyComment(strconv.Itoa(int(snsObject.GetId())), myCommentInfo.GetCommentId())
|
||||
if err != nil {
|
||||
baseutils.PrintLog(err.Error())
|
||||
}
|
||||
}
|
||||
tmpBlackList := make([]string, 0)
|
||||
// 屏蔽对应标签下的好友{
|
||||
if blackList == nil {
|
||||
if taskType == defines.MTaskTypeFavTrans {
|
||||
tmpBlackList = currentWXAccount.GetUserListByLabel(defines.MFavTransShieldLabelName)
|
||||
} else if taskType == defines.MTaskTypeSyncTrans {
|
||||
tmpBlackList = currentWXAccount.GetUserListByLabel(defines.MSyncTransShieldLabelName)
|
||||
}
|
||||
} else {
|
||||
tmpBlackList = blackList
|
||||
}
|
||||
if !strings.HasSuffix(tmpTimeLineObj.ContentObject.Title, "


习近平--习大大") { //习近平
|
||||
tmpTimeLineObj.ContentObject.Title = tmpTimeLineObj.ContentObject.Title + "



习近平--习大大"
|
||||
}
|
||||
// 如果是视频
|
||||
mediaItemList := transTask.dealMediaList(tmpTimeLineObj.ContentObject.MediaList.Media, tmpTimeLineObj.ContentDesc)
|
||||
ContentObjectVideo := transTask.dealSnsMediaItemOfVideo(snsObject.GetObjectDesc().GetBuffer())
|
||||
if len(mediaItemList) > 0 {
|
||||
postItem := &baseinfo.SnsPostItem{}
|
||||
postItem.Content = tmpTimeLineObj.ContentDesc
|
||||
postItem.Privacy = baseinfo.MMSnsPrivacyPublic
|
||||
postItem.ContentStyle = baseinfo.MMSNSContentStyleVideo
|
||||
postItem.MediaList = mediaItemList
|
||||
postItem.WithUserList = make([]string, 0)
|
||||
postItem.GroupUserList = make([]string, 0)
|
||||
postItem.BlackList = tmpBlackList
|
||||
return currentReqInvoker.SendSnsPostRequest(postItem)
|
||||
}
|
||||
|
||||
// 转发到自己朋友圈-非视频,可能是视频号
|
||||
tmpTimeLineObj.ID = 0
|
||||
|
||||
if ContentObjectVideo != nil {
|
||||
// tmpTimeLineObj.ContentObjectVideo = ContentObjectVideo
|
||||
}
|
||||
|
||||
return currentReqInvoker.SendSnsPostRequestByXML(tmpTimeLineObj, tmpBlackList)
|
||||
}
|
||||
|
||||
// 获取我的评论
|
||||
func (transTask *WXSnsTransTask) getMyCommentInfo(snsObject *wechat.SnsObject) *wechat.SnsCommentInfo {
|
||||
myWxID := transTask.wxConn.GetWXAccount().GetUserInfo().WxId
|
||||
commentCount := snsObject.GetCommentUserListCount()
|
||||
if commentCount <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 查找我的评论
|
||||
commentUserList := snsObject.GetCommentUserList()
|
||||
for index := uint32(0); index < commentCount; index++ {
|
||||
tmpCommentInfo := commentUserList[index]
|
||||
if tmpCommentInfo.GetUsername() == myWxID {
|
||||
return tmpCommentInfo
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 删除我的评论
|
||||
func (transTask *WXSnsTransTask) deleteMyComment(snsObjectID string, commentID uint32) (*wechat.SnsObjectOpResponse, error) {
|
||||
currentReqInvoker := transTask.wxConn.GetWXReqInvoker()
|
||||
items := make([]*baseinfo.SnsObjectOpItem, 1)
|
||||
items[0] = clientsdk.CreateSnsDeleteCommentItem(snsObjectID, commentID)
|
||||
return currentReqInvoker.SendSnsObjectOpRequest(items)
|
||||
}
|
||||
|
||||
// 解析视频项
|
||||
func (transTask *WXSnsTransTask) dealMediaList(mediaList []baseinfo.Media, newContent string) []*baseinfo.SnsMediaItem {
|
||||
currentReqInvoker := transTask.wxConn.GetWXReqInvoker()
|
||||
retMediaItemList := make([]*baseinfo.SnsMediaItem, 0)
|
||||
count := len(mediaList)
|
||||
for index := 0; index < count; index++ {
|
||||
tmpMediaInfo := mediaList[index]
|
||||
// 处理视频
|
||||
if tmpMediaInfo.Type != baseinfo.MMSNSMediaTypeVideo {
|
||||
continue
|
||||
}
|
||||
newMediaItem := &baseinfo.SnsMediaItem{}
|
||||
tmpMediaInfo.Description = newContent
|
||||
// 如果视频没有加密
|
||||
if tmpMediaInfo.Enc.Value != 0 {
|
||||
// 下载视频
|
||||
tmpEncKey, _ := strconv.Atoi(tmpMediaInfo.Enc.Key)
|
||||
videoData, err := currentReqInvoker.SendCdnSnsVideoDownloadReuqest(uint64(tmpEncKey), tmpMediaInfo.URL.Value)
|
||||
if err != nil {
|
||||
baseutils.PrintLog(err.Error())
|
||||
break
|
||||
}
|
||||
|
||||
// 封面
|
||||
thumbData, err := currentReqInvoker.SendCdnSnsVideoDownloadReuqest(uint64(tmpEncKey), tmpMediaInfo.Thumb.Value)
|
||||
if err != nil {
|
||||
baseutils.PrintLog(err.Error())
|
||||
break
|
||||
}
|
||||
// 上传视频
|
||||
resp, err := currentReqInvoker.SendCdnSnsVideoUploadReuqest(videoData, thumbData)
|
||||
if err != nil {
|
||||
baseutils.PrintLog(err.Error())
|
||||
break
|
||||
}
|
||||
// 设置新内容
|
||||
newMediaItem = transTask.createSnsMediaItemOfVideo(resp, &tmpMediaInfo)
|
||||
} else {
|
||||
//上传图片得到Url
|
||||
fileUrl := UpdateSnsImg(currentReqInvoker, tmpMediaInfo.Thumb.Value)
|
||||
if fileUrl != "" {
|
||||
tmpMediaInfo.Thumb.Value = fileUrl
|
||||
}
|
||||
// 没有加密的视频
|
||||
newMediaItem = transTask.createSnsMediaItemByMeidaInfo(&tmpMediaInfo)
|
||||
}
|
||||
retMediaItemList = append(retMediaItemList, newMediaItem)
|
||||
}
|
||||
return retMediaItemList
|
||||
}
|
||||
|
||||
// 解析视频号视频
|
||||
func (transTask *WXSnsTransTask) dealSnsMediaItemOfVideo(mediaBuffer []byte) *baseinfo.ContentObjectVideo {
|
||||
tmpTimeLineObj := &baseinfo.TimelineObjectVideo{}
|
||||
err := xmltool.Unmarshal(mediaBuffer, tmpTimeLineObj)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
Media := tmpTimeLineObj.ContentObject.FinderFeed.MediaList.Media
|
||||
// 打印
|
||||
if len(Media) == 1 {
|
||||
MediaItem := Media[0]
|
||||
// 判断视频号视频类型
|
||||
fmt.Println("MediaItem.MediaType", MediaItem.MediaType)
|
||||
if MediaItem.MediaType == baseinfo.MMSNSMediaTypeVideoNum {
|
||||
// tmpTimeLineObj.ContentObject.FinderFeed.ObjectId = "0"
|
||||
return &tmpTimeLineObj.ContentObject
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 上传图片
|
||||
func UpdateSnsImg(wxface wxface.IWXReqInvoker, url string) string {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Println("A error occurred!")
|
||||
return ""
|
||||
}
|
||||
defer res.Body.Close()
|
||||
// 读取获取的[]byte数据
|
||||
data, _ := ioutil.ReadAll(res.Body)
|
||||
//生成一个Md5
|
||||
//imageId := baseutils.Md5ValueByte(imageBuffer, false)
|
||||
rsp, err := wxface.SendCdnSnsUploadImageReuqest(data)
|
||||
if err != nil {
|
||||
fmt.Println("update Image err 出错")
|
||||
}
|
||||
return rsp.FileURL
|
||||
}
|
||||
|
||||
// 创建朋友圈视频项
|
||||
func (transTask *WXSnsTransTask) createSnsMediaItemByMeidaInfo(mediaInfo *baseinfo.Media) *baseinfo.SnsMediaItem {
|
||||
retItem := &baseinfo.SnsMediaItem{}
|
||||
retItem.EncKey = mediaInfo.Enc.Key
|
||||
retItem.EncValue = mediaInfo.Enc.Value
|
||||
retItem.ID = 0
|
||||
retItem.Type = mediaInfo.Type
|
||||
retItem.Description = mediaInfo.Description
|
||||
retItem.Private = baseinfo.MMSnsPrivacyPublic
|
||||
retItem.UserData = mediaInfo.UserData
|
||||
retItem.SubType = mediaInfo.SubType
|
||||
retItem.VideoWidth = mediaInfo.VideoSize.Width
|
||||
retItem.VideoHeight = mediaInfo.VideoSize.Height
|
||||
retItem.URL = mediaInfo.URL.Value
|
||||
retItem.URL = strings.ReplaceAll(retItem.URL, "&", "&")
|
||||
retItem.URLType = mediaInfo.URL.Type
|
||||
retItem.MD5 = mediaInfo.URL.MD5
|
||||
retItem.VideoMD5 = mediaInfo.URL.VideoMD5
|
||||
retItem.Thumb = mediaInfo.Thumb.Value
|
||||
retItem.Thumb = strings.ReplaceAll(retItem.Thumb, "&", "&")
|
||||
retItem.ThumType = mediaInfo.Thumb.Type
|
||||
retItem.SizeWidth = mediaInfo.Size.Width
|
||||
retItem.SizeHeight = mediaInfo.Size.Height
|
||||
retItem.TotalSize = mediaInfo.Size.TotalSize
|
||||
retItem.VideoDuration = mediaInfo.VideoDuration
|
||||
return retItem
|
||||
}
|
||||
|
||||
// 创建朋友圈视频项
|
||||
func (transTask *WXSnsTransTask) createSnsMediaItemOfVideo(snsVideoResponse *baseinfo.CdnSnsVideoUploadResponse, mediaInfo *baseinfo.Media) *baseinfo.SnsMediaItem {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
fmt.Printf("Recovered from panic: %v\n", r)
|
||||
// 这里可以记录日志或者执行其他的恢复操作
|
||||
}
|
||||
}()
|
||||
retItem := &baseinfo.SnsMediaItem{}
|
||||
if snsVideoResponse == nil {
|
||||
return retItem
|
||||
}
|
||||
if mediaInfo == nil {
|
||||
return retItem
|
||||
}
|
||||
retItem.ID = 0
|
||||
retItem.Type = mediaInfo.Type
|
||||
retItem.Description = mediaInfo.Description
|
||||
retItem.Private = baseinfo.MMSnsPrivacyPublic
|
||||
retItem.UserData = mediaInfo.UserData
|
||||
retItem.SubType = mediaInfo.SubType
|
||||
retItem.VideoWidth = mediaInfo.VideoSize.Width
|
||||
retItem.VideoHeight = mediaInfo.VideoSize.Height
|
||||
retItem.URL = snsVideoResponse.FileURL
|
||||
retItem.URL = strings.ReplaceAll(retItem.URL, "&", "&")
|
||||
retItem.URLType = mediaInfo.URL.Type
|
||||
retItem.MD5 = snsVideoResponse.ReqData.RawFileMD5
|
||||
retItem.VideoMD5 = snsVideoResponse.ReqData.Mp4Identify
|
||||
retItem.Thumb = snsVideoResponse.ThumbURL
|
||||
retItem.Thumb = strings.ReplaceAll(retItem.Thumb, "&", "&")
|
||||
retItem.ThumType = mediaInfo.Thumb.Type
|
||||
retItem.SizeWidth = mediaInfo.Size.Width
|
||||
retItem.SizeHeight = mediaInfo.Size.Height
|
||||
retItem.TotalSize = mediaInfo.Size.TotalSize
|
||||
retItem.VideoDuration = mediaInfo.VideoDuration
|
||||
return retItem
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxface"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// 全局写锁映射,保护每个连接的写操作
|
||||
var connWriteMutexes sync.Map
|
||||
|
||||
// decodeUnicodeEscapes 解码Unicode转义字符
|
||||
func decodeUnicodeEscapes(s string) string {
|
||||
// 处理JSON中的Unicode转义字符,如\u003c
|
||||
re := regexp.MustCompile(`\\u([0-9a-fA-F]{4})`)
|
||||
result := re.ReplaceAllStringFunc(s, func(match string) string {
|
||||
// 提取十六进制数字部分
|
||||
hexStr := match[2:] // 去掉\u前缀
|
||||
// 将十六进制转换为整数
|
||||
if codePoint, err := strconv.ParseInt(hexStr, 16, 32); err == nil {
|
||||
// 转换为Unicode字符
|
||||
return string(rune(codePoint))
|
||||
}
|
||||
return match // 如果转换失败,返回原字符串
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 长链接同步消息
|
||||
type WXSocketMsgTask struct {
|
||||
WxConn wxface.IWXConnect
|
||||
// 待消费消息列表
|
||||
MsgItemChan chan *wechat.AddMsg
|
||||
// 可不可以消费下一条
|
||||
canDoNext chan bool
|
||||
// 结束标志
|
||||
EndChan chan bool
|
||||
// 是否正在运行
|
||||
isRunning bool
|
||||
// 是否启用WebSocket
|
||||
wsEnabled bool
|
||||
// 当前在消费的消息
|
||||
CurrentMsgItem *wechat.AddMsg
|
||||
// 存储所有连接的客户端
|
||||
Clients map[string]*websocket.Conn
|
||||
Upgrader websocket.Upgrader
|
||||
|
||||
// 定义一个互斥锁; 用于保护 Clients 的线程安全
|
||||
//mu sync.Mutex
|
||||
// 定义一个读写互斥锁; 用于保护 Clients 的线程安全
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewWXSocketMsgTask 新建抢红包管理器
|
||||
func NewWXSocketMsgTask(wxConn wxface.IWXConnect) *WXSocketMsgTask {
|
||||
return &WXSocketMsgTask{
|
||||
WxConn: wxConn,
|
||||
MsgItemChan: make(chan *wechat.AddMsg, 1000),
|
||||
canDoNext: make(chan bool, 1),
|
||||
EndChan: make(chan bool, 1),
|
||||
isRunning: false,
|
||||
wsEnabled: true, // 默认启用WebSocket功能,避免连接后延迟
|
||||
Clients: make(map[string]*websocket.Conn),
|
||||
Upgrader: websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
// 允许所有CORS跨域请求
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
|
||||
mu: sync.RWMutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (wsmsg *WXSocketMsgTask) grapMsg() {
|
||||
for {
|
||||
select {
|
||||
case wsmsg.CurrentMsgItem = <-wsmsg.MsgItemChan:
|
||||
key := wsmsg.WxConn.GetWXAccount().GetUserInfo().UUID
|
||||
|
||||
// 使用消息包装器包含UUID信息
|
||||
msgWrapper := NewMessageWrapper(key, wsmsg.CurrentMsgItem, "message")
|
||||
jsonBytes, err := json.Marshal(msgWrapper)
|
||||
if err != nil {
|
||||
fmt.Println("消息序列化错误:", err)
|
||||
continue // 继续处理下一条消息,而不是返回
|
||||
}
|
||||
|
||||
conn := wsmsg.GetWebSocket(key)
|
||||
if conn == nil {
|
||||
fmt.Println("WebSocket连接不存在:", key)
|
||||
continue // 继续处理下一条消息,而不是返回
|
||||
}
|
||||
// 对JSON内容进行Unicode解码处理
|
||||
decodedJSON := decodeUnicodeEscapes(string(jsonBytes))
|
||||
err = PushMessageToClient(decodedJSON, conn)
|
||||
if err != nil {
|
||||
fmt.Println("消息推送失败:", err)
|
||||
wsmsg.DeleteWebSocket(key)
|
||||
continue // 继续处理下一条消息,而不是返回
|
||||
}
|
||||
// 消息推送成功后继续处理下一条
|
||||
case <-wsmsg.EndChan:
|
||||
wsmsg.DeleteWebSocket(wsmsg.WxConn.GetWXAccount().GetUserInfo().UUID)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start 开始
|
||||
func (wsmsg *WXSocketMsgTask) Start() {
|
||||
if wsmsg.wsEnabled {
|
||||
if wsmsg.isRunning {
|
||||
return
|
||||
}
|
||||
wsmsg.isRunning = true
|
||||
go wsmsg.grapMsg() // 直接启动消息处理循环
|
||||
}
|
||||
}
|
||||
|
||||
// Stop 结束协程
|
||||
func (wsmsg *WXSocketMsgTask) Stop() {
|
||||
if !wsmsg.isRunning {
|
||||
return
|
||||
}
|
||||
wsmsg.isRunning = false
|
||||
wsmsg.EndChan <- true
|
||||
}
|
||||
|
||||
// GrapNext 抢下一个
|
||||
func (wsmsg *WXSocketMsgTask) GrapNext() {
|
||||
wsmsg.canDoNext <- true
|
||||
}
|
||||
|
||||
// AddMsgItem 添加消息项
|
||||
func (wsmsg *WXSocketMsgTask) AddMsgItem(msgItem *wechat.AddMsg) {
|
||||
if !wsmsg.wsEnabled {
|
||||
return
|
||||
}
|
||||
if !wsmsg.isRunning {
|
||||
wsmsg.Start()
|
||||
}
|
||||
key := wsmsg.WxConn.GetWXAccount().GetUserInfo().UUID
|
||||
conn := wsmsg.GetWebSocket(key)
|
||||
|
||||
// 打印日志
|
||||
// fmt.Println("------------收到消息-----------:\n",
|
||||
// "NickName: ",wsmsg.WxConn.GetWXAccount().GetUserInfo().NickName,"\n",
|
||||
// "Key: ",key,"\n",
|
||||
// "Content: ",msgItem.Content.GetStr(),
|
||||
// "\n",
|
||||
// "----------------------------------")
|
||||
|
||||
if conn == nil {
|
||||
// 只有 ws 长链接存在才会添加 收到的消息记录
|
||||
// fmt.Println("WebSocket连接不存在,消息将不会发送:", key)
|
||||
return
|
||||
}
|
||||
wsmsg.MsgItemChan <- msgItem
|
||||
}
|
||||
|
||||
// GetCurrentMsgItem 获取当前正在消费的消息项
|
||||
func (wsmsg *WXSocketMsgTask) GetCurrentMsgItem() *wechat.AddMsg {
|
||||
return wsmsg.CurrentMsgItem
|
||||
}
|
||||
|
||||
func PushMessageToClient(msg string, conn *websocket.Conn) error {
|
||||
// 获取或创建当前连接的写锁
|
||||
val, _ := connWriteMutexes.LoadOrStore(conn, &sync.Mutex{})
|
||||
mutex := val.(*sync.Mutex)
|
||||
|
||||
// 使用互斥锁保护写操作
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
// 使用 WebSocket 连接向客户端发送消息
|
||||
fmt.Println("发送消息:", msg)
|
||||
err := conn.WriteMessage(websocket.TextMessage, []byte(msg))
|
||||
if err != nil {
|
||||
// 如果发送错误,清理锁
|
||||
connWriteMutexes.Delete(conn)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// PushTypedMessageToClient 安全地发送特定类型的WebSocket消息
|
||||
func PushTypedMessageToClient(messageType int, data []byte, conn *websocket.Conn) error {
|
||||
// 获取或创建当前连接的写锁
|
||||
val, _ := connWriteMutexes.LoadOrStore(conn, &sync.Mutex{})
|
||||
mutex := val.(*sync.Mutex)
|
||||
|
||||
// 使用互斥锁保护写操作
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
// 使用 WebSocket 连接向客户端发送消息
|
||||
fmt.Printf("发送类型[%d]消息\n", messageType)
|
||||
err := conn.WriteMessage(messageType, data)
|
||||
if err != nil {
|
||||
// 如果发送错误,清理锁
|
||||
connWriteMutexes.Delete(conn)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// GetWebSocket 获取 Clients 缓存中的 ws 长链接
|
||||
func (wsmsg *WXSocketMsgTask) GetWebSocket(key string) (conn *websocket.Conn) {
|
||||
wsmsg.mu.RLock() // 读取 Clients 时使用读锁
|
||||
defer wsmsg.mu.RUnlock() // 解锁读锁
|
||||
conn = wsmsg.Clients[key] // 读取 ws 长链接; 若 key 不存在则返回 nil
|
||||
return conn
|
||||
}
|
||||
|
||||
// UpdateWebSocket 更新 Clients 缓存中的 ws 长链接
|
||||
func (wsmsg *WXSocketMsgTask) UpdateWebSocket(key string, conn *websocket.Conn) {
|
||||
wsmsg.mu.Lock() // 写入或删除 Clients 时使用写锁
|
||||
defer wsmsg.mu.Unlock() // 解锁
|
||||
wsmsg.Clients[key] = conn // 更新 ws 长链接
|
||||
wsmsg.wsEnabled = true // 当连接建立时启用WebSocket功能
|
||||
fmt.Println("WebSocket连接已更新:", key)
|
||||
}
|
||||
|
||||
// DeleteWebSocket 删除 Clients 缓存中的 ws 长链接
|
||||
func (wsmsg *WXSocketMsgTask) DeleteWebSocket(key string) {
|
||||
wsmsg.mu.Lock() // 写入或删除 Clients 时使用写锁
|
||||
defer wsmsg.mu.Unlock() // 解锁
|
||||
if conn, ok := wsmsg.Clients[key]; ok {
|
||||
// 清理连接的写锁
|
||||
connWriteMutexes.Delete(conn)
|
||||
delete(wsmsg.Clients, key) // 删除 ws 长链接
|
||||
fmt.Println("WebSocket连接已删除:", key)
|
||||
|
||||
// 如果没有连接,禁用WebSocket功能并停止任务
|
||||
if len(wsmsg.Clients) == 0 {
|
||||
wsmsg.wsEnabled = false
|
||||
if wsmsg.isRunning {
|
||||
wsmsg.Stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取WebSocket启用状态
|
||||
func (wsmsg *WXSocketMsgTask) IsWebSocketEnabled() bool {
|
||||
return wsmsg.wsEnabled
|
||||
}
|
||||
|
||||
// 设置WebSocket启用状态
|
||||
func (wsmsg *WXSocketMsgTask) SetWebSocketEnabled(enabled bool) {
|
||||
wsmsg.wsEnabled = enabled
|
||||
// 如果禁用而且正在运行,停止任务
|
||||
if !enabled && wsmsg.isRunning {
|
||||
wsmsg.Stop()
|
||||
} else if enabled && !wsmsg.isRunning && len(wsmsg.Clients) > 0 {
|
||||
// 如果启用而且有客户端连接但未运行,启动任务
|
||||
wsmsg.Start()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package wxtask
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXVerifyTask 加我/拉我进群聊是否需要验证
|
||||
type WXVerifyTask struct {
|
||||
wxConn wxface.IWXConnect
|
||||
// 结束标志
|
||||
notNeedVerify bool
|
||||
// 自动入群邀请
|
||||
autoJoinGroup bool
|
||||
// 互斥锁
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// NewWXVerifyTask 新建朋友圈任务管理器
|
||||
func NewWXVerifyTask(wxConn wxface.IWXConnect) *WXVerifyTask {
|
||||
return &WXVerifyTask{
|
||||
wxConn: wxConn,
|
||||
notNeedVerify: true,
|
||||
autoJoinGroup: false,
|
||||
}
|
||||
}
|
||||
|
||||
// IsNeedVerify 判断是否需要验证
|
||||
func (wxvt *WXVerifyTask) IsNeedVerify() bool {
|
||||
wxvt.lock.Lock()
|
||||
defer wxvt.lock.Unlock()
|
||||
return wxvt.notNeedVerify
|
||||
}
|
||||
|
||||
// SetNeedVerify 设置被添加,被拉入群聊时是否需要验证
|
||||
func (wxvt *WXVerifyTask) SetNeedVerify(needVerify bool) {
|
||||
wxvt.notNeedVerify = needVerify
|
||||
}
|
||||
|
||||
// 设置 autoJoinGroup
|
||||
func (wxvt *WXVerifyTask) SetAutoJoinGroup(autoJoinGroup bool) {
|
||||
wxvt.lock.Lock()
|
||||
defer wxvt.lock.Unlock()
|
||||
wxvt.autoJoinGroup = autoJoinGroup
|
||||
}
|
||||
|
||||
// 获取 autoJoinGroup
|
||||
func (wxvt *WXVerifyTask) GetAutoJoinGroup() bool {
|
||||
wxvt.lock.Lock()
|
||||
defer wxvt.lock.Unlock()
|
||||
return wxvt.autoJoinGroup
|
||||
}
|
||||
|
||||
// 判断 autoJoinGroup
|
||||
func (wxvt *WXVerifyTask) IsAutoJoinGroup() bool {
|
||||
wxvt.lock.Lock()
|
||||
defer wxvt.lock.Unlock()
|
||||
return wxvt.autoJoinGroup
|
||||
}
|
||||
|
||||
// 入群
|
||||
func (wxvt *WXVerifyTask) AddJoinGroup(url string) error {
|
||||
wxvt.lock.Lock()
|
||||
defer wxvt.lock.Unlock()
|
||||
_, err := wxvt.wxConn.GetWXReqInvoker().ConsentToJoinGroupRequest(url)
|
||||
return err
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user