first commit
This commit is contained in:
27
srv/defines/enums.go
Normal file
27
srv/defines/enums.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package defines
|
||||
|
||||
const (
|
||||
// EGroupTaskStateIdel 群聊任务状态:空闲
|
||||
EGroupTaskStateIdel uint32 = 0
|
||||
// EGroupTaskStateSave 群聊任务状态:保存群聊
|
||||
EGroupTaskStateSave uint32 = 1
|
||||
// EGroupTaskStateUnSave 群聊任务状态:取消保存群聊
|
||||
EGroupTaskStateUnSave uint32 = 2
|
||||
|
||||
// EGroupTaskStateDownQrcode 群聊任务状态:下载群二维码
|
||||
EGroupTaskStateDownQrcode uint32 = 3
|
||||
)
|
||||
|
||||
const (
|
||||
// MTaskTypeFavTrans 收藏转发
|
||||
MTaskTypeFavTrans uint32 = 0
|
||||
// MTaskTypeSyncTrans 同步转发
|
||||
MTaskTypeSyncTrans uint32 = 0
|
||||
)
|
||||
|
||||
const (
|
||||
// MFavTransShieldLabelName 收藏转发屏蔽标签名
|
||||
MFavTransShieldLabelName string = "收藏转发屏蔽"
|
||||
// MSyncTransShieldLabelName 同步转发屏蔽标签名
|
||||
MSyncTransShieldLabelName string = "同步转发屏蔽"
|
||||
)
|
||||
151
srv/srvconfig/globalconfig.go
Normal file
151
srv/srvconfig/globalconfig.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package srvconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
|
||||
"github.com/gogf/gf/database/gredis"
|
||||
)
|
||||
|
||||
// GlobalSetting 全局设置
|
||||
var GlobalSetting Setting
|
||||
|
||||
// TaskExecWaitTimes 任务执行间隔时间 500毫秒
|
||||
var TaskExecWaitTimes = uint32(500)
|
||||
|
||||
// Setting 设置
|
||||
type Setting struct {
|
||||
Debug bool `json:"debug"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
ApiVersion string `json:"apiVersion"`
|
||||
OpenClearMsg bool `json:"openClearMsg"`
|
||||
SycnTargetIpUrl string `json:"sycnTargetIpUrl"` // 同步外网IP地址的url
|
||||
|
||||
WorkerPoolSize uint32 `json:"workerpoolsize"`
|
||||
MaxWorkerTaskLen uint32 `json:"maxworkertasklen"`
|
||||
WebDomain string `json:"webdomain"`
|
||||
WebDomainNum string `json:"webdomainnum"`
|
||||
SyncOnlineCount string `json:"syncOnlineCount"`
|
||||
WebTaskName string `json:"webtaskname"`
|
||||
WebTaskAppNumber string `json:"webtaskappnumber"`
|
||||
//Redis
|
||||
RedisConfig gredis.Config `json:"redisConfig"`
|
||||
//消息同步 是否按微信id 发布消息
|
||||
NewsSynWxId bool `json:"newsSynWxId"`
|
||||
Dt bool `json:"dt"`
|
||||
MysqlConnectStr string `json:"mySqlConnectStr"`
|
||||
InitializeMySQLTables bool `json:"initializeMySQLTables"`
|
||||
UserInputKey string `json:"userInputKey"`
|
||||
Version string `json:"version"`
|
||||
HttpSyncMsg bool `json:"httpSyncMsg"`
|
||||
IsInitOld bool `json:"isInitOld"`
|
||||
WsSyncMsg bool `json:"wsSyncMsg"`
|
||||
SyncHisyory bool `json:"syncHisyory"`
|
||||
LoginBeforeRequestUrl string `json:"loginBeforeRequestUrl"` // 登录前会请求该 url(二维码和唤醒)
|
||||
// 当前服务器外网IP地址
|
||||
TargetIp string `json:"targetIp"`
|
||||
// 当前 HTTP-Api 服务的本地地址 基址
|
||||
LocalApiUrl string
|
||||
// 推广关注自己的微信公众号(新用户首次登录时关注)
|
||||
GhWxid string `json:"ghWxid"`
|
||||
// 管理接口授权 ADMIN_KEY
|
||||
AdminKey string `json:"adminKey"`
|
||||
// 是否开启 mac2ipad
|
||||
Mac2Ipad bool `json:"mac2ipad"`
|
||||
// 是否开启 car2ipad
|
||||
Car2Ipad bool `json:"car2ipad"`
|
||||
}
|
||||
|
||||
// getExternal 请求获取外网ip
|
||||
func getExternal() string {
|
||||
resp, err := http.Get(GlobalSetting.SycnTargetIpUrl)
|
||||
if err != nil {
|
||||
fmt.Printf("获取 ip 失败 -> 退出程序!---->")
|
||||
os.Exit(1)
|
||||
// return fmt.Sprintf("%s:%s", GlobalSetting.Host, GlobalSetting.Port)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
content, _ := ioutil.ReadAll(resp.Body)
|
||||
if content == nil {
|
||||
fmt.Printf("获取 ip 失败 -> 退出程序!---->")
|
||||
os.Exit(1)
|
||||
// return fmt.Sprintf("%s:%s", GlobalSetting.Host, GlobalSetting.Port)
|
||||
}
|
||||
// 校验一下是不是 ip
|
||||
if net.ParseIP(string(content)) == nil {
|
||||
fmt.Printf("获取 ip 失败 -> 退出程序!---->")
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("获取 ip 成功 -> %s ----> %s\n", content, GlobalSetting.SycnTargetIpUrl)
|
||||
|
||||
return fmt.Sprintf("%s:%s", content, GlobalSetting.Port)
|
||||
}
|
||||
|
||||
func isValidWeChatID(wxid string) bool {
|
||||
if strings.TrimSpace(wxid) == "" {
|
||||
GlobalSetting.GhWxid = ""
|
||||
return true
|
||||
}
|
||||
regex := `^[a-zA-Z][a-zA-Z0-9_-]{5,19}$`
|
||||
r := regexp.MustCompile(regex)
|
||||
return r.MatchString(wxid)
|
||||
}
|
||||
|
||||
func ConfigSetUp() {
|
||||
tmpHomeDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
baseutils.PrintLog(err.Error())
|
||||
return
|
||||
}
|
||||
baseinfo.HomeDIR = tmpHomeDir
|
||||
|
||||
// 读取配置文件
|
||||
configData, err := baseutils.ReadFile(baseinfo.HomeDIR + "/assets/setting.json")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(configData, &GlobalSetting)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(strings.TrimSpace(GlobalSetting.AdminKey)) == 0 {
|
||||
// 默认授权admin_key
|
||||
GlobalSetting.AdminKey = "df704bd7012548049e68db25aff0507f"
|
||||
}
|
||||
fmt.Println("======== ADMIN_KEY ===", GlobalSetting.AdminKey, "========")
|
||||
|
||||
if !isValidWeChatID(GlobalSetting.GhWxid) {
|
||||
fmt.Println("引流公众号(assets/setting.json ghWxid)不合法:", GlobalSetting.GhWxid, ";已重设为空")
|
||||
GlobalSetting.GhWxid = ""
|
||||
}
|
||||
|
||||
// 确保API版本格式正确,以斜杠开头
|
||||
if GlobalSetting.ApiVersion != "" && !strings.HasPrefix(GlobalSetting.ApiVersion, "/") {
|
||||
GlobalSetting.ApiVersion = "/" + GlobalSetting.ApiVersion
|
||||
}
|
||||
if GlobalSetting.ApiVersion == "/" {
|
||||
GlobalSetting.ApiVersion = ""
|
||||
}
|
||||
// 如果ApiVersion不为空且不以斜杠结尾,则添加斜杠
|
||||
if GlobalSetting.ApiVersion != "" && !strings.HasSuffix(GlobalSetting.ApiVersion, "/") {
|
||||
GlobalSetting.ApiVersion += "/"
|
||||
}
|
||||
GlobalSetting.LocalApiUrl = fmt.Sprintf("http://127.0.0.1:%s%s", GlobalSetting.Port, GlobalSetting.ApiVersion)
|
||||
|
||||
// 获取当前服务器外网IP地址
|
||||
// 如果没有指定 TargetIp, 同时 SycnTargetIpUrl 不为空, 则请求 SycnTargetIpUrl 获取外网 IP
|
||||
if GlobalSetting.TargetIp == "" && GlobalSetting.SycnTargetIpUrl != "" {
|
||||
GlobalSetting.TargetIp = getExternal()
|
||||
}
|
||||
}
|
||||
48
srv/websrv/define.go
Normal file
48
srv/websrv/define.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package websrv
|
||||
|
||||
import "xiawan/wx/clientsdk/baseinfo"
|
||||
|
||||
const (
|
||||
// TaskStateLoginSuccess 登录成功状态
|
||||
TaskStateLoginSuccess = string("2")
|
||||
// TaskStateLogout 退出登录
|
||||
TaskStateLogout = string("6")
|
||||
// TaskStateCheckLoginQrcodeSuccess 检测状态
|
||||
TaskStateCheckLoginQrcodeSuccess = string("1")
|
||||
// TaskStateCheckLoginQrcodeStartLogin 用户点击了登录
|
||||
TaskStateCheckLoginQrcodeStartLogin = string("7")
|
||||
// TaskStateMismatching 账号不匹配
|
||||
TaskStateMismatching = string("9")
|
||||
|
||||
// TaskTypeUploadStatus 上传状态
|
||||
TaskTypeUploadStatus uint32 = 1
|
||||
// TaskTypeReportHeart 发送心跳包
|
||||
TaskTypeReportHeart uint32 = 2
|
||||
)
|
||||
|
||||
// TaskInfo 任务信息
|
||||
type TaskInfo struct {
|
||||
UUID string
|
||||
TaskID string
|
||||
Name string
|
||||
AppNumber string
|
||||
Account string
|
||||
SignKey string
|
||||
}
|
||||
|
||||
// UploadTaskStatusResp 上传状态响应
|
||||
type UploadTaskStatusResp struct {
|
||||
Code uint32 `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
// WebTask web任务
|
||||
type WebTask struct {
|
||||
UserInfo *baseinfo.UserInfo
|
||||
TaskInfo *TaskInfo
|
||||
ConnectInfo map[string]interface{}
|
||||
Status string
|
||||
Type uint32
|
||||
Count uint32
|
||||
}
|
||||
51
srv/websrv/httptool.go
Normal file
51
srv/websrv/httptool.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package websrv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// TaskPost 短连接发送数据
|
||||
func TaskPost(uri string, data []byte) ([]byte, error) {
|
||||
client := &http.Client{}
|
||||
request, err := http.NewRequest("POST", uri, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("UserAgent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)")
|
||||
request.Header.Add("Accept", "*/*")
|
||||
request.Header.Add("content-type", "application/x-www-form-urlencoded")
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(body), nil
|
||||
}
|
||||
|
||||
// TaskPost 短连接发送数据
|
||||
func TaskPostJson(uri string, data []byte) ([]byte, error) {
|
||||
client := &http.Client{}
|
||||
request, err := http.NewRequest("POST", uri, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("content-type", "application/json")
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("短连接发送数据", uri,string(data),string(body))
|
||||
return []byte(body), nil
|
||||
}
|
||||
112
srv/websrv/taskmgr.go
Normal file
112
srv/websrv/taskmgr.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package websrv
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
)
|
||||
|
||||
// WebTaskMgr web任务管理器
|
||||
type WebTaskMgr struct {
|
||||
// wxConn wxface.IWXConnect
|
||||
taskChan chan *WebTask
|
||||
endChan chan bool
|
||||
isStart bool
|
||||
}
|
||||
|
||||
// 全局只能定义一个
|
||||
var WebTaskMgrInit *WebTaskMgr = &WebTaskMgr{
|
||||
taskChan: make(chan *WebTask, 100),
|
||||
endChan: make(chan bool, 1),
|
||||
isStart: false,
|
||||
}
|
||||
|
||||
var globalLock sync.Mutex = sync.Mutex{}
|
||||
|
||||
// NewWebTaskMgr 新建web任务管理器
|
||||
func NewWebTaskMgr() *WebTaskMgr {
|
||||
globalLock.Lock()
|
||||
defer globalLock.Unlock()
|
||||
return WebTaskMgrInit
|
||||
}
|
||||
|
||||
// Start 开启
|
||||
func (wtm *WebTaskMgr) Start() {
|
||||
globalLock.Lock()
|
||||
defer globalLock.Unlock()
|
||||
if wtm.isStart {
|
||||
return
|
||||
}
|
||||
wtm.isStart = true
|
||||
go wtm.queryAndExecuteTask()
|
||||
}
|
||||
|
||||
// Stop 关闭
|
||||
func (wtm *WebTaskMgr) Stop() {
|
||||
wtm.isStart = false
|
||||
wtm.endChan <- true
|
||||
}
|
||||
|
||||
// AddWebTask 新增Web任务
|
||||
func (wtm *WebTaskMgr) retSetWebTask(webTask *WebTask) {
|
||||
// 最多三次
|
||||
if webTask.Count >= 2 {
|
||||
return
|
||||
}
|
||||
webTask.Count++
|
||||
wtm.taskChan <- webTask
|
||||
}
|
||||
|
||||
// AddWebTask 新增Web任务
|
||||
func (wtm *WebTaskMgr) AddWebTask(userInfo *baseinfo.UserInfo, taskInfo *TaskInfo, status string, tmpType uint32, connectInfo map[string]interface{}) {
|
||||
if !wtm.isStart {
|
||||
return
|
||||
}
|
||||
globalLock.Lock()
|
||||
defer globalLock.Unlock()
|
||||
newWebTask := &WebTask{}
|
||||
newWebTask.ConnectInfo = connectInfo
|
||||
newWebTask.TaskInfo = taskInfo
|
||||
newWebTask.UserInfo = userInfo
|
||||
newWebTask.Status = status
|
||||
newWebTask.Type = tmpType
|
||||
newWebTask.Count = 0
|
||||
wtm.taskChan <- newWebTask
|
||||
}
|
||||
|
||||
func (wtm *WebTaskMgr) queryAndExecuteTask() {
|
||||
for {
|
||||
select {
|
||||
case webTask := <-wtm.taskChan:
|
||||
if webTask.Type == TaskTypeUploadStatus {
|
||||
err := errors.New("")
|
||||
// err := UploadTaskStatus(webTask)
|
||||
// if err != nil && webTask.Status != TaskStateCheckLoginQrcodeSuccess {
|
||||
// wtm.retSetWebTask(webTask)
|
||||
// continue
|
||||
// }
|
||||
// 登陆成功上报
|
||||
if webTask.Status == TaskStateLoginSuccess {
|
||||
err = ReportWechatStatus(webTask, "1")
|
||||
if err != nil {
|
||||
wtm.retSetWebTask(webTask)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// 退出登陆上报
|
||||
if webTask.Status == TaskStateLogout {
|
||||
err = ReportWechatStatus(webTask, "0")
|
||||
if err != nil {
|
||||
wtm.retSetWebTask(webTask)
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else if webTask.Type == TaskTypeReportHeart {
|
||||
// 上报心跳包
|
||||
}
|
||||
continue
|
||||
case <-wtm.endChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
126
srv/websrv/tasktool.go
Normal file
126
srv/websrv/tasktool.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package websrv
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
"xiawan/wx/srv/srvconfig"
|
||||
)
|
||||
|
||||
func createParamData(paramMap map[string]string) []byte {
|
||||
retString := ""
|
||||
for key, value := range paramMap {
|
||||
retString = retString + key + "=" + value + "&"
|
||||
}
|
||||
retBytes := []byte(retString)
|
||||
count := len(retBytes)
|
||||
retBytes = retBytes[0 : count-1]
|
||||
return retBytes
|
||||
}
|
||||
|
||||
func getBaseParamMap(taskInfo *TaskInfo) map[string]string {
|
||||
retMap := make(map[string]string)
|
||||
curTime := strconv.Itoa(int(time.Now().UnixNano() / 1000000000))
|
||||
head := curTime + taskInfo.SignKey
|
||||
hsWebTime := curTime + baseutils.RandomBigHexString(20)
|
||||
apiKey := baseutils.Md5Value(head)
|
||||
|
||||
retMap["name"] = taskInfo.Name
|
||||
retMap["app_number"] = taskInfo.AppNumber
|
||||
retMap["apikey"] = apiKey
|
||||
retMap["hswebtime"] = hsWebTime
|
||||
retMap["time"] = curTime
|
||||
|
||||
return retMap
|
||||
}
|
||||
|
||||
// UploadTaskStatus 上传任务状态
|
||||
func UploadTaskStatus(webTask *WebTask) error {
|
||||
baseParamMap := getBaseParamMap(webTask.TaskInfo)
|
||||
baseParamMap["name"] = webTask.UserInfo.NickName
|
||||
baseParamMap["task_id"] = webTask.TaskInfo.TaskID
|
||||
baseParamMap["account"] = webTask.UserInfo.WxId
|
||||
baseParamMap["headimg"] = webTask.UserInfo.HeadURL
|
||||
baseParamMap["status"] = webTask.Status
|
||||
if webTask.Status == TaskStateLoginSuccess {
|
||||
tmpToken := base64.StdEncoding.EncodeToString(webTask.UserInfo.AutoAuthKey)
|
||||
baseParamMap["token"] = tmpToken
|
||||
baseParamMap["data"] = ""
|
||||
baseParamMap["autoauth"] = "data=" + "token=" + tmpToken
|
||||
}
|
||||
paramBytes := createParamData(baseParamMap)
|
||||
respData, err := TaskPost("http://"+srvconfig.GlobalSetting.WebDomain+"/statistic/Wechat/upd.html", paramBytes)
|
||||
if err != nil {
|
||||
baseutils.PrintLog(err.Error())
|
||||
return err
|
||||
}
|
||||
resp := &UploadTaskStatusResp{}
|
||||
err = json.Unmarshal(respData, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果显示44
|
||||
if resp.Code == 44 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReportWechatStatus 上报状态
|
||||
func ReportWechatStatus(webTask *WebTask, tmpType string) error {
|
||||
baseParamMap := getBaseParamMap(webTask.TaskInfo)
|
||||
baseParamMap["name"] = webTask.UserInfo.NickName
|
||||
baseParamMap["uuid"] = webTask.UserInfo.UUID
|
||||
baseParamMap["task_id"] = webTask.TaskInfo.TaskID
|
||||
baseParamMap["account"] = webTask.UserInfo.WxId
|
||||
baseParamMap["task_type"] = "2"
|
||||
baseParamMap["service"] = srvconfig.GlobalSetting.WebDomainNum
|
||||
baseParamMap["type"] = tmpType
|
||||
connectInfo := map[string]interface{}{}
|
||||
connectInfo["info"] = baseParamMap
|
||||
|
||||
// 复制所有能够被序列化的字段
|
||||
for key, value := range webTask.ConnectInfo {
|
||||
switch v := value.(type) {
|
||||
case func(): // 这里检查并排除不支持的字段
|
||||
fmt.Println("Skipping function:", key)
|
||||
default:
|
||||
// 判断是否是基本类型
|
||||
if reflect.TypeOf(v).Kind() == reflect.String || reflect.TypeOf(v).Kind() == reflect.Int || reflect.TypeOf(v).Kind() == reflect.Bool {
|
||||
connectInfo[key] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将参数转换为 JSON 格式
|
||||
paramBytes, err := json.Marshal(connectInfo)
|
||||
if err != nil {
|
||||
fmt.Println("Error marshaling JSON:", err)
|
||||
return err
|
||||
}
|
||||
if srvconfig.GlobalSetting.WebDomain == "" {
|
||||
return nil
|
||||
}
|
||||
respData, err := TaskPostJson("http://"+srvconfig.GlobalSetting.WebDomain+"/statistic/Wechat/reportStatus", paramBytes)
|
||||
if err != nil {
|
||||
baseutils.PrintLog(err.Error())
|
||||
return err
|
||||
}
|
||||
resp := &UploadTaskStatusResp{}
|
||||
err = json.Unmarshal(respData, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 上报错误
|
||||
if resp.Code == 44 {
|
||||
return errors.New("上报错误")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
319
srv/wxaccount.go
Normal file
319
srv/wxaccount.go
Normal file
@@ -0,0 +1,319 @@
|
||||
package srv
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"xiawan/wx/srv/websrv"
|
||||
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/clientsdk/proxynet"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
)
|
||||
|
||||
// WXAccount 代表微信帐号
|
||||
type WXAccount struct {
|
||||
userInfo *baseinfo.UserInfo
|
||||
// 好友列表
|
||||
FriendMap map[string]*wechat.ModContact
|
||||
// 公众号列表
|
||||
ghMap map[string]*wechat.ModContact
|
||||
// 群map
|
||||
groupMap map[string]*wechat.ModContact
|
||||
// 标签列表
|
||||
labelMap map[uint32]*wechat.LabelPair
|
||||
// 配置文件信息
|
||||
userProfile *wechat.GetProfileResponse
|
||||
// 登录状态
|
||||
loginState uint32
|
||||
// 刚刚扫码登陆要初始化
|
||||
bInitializing bool
|
||||
// 任务信息
|
||||
taskInfo *websrv.TaskInfo
|
||||
friendMapLock sync.RWMutex //读写连接的读写锁
|
||||
ghMapLock sync.RWMutex //读写连接的读写锁
|
||||
groupMapLock sync.RWMutex //读写连接的读写锁
|
||||
labelMapLock sync.RWMutex //读写连接的读写锁
|
||||
}
|
||||
|
||||
// NewWXAccount 生成一个新的账户
|
||||
func NewWXAccount(taskInfo *websrv.TaskInfo, proxyInfo *proxynet.WXProxyInfo, ClientVersion uint32, dbUserInfo *baseinfo.UserInfo) *WXAccount {
|
||||
if !(int(ClientVersion) > 0) {
|
||||
ClientVersion = baseinfo.ClientVersion
|
||||
}
|
||||
|
||||
if ClientVersion == 319293451 {
|
||||
wxAccount := &WXAccount{
|
||||
userInfo: clientsdk.NewUserInfo_Mac(taskInfo.UUID, proxyInfo, ClientVersion, dbUserInfo),
|
||||
FriendMap: make(map[string]*wechat.ModContact),
|
||||
ghMap: make(map[string]*wechat.ModContact),
|
||||
groupMap: make(map[string]*wechat.ModContact),
|
||||
labelMap: make(map[uint32]*wechat.LabelPair),
|
||||
userProfile: nil,
|
||||
loginState: baseinfo.MMLoginStateNoLogin,
|
||||
taskInfo: taskInfo,
|
||||
}
|
||||
return wxAccount
|
||||
} else {
|
||||
wxAccount := &WXAccount{
|
||||
userInfo: clientsdk.NewUserInfo(taskInfo.UUID, proxyInfo, ClientVersion, dbUserInfo),
|
||||
FriendMap: make(map[string]*wechat.ModContact),
|
||||
ghMap: make(map[string]*wechat.ModContact),
|
||||
groupMap: make(map[string]*wechat.ModContact),
|
||||
labelMap: make(map[uint32]*wechat.LabelPair),
|
||||
userProfile: nil,
|
||||
loginState: baseinfo.MMLoginStateNoLogin,
|
||||
taskInfo: taskInfo,
|
||||
}
|
||||
return wxAccount
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserInfo 获取UserInfo
|
||||
func (wxAccount *WXAccount) GetUserInfo() *baseinfo.UserInfo {
|
||||
return wxAccount.userInfo
|
||||
}
|
||||
|
||||
// SetUserInfo 设置用户信息
|
||||
func (wxAccount *WXAccount) SetUserInfo(info *baseinfo.UserInfo) {
|
||||
// 默认重启状态为 false
|
||||
info.IsServerRestart = false
|
||||
wxAccount.userInfo = info
|
||||
|
||||
}
|
||||
|
||||
// GetTaskInfo 获取任务信息
|
||||
func (wxAccount *WXAccount) GetTaskInfo() *websrv.TaskInfo {
|
||||
return wxAccount.taskInfo
|
||||
}
|
||||
|
||||
// SetUserProfile 设置用户配置信息
|
||||
func (wxAccount *WXAccount) SetUserProfile(userProfile *wechat.GetProfileResponse) {
|
||||
wxAccount.userProfile = userProfile
|
||||
}
|
||||
|
||||
// GetUserProfile 获取帐号信息
|
||||
func (wxAccount *WXAccount) GetUserProfile() *wechat.GetProfileResponse {
|
||||
return wxAccount.userProfile
|
||||
}
|
||||
|
||||
// GetLoginState 获取登录状态
|
||||
func (wxAccount *WXAccount) GetLoginState() uint32 {
|
||||
//return wxAccount.loginState
|
||||
return wxAccount.GetUserInfo().GetLoginState()
|
||||
}
|
||||
|
||||
// SetLoginState 设置登录状态
|
||||
func (wxAccount *WXAccount) SetLoginState(loginState uint32) {
|
||||
wxAccount.loginState = loginState
|
||||
wxAccount.userInfo.SetLoginState(loginState)
|
||||
}
|
||||
|
||||
// AddWXFriendContact 增加微信好友ID
|
||||
func (wxAccount *WXAccount) AddWXFriendContact(modContact *wechat.ModContact) {
|
||||
wxAccount.friendMapLock.Lock()
|
||||
defer wxAccount.friendMapLock.Unlock()
|
||||
// 不存在-添加, 存在-更新
|
||||
wxAccount.FriendMap[modContact.GetUserName().GetStr()] = modContact
|
||||
}
|
||||
|
||||
// RemoveWXFriendID 删除信好友ID
|
||||
func (wxAccount *WXAccount) RemoveWXFriendID(friendWXID string) bool {
|
||||
wxAccount.friendMapLock.Lock()
|
||||
defer wxAccount.friendMapLock.Unlock()
|
||||
|
||||
// 如果不存在则退出
|
||||
_, ok := wxAccount.FriendMap[friendWXID]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
delete(wxAccount.FriendMap, friendWXID)
|
||||
return true
|
||||
}
|
||||
|
||||
// GetWXFriendList 获取微信好友ID列表
|
||||
func (wxAccount *WXAccount) GetWXFriendList() []*wechat.ModContact {
|
||||
wxAccount.friendMapLock.Lock()
|
||||
defer wxAccount.friendMapLock.Unlock()
|
||||
|
||||
retList := make([]*wechat.ModContact, 0)
|
||||
for _, modContact := range wxAccount.FriendMap {
|
||||
retList = append(retList, modContact)
|
||||
}
|
||||
return retList
|
||||
}
|
||||
|
||||
// GetWXFriendList 根据 id 获取好友
|
||||
func (wxAccount *WXAccount) GetWXFriendByWxid(wxid string) wechat.ModContact {
|
||||
wxAccount.friendMapLock.Lock()
|
||||
defer wxAccount.friendMapLock.Unlock()
|
||||
for _, modContact := range wxAccount.FriendMap {
|
||||
if modContact.GetUserName().GetStr() == wxid {
|
||||
return *modContact
|
||||
}
|
||||
}
|
||||
return wechat.ModContact{}
|
||||
}
|
||||
|
||||
// GetWXFriendList 获取微信好友ID列表
|
||||
func (wxAccount *WXAccount) getWXFriendListByLabelID(labelID uint32) []string {
|
||||
wxAccount.friendMapLock.Lock()
|
||||
defer wxAccount.friendMapLock.Unlock()
|
||||
|
||||
retList := make([]string, 0)
|
||||
// 遍历好友 获取对应标签的好友列表
|
||||
for userName, modContact := range wxAccount.FriendMap {
|
||||
if wxAccount.ContainsLabel(modContact.GetLabelIdlist(), labelID) {
|
||||
retList = append(retList, userName)
|
||||
}
|
||||
}
|
||||
return retList
|
||||
}
|
||||
|
||||
// AddWXGhContact 增加微信公众号ID
|
||||
func (wxAccount *WXAccount) AddWXGhContact(modContact *wechat.ModContact) {
|
||||
wxAccount.ghMapLock.Lock()
|
||||
defer wxAccount.ghMapLock.Unlock()
|
||||
// 不存在-添加, 存在-更新
|
||||
wxAccount.ghMap[modContact.GetUserName().GetStr()] = modContact
|
||||
}
|
||||
|
||||
// RemoveWXGhID 删除微信公众号ID
|
||||
func (wxAccount *WXAccount) RemoveWXGhID(ghWXID string) bool {
|
||||
wxAccount.ghMapLock.Lock()
|
||||
defer wxAccount.ghMapLock.Unlock()
|
||||
|
||||
// 如果不存在则退出
|
||||
_, ok := wxAccount.ghMap[ghWXID]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
delete(wxAccount.ghMap, ghWXID)
|
||||
return true
|
||||
}
|
||||
|
||||
// GetWXGhList 获取微信公众号ID列表
|
||||
func (wxAccount *WXAccount) GetWXGhList() []*wechat.ModContact {
|
||||
wxAccount.ghMapLock.Lock()
|
||||
defer wxAccount.ghMapLock.Unlock()
|
||||
|
||||
retList := make([]*wechat.ModContact, 0)
|
||||
for _, modContact := range wxAccount.ghMap {
|
||||
retList = append(retList, modContact)
|
||||
}
|
||||
return retList
|
||||
}
|
||||
|
||||
// AddWXGroup 增加群聊ID
|
||||
func (wxAccount *WXAccount) AddWXGroup(modContact *wechat.ModContact) {
|
||||
wxAccount.groupMapLock.Lock()
|
||||
defer wxAccount.groupMapLock.Unlock()
|
||||
// 不存在-添加,存在-更新
|
||||
userName := modContact.GetUserName().GetStr()
|
||||
wxAccount.groupMap[userName] = modContact
|
||||
}
|
||||
|
||||
// RemoveWXGroup 删除群聊ID
|
||||
func (wxAccount *WXAccount) RemoveWXGroup(groupWxID string) bool {
|
||||
wxAccount.groupMapLock.Lock()
|
||||
defer wxAccount.groupMapLock.Unlock()
|
||||
|
||||
// 如果不存在则退出
|
||||
_, ok := wxAccount.groupMap[groupWxID]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
delete(wxAccount.groupMap, groupWxID)
|
||||
return true
|
||||
}
|
||||
|
||||
// GetWXGroupList 获取微信群聊ID列表
|
||||
func (wxAccount *WXAccount) GetWXGroupList() []*wechat.ModContact {
|
||||
wxAccount.groupMapLock.Lock()
|
||||
defer wxAccount.groupMapLock.Unlock()
|
||||
|
||||
retList := make([]*wechat.ModContact, 0)
|
||||
for _, modContact := range wxAccount.groupMap {
|
||||
retList = append(retList, modContact)
|
||||
}
|
||||
return retList
|
||||
}
|
||||
|
||||
// SetLabelPairList 设置标签列表
|
||||
func (wxAccount *WXAccount) SetLabelPairList(labelList []*wechat.LabelPair) {
|
||||
wxAccount.labelMapLock.Lock()
|
||||
defer wxAccount.labelMapLock.Unlock()
|
||||
|
||||
labelCount := len(labelList)
|
||||
wxAccount.labelMap = make(map[uint32]*wechat.LabelPair)
|
||||
for index := 0; index < labelCount; index++ {
|
||||
tmpLabelPair := labelList[index]
|
||||
wxAccount.labelMap[tmpLabelPair.GetLabelId()] = tmpLabelPair
|
||||
}
|
||||
}
|
||||
|
||||
// 获取对应名称的LabelPair
|
||||
func (wxAccount *WXAccount) getLabelPairByName(labelName string) *wechat.LabelPair {
|
||||
for _, labelPair := range wxAccount.labelMap {
|
||||
if labelPair.GetLabelName() == labelName {
|
||||
return labelPair
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserListByLabel 根据Label名称获取好友列表
|
||||
func (wxAccount *WXAccount) GetUserListByLabel(labelName string) []string {
|
||||
wxAccount.labelMapLock.Lock()
|
||||
defer wxAccount.labelMapLock.Unlock()
|
||||
|
||||
// 先获取LabelPair
|
||||
tmpLabelPair := wxAccount.getLabelPairByName(labelName)
|
||||
if tmpLabelPair == nil {
|
||||
return []string{}
|
||||
}
|
||||
return wxAccount.getWXFriendListByLabelID(tmpLabelPair.GetLabelId())
|
||||
}
|
||||
|
||||
// ContainsLabel 判断好友是否属于某个标签
|
||||
func (wxAccount *WXAccount) ContainsLabel(strLabelList string, tmpLabel uint32) bool {
|
||||
if len(strLabelList) <= 0 {
|
||||
return false
|
||||
}
|
||||
// 判断是否属于标签
|
||||
labelList := strings.Split(strLabelList, ",")
|
||||
tmpStrLabel := strconv.Itoa(int(tmpLabel))
|
||||
tmpCount := len(labelList)
|
||||
for index := 0; index < tmpCount; index++ {
|
||||
if tmpStrLabel == labelList[index] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetBindQueryNewReq GetBindQueryNewReq
|
||||
func (wxAccount *WXAccount) GetBindQueryNewReq() (string, error) {
|
||||
tmpBindQueryNewReq := &baseinfo.BindQueryNewReq{}
|
||||
tmpBindQueryNewReq.BalanceVersion = wxAccount.userInfo.BalanceVersion
|
||||
tmpBindQueryNewReq.BindQueryScen = 1
|
||||
tmpBindQueryNewReq.BindTypeCond = "all_type"
|
||||
tmpBindQueryNewReq.ISRoot = 0
|
||||
tmpBindQueryNewReq.City = wxAccount.userProfile.GetUserInfo().GetCity()
|
||||
tmpBindQueryNewReq.Province = wxAccount.userProfile.GetUserInfo().GetProvince()
|
||||
tmpString := "balance_version=" + strconv.Itoa(int(tmpBindQueryNewReq.BalanceVersion))
|
||||
tmpString = tmpString + "&bind_query_scene=" + strconv.Itoa(int(tmpBindQueryNewReq.BindQueryScen))
|
||||
tmpString = tmpString + "&bind_type_cond=" + tmpBindQueryNewReq.BindTypeCond
|
||||
tmpString = tmpString + "&city=" + tmpBindQueryNewReq.City
|
||||
tmpString = tmpString + "&is_device_open_touch=" + strconv.Itoa(int(tmpBindQueryNewReq.ISDeviceOpenTouch))
|
||||
tmpString = tmpString + "&is_root=" + strconv.Itoa(int(tmpBindQueryNewReq.ISRoot))
|
||||
tmpString = tmpString + "&province=" + tmpBindQueryNewReq.Province
|
||||
wcPaySign, err := clientsdk.TenPaySignDes3(tmpString, "%^&*Tenpay!@#$")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tmpString = tmpString + "&WCPaySign=" + wcPaySign
|
||||
return tmpString, nil
|
||||
}
|
||||
21
srv/wxcore/wxbaserouter.go
Normal file
21
srv/wxcore/wxbaserouter.go
Normal 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
srv/wxcore/wxcache.go
Normal file
478
srv/wxcore/wxcache.go
Normal 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
|
||||
}
|
||||
1206
srv/wxcore/wxconnect.go
Normal file
1206
srv/wxcore/wxconnect.go
Normal file
File diff suppressed because it is too large
Load Diff
222
srv/wxcore/wxconnectmgr.go
Normal file
222
srv/wxcore/wxconnectmgr.go
Normal 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
srv/wxcore/wxfilehelpermgr.go
Normal file
165
srv/wxcore/wxfilehelpermgr.go
Normal 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
srv/wxcore/wxlongrequest.go
Normal file
17
srv/wxcore/wxlongrequest.go
Normal 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
srv/wxcore/wxmsghandler.go
Normal file
101
srv/wxcore/wxmsghandler.go
Normal 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
|
||||
}
|
||||
6502
srv/wxcore/wxreqinvoker.go
Normal file
6502
srv/wxcore/wxreqinvoker.go
Normal file
File diff suppressed because it is too large
Load Diff
32
srv/wxcore/wxresponse.go
Normal file
32
srv/wxcore/wxresponse.go
Normal 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
srv/wxcore/wxserver.go
Normal file
78
srv/wxcore/wxserver.go
Normal 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
srv/wxcore/wxsyncmgr.go
Normal file
110
srv/wxcore/wxsyncmgr.go
Normal 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
srv/wxcore/wxtaskmgr.go
Normal file
108
srv/wxcore/wxtaskmgr.go
Normal 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
srv/wxcore/wxtry.go
Normal file
18
srv/wxcore/wxtry.go
Normal 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
srv/wxcore/wxusermsgmgr.go
Normal file
150
srv/wxcore/wxusermsgmgr.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
49
srv/wxface/iwxcache.go
Normal file
49
srv/wxface/iwxcache.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package wxface
|
||||
|
||||
import (
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
)
|
||||
|
||||
// IWXCache 缓存接口
|
||||
type IWXCache interface {
|
||||
// 设置Qrcode信息
|
||||
SetQrcodeInfo(qrcodeInfo *baseinfo.QrcodeInfo)
|
||||
// 获取二维码信息
|
||||
GetQrcodeInfo() *baseinfo.QrcodeInfo
|
||||
// 获取收藏缓存
|
||||
GetFavInfoCache() *baseinfo.FavInfoCache
|
||||
// 设置初始化联系人状态
|
||||
SetInitContactFinished(bFlag bool)
|
||||
// 设置初始化同步信息状态
|
||||
SetInitNewSyncFinished(bFlag bool)
|
||||
// 设置初始化收藏同步信息状态
|
||||
SetInitFavSyncFinished(bFlag bool)
|
||||
// 初始化联系人是否完成
|
||||
IsInitContactFinished() bool
|
||||
// 初始化同步信息是否完成
|
||||
IsInitNewSyncFinished() bool
|
||||
// 初始化同步信息是否完成
|
||||
IsInitFavSyncFinished() bool
|
||||
// 所有初始化是否完成
|
||||
IsInitFinished() bool
|
||||
// 设置发送使用说明初始化状态
|
||||
SetIsInitFinished(bFlag bool)
|
||||
// 使用说明命令
|
||||
SendUsageByText()
|
||||
// 发送使用说明
|
||||
SendUsage()
|
||||
// 扫码完成
|
||||
SetScanFinish(bFlag bool)
|
||||
// 设置初始化通讯录的标志
|
||||
SetContactSeq(contactSeq uint32)
|
||||
// 获取初始化通讯录的标志
|
||||
GetContactSeq() uint32
|
||||
// 新增联系人WXID列表
|
||||
AddInitContactWxidList(contactWxidList []string)
|
||||
// 获取指定数量的联系人微信ID列表
|
||||
GetNextInitContactWxidList(count uint32) []string
|
||||
// 获取全部联系人Wxid
|
||||
GetAllContactList() []string
|
||||
// 清空缓存
|
||||
Clear()
|
||||
}
|
||||
60
srv/wxface/iwxconnect.go
Normal file
60
srv/wxface/iwxconnect.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package wxface
|
||||
|
||||
import (
|
||||
"xiawan/wx/srv"
|
||||
)
|
||||
|
||||
// IWXConnect 微信链接接口
|
||||
type IWXConnect interface {
|
||||
// 开启
|
||||
Start() error
|
||||
// 关闭
|
||||
Stop()
|
||||
// 设置微信链接ID
|
||||
SetWXConnID(wxConnID uint32)
|
||||
// 获取WX链接ID
|
||||
GetWXConnID() uint32
|
||||
// 获取微信服务器
|
||||
GetWXServer() IWXServer
|
||||
// 获取微信帐号信息
|
||||
GetWXAccount() *srv.WXAccount
|
||||
// 获取缓存器
|
||||
GetWXCache() IWXCache
|
||||
// 获取调用器
|
||||
GetWXReqInvoker() IWXReqInvoker
|
||||
// 获取任务管理器
|
||||
GetWXTaskMgr() IWXTaskMgr
|
||||
// 获取同步管理器
|
||||
GetWXSyncMgr() IWXSyncMgr
|
||||
// 获取文件助手消息管理器
|
||||
GetWXFileHelperMgr() IWXFileHelperMgr
|
||||
// 获取好友消息管理器
|
||||
GetWXFriendMsgMgr() IWXUserMsgMgr
|
||||
// 判断是否处于链接状态
|
||||
IsConnected() bool
|
||||
// 发送给消息队列去处理
|
||||
SendToWXMsgHandler(wxResp IWXResponse)
|
||||
// 添加到长链接请求队列
|
||||
SendToWXLongReqQueue(wxLongReq IWXLongRequest)
|
||||
// 添加到长链接请求队列
|
||||
SendWebTask(status string, taskType uint32)
|
||||
// 等待 waitTimes后发送心跳包
|
||||
SendHeartBeatWaitingSeconds(seconds uint32)
|
||||
// 等待 waitTimes后发送二次登录包
|
||||
SendAutoAuthWaitingMinutes(minutes uint32)
|
||||
// 添加群二维码
|
||||
AddGroupQrcodeData(fileData []byte, fileName string)
|
||||
// 开始下载群二维码
|
||||
DumpGroupQrcode()
|
||||
// CheckOnLineStatus 检查在线状态
|
||||
CheckOnLineStatus() bool
|
||||
CheckOnLineStatusLogin() bool
|
||||
|
||||
// 获取上次心跳时间
|
||||
GetHeartBeatTime() int64
|
||||
// 设置上次心跳时间
|
||||
SetHeartBeatTime(time int64)
|
||||
|
||||
// 关闭
|
||||
StopShortReader()
|
||||
}
|
||||
13
srv/wxface/iwxconnectmgr.go
Normal file
13
srv/wxface/iwxconnectmgr.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package wxface
|
||||
|
||||
// IWXConnectMgr 微信链接管理器
|
||||
type IWXConnectMgr interface {
|
||||
Add(wxConnect IWXConnect) // 添加链接
|
||||
GetWXConnectByUserInfoUUID(userInfoUUID string) IWXConnect // 根据UserInfoUUID获取微信链接
|
||||
GetWXConnectByWXID(wxid string) IWXConnect // 根据WXID获取微信链接
|
||||
Remove(wxconn IWXConnect) // 删除连接
|
||||
Len() int // 获取当前连接
|
||||
ClearWXConn() // 删除并停止所有链接
|
||||
ShowConnectInfo() string // 打印链接数量
|
||||
GetConnectInfo() map[string]interface{} // 打印链接信息
|
||||
}
|
||||
14
srv/wxface/iwxfilehelpermgr.go
Normal file
14
srv/wxface/iwxfilehelpermgr.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package wxface
|
||||
|
||||
// IWXFileHelperMgr 文件传输助手消息管理器
|
||||
type IWXFileHelperMgr interface {
|
||||
Start()
|
||||
Stop()
|
||||
AddNewTipMsg(newMsg string)
|
||||
AddNewCardMsg(newMsg string)
|
||||
AddImageMsg(imgData []byte)
|
||||
// 转发图片
|
||||
ForwardImageMsg(imgData []byte)
|
||||
// 转发表情包
|
||||
ForwardEmoticonMsg(imgData []byte)
|
||||
}
|
||||
29
srv/wxface/iwxgrabhbmgr.go
Normal file
29
srv/wxface/iwxgrabhbmgr.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package wxface
|
||||
|
||||
import "xiawan/wx/clientsdk/baseinfo"
|
||||
|
||||
// IWXGrabHBMgr 自动抢红包管理器
|
||||
type IWXGrabHBMgr interface {
|
||||
// 开始抢红包协程
|
||||
Start()
|
||||
// 结束抢红包协程
|
||||
Stop()
|
||||
// 抢下一个红包
|
||||
GrapNext()
|
||||
// 添加红包项
|
||||
AddHBItem(hbItem *baseinfo.HongBaoItem)
|
||||
// 获取当前正在抢的红包项
|
||||
GetCurrentHBItem() *baseinfo.HongBaoItem
|
||||
// 是否开启自动抢红包功能
|
||||
IsAutoGrap() bool
|
||||
// 设置自动抢红包开关
|
||||
SetAutoGrap(bFlag bool)
|
||||
//设置抢红包自动回复
|
||||
SetAutoReply(bFlag bool)
|
||||
//设置延迟抢红包时间
|
||||
SetDelayOpen(bFlag int)
|
||||
//是否抢红包自动回复
|
||||
IsAutoReply()
|
||||
//获取延迟时间
|
||||
GetDelayOpen()
|
||||
}
|
||||
7
srv/wxface/iwxlongrequest.go
Normal file
7
srv/wxface/iwxlongrequest.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package wxface
|
||||
|
||||
// IWXLongRequest 微信请求
|
||||
type IWXLongRequest interface {
|
||||
GetOpcode() uint32
|
||||
GetData() []byte
|
||||
}
|
||||
9
srv/wxface/iwxmsghandler.go
Normal file
9
srv/wxface/iwxmsghandler.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package wxface
|
||||
|
||||
// IWXMsgHandler 微信响应处理器
|
||||
type IWXMsgHandler interface {
|
||||
AddRouter(respID uint32, wxRouter IWXRouter) // 为消息添加具体的处理逻辑
|
||||
GetRouterByRespID(urlID uint32) IWXRouter // 获取对应的路由处理器
|
||||
StartWorkerPool() // 启动worker工作池
|
||||
SendWXRespToTaskQueue(response IWXResponse) // 将消息交给TaskQueue,由worker进行处理
|
||||
}
|
||||
344
srv/wxface/iwxreqinvoker.go
Normal file
344
srv/wxface/iwxreqinvoker.go
Normal file
@@ -0,0 +1,344 @@
|
||||
package wxface
|
||||
|
||||
import (
|
||||
"xiawan/wx/api/req"
|
||||
"xiawan/wx/api/vo"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
)
|
||||
|
||||
// IWXReqInvoker 微信请求调用器
|
||||
type IWXReqInvoker interface {
|
||||
// 发送登录短信
|
||||
SendWxBindOpMobileForRequest(OpCode int64, PhoneNumber string, VerifyCode string) (*wechat.BindOpMobileForRegResponse, error)
|
||||
// 获取登录二维码
|
||||
SendGetLoginQrcodeRequest() (*wechat.LoginQRCodeResponse, error)
|
||||
// 获取登录二维码(直登)
|
||||
SendGetLoginQrcodeRequestDirect() (*wechat.LoginQRCodeResponse, error)
|
||||
// 获取登录二维码(绕过验证码)
|
||||
SendGetLoginQrcodeRequestX() (*wechat.LoginQRCodeResponse, error)
|
||||
// 检测登录二维码状态
|
||||
SendCheckLoginQrcodeRequest(qrcodeUUID string, qrcodeKey []byte) error
|
||||
// SendHybridManualAutoRequest
|
||||
SendHybridManualAutoRequest(newPass string, wxID string, ver byte) error
|
||||
// 发送登陆请求
|
||||
SendManualAuthRequest(newPass string, wxID string) error
|
||||
// 发送登录请求根据设备Id进行登录
|
||||
SendManualAuthByDeviceIdRequest() error
|
||||
// 发送获取deviceToken请求
|
||||
SendDeviceTokenRequest() (*wechat.TrustResp, error)
|
||||
// 获取设备
|
||||
SendGetSafetyInfoRequest() (*wechat.GetSafetyInfoResponse, error)
|
||||
// 删除设备
|
||||
SendDelSafeDeviceRequest(deviceUUID string) (*wechat.DelSafeDeviceResponse, error)
|
||||
// 获取硬件设备情况
|
||||
SendGetBoundHardDeviceRequest() (*wechat.GetBoundHardDevicesResponse, error)
|
||||
// 检测微信登录环境
|
||||
SendCheckCanSetAliasRequest() (*wechat.CheckCanSetAliasResp, error)
|
||||
// 发送心跳包
|
||||
SendHeartBeatRequest() error
|
||||
// 发送短链接心跳
|
||||
SendHeartBeatShortRequest() (*wechat.HeartBeatResponse, int32, error)
|
||||
// 发送同步请求; 真正的同步消息接口; 新消息都需要从此接口同步
|
||||
SendNewSyncRequest(scene uint32) error
|
||||
// 获取微信账号配置信息
|
||||
SendGetProfileRequest() error
|
||||
SendGetProfileNewRequest() (*wechat.GetProfileResponse, error)
|
||||
// 同步消息
|
||||
SendWxSyncMsg(key string) (*wechat.NewSyncResponse, error)
|
||||
|
||||
SendNewInitSyncRequest() error
|
||||
// 会重新链接服务器 发送Token登陆请求
|
||||
SendAutoAuthRequest() error
|
||||
// 发送二维码二次登录; 扫码唤醒登录
|
||||
SendPushQrLoginNotice() (*wechat.PushLoginURLResponse, error)
|
||||
// 发送初始化联系人请求
|
||||
SendInitContactRequest(contactSeq uint32) error
|
||||
// 分页获取联系人
|
||||
SendGetContactListPageRequest(CurrentWxcontactSeq uint32, CurrentChatRoomContactSeq uint32) (*wechat.InitContactResp, error)
|
||||
// 批量获取联系人详情
|
||||
SendBatchGetContactBriefInfoReq(userWxidList []string) error
|
||||
// 获取联系人信息列表
|
||||
SendGetContactRequest(userInfoList []string, antisPanTicketList []string, chatRoomWxidList []string, needResp bool) (*wechat.GetContactResponse, error)
|
||||
// 获取联系人信息列表(优先本地缓存)
|
||||
SendGetContactRequestForCache(userWxid string, isCache bool) (*wechat.ModContact, *wechat.VerifyUserValidTicket, error)
|
||||
// 获取联系人信息列表
|
||||
SendGetContactRequestForHB(userWxid string) (*wechat.GetContactResponse, error)
|
||||
// 获取联系人信息列表List
|
||||
SendGetContactRequestForList(userInfoList []string, roomWxIDList []string) (*wechat.GetContactResponse, error)
|
||||
// 获取好友关系状态
|
||||
SendGetFriendRelationRequest(userName string) (*wechat.MMBizJsApiGetUserOpenIdResponse, error)
|
||||
// 接收红包
|
||||
SendReceiveWxHBRequest(hbItem *baseinfo.HongBaoItem) error
|
||||
// 打开红包
|
||||
SendOpenWxHBRequest(hbItem *baseinfo.HongBaoItem, timingIdentifier string) error
|
||||
// 拆红包
|
||||
SendOpenRedEnvelopesRequest(hbItem *baseinfo.HongBaoItem) (*wechat.HongBaoRes, error)
|
||||
// 接收转账
|
||||
SendReceiveZZ(transferItem *baseinfo.TenPayReqItem, wcPayInfo *baseinfo.WCPayInfo2) error
|
||||
// 创建红包
|
||||
SendWXCreateRedPacketRequest(hbItem *baseinfo.RedPacket) (*wechat.HongBaoRes, error)
|
||||
// 查看红包详情
|
||||
SendRedEnvelopesDetailRequest(hbItem *baseinfo.HongBaoItem) (*wechat.HongBaoRes, error)
|
||||
// 查看红包列表
|
||||
SendGetRedPacketListRequest(hbItem *baseinfo.GetRedPacketList) (*wechat.HongBaoRes, error)
|
||||
// 创建转账
|
||||
SendCreatePreTransferRequest(transferItem *req.CreatePreTransfer) (*baseinfo.PreTransferResp, error)
|
||||
// 确认转账
|
||||
SendConfirmPreTransferRequest(transferItem *req.ConfirmPreTransfer) (*wechat.TenPayResponse, error)
|
||||
// 发送消息
|
||||
SendTextMsgRequest(toUserName string, content string, atWxIDList []string, ContentType int) (*wechat.NewSendMsgResponse, error)
|
||||
// 发送消息给文件助手
|
||||
SendTextMsgToFileHelperRequest(content string) error
|
||||
// 发送名片给文件助手
|
||||
SendCardMsgToFileHelperRequest(content string) error
|
||||
// 发送Oplog请求
|
||||
SendOplogRequest(modifyItems []*baseinfo.ModifyItem) error
|
||||
// 发送企业Oplog请求
|
||||
SendQWOpLogRequest(cmdId int64, value []byte) error
|
||||
// 获取群/个人二维码(封号;限制功能)
|
||||
SendGetQRCodeRequest(userName string) error
|
||||
// 退出登陆
|
||||
SendLogoutRequest() error
|
||||
// 同步收藏
|
||||
SendFavSyncRequest() error
|
||||
SendFavSyncRequestResult() (*wechat.FavSyncResponse, error)
|
||||
SendFavSyncListRequestResult(keyBuf string) (*wechat.SyncResponse, error)
|
||||
// 获取收藏信息
|
||||
SendGetFavInfoRequest() error
|
||||
SendGetFavInfoRequestResult() (*wechat.GetFavInfoResponse, error)
|
||||
// 获取收藏项详情
|
||||
SendBatchGetFavItemRequest(favID uint32) error
|
||||
SendBatchGetFavItemRequestResult(favID uint32) (*wechat.BatchGetFavItemResponse, error)
|
||||
// 删除收藏
|
||||
SendBatchDelFavItemRequest(favID uint32) error
|
||||
SendBatchDelFavItemRequestResult(favID uint32) (*wechat.BatchDelFavItemResponse, error)
|
||||
// 获取CdnDns信息
|
||||
SendGetCDNDnsRequest() error
|
||||
// 发送朋友圈
|
||||
SendSnsPostRequest(postItem *baseinfo.SnsPostItem) error
|
||||
// 发送朋友圈
|
||||
SendSnsPostRequestNew(postItem *baseinfo.SnsPostItem) (*wechat.SnsPostResponse, error)
|
||||
// 设置朋友圈可见天数
|
||||
SetFriendCircleDays(postItem *req.SetFriendCircleDaysModel) error
|
||||
// 操作朋友圈
|
||||
SendSnsObjectOpRequest(opItems []*baseinfo.SnsObjectOpItem) (*wechat.SnsObjectOpResponse, error)
|
||||
// 上传文件
|
||||
UploadAppAttach(fileData []byte) (*wechat.UploadAppAttachResponse, error)
|
||||
// 获取指定好友朋友圈
|
||||
SendSnsUserPageRequest(userName string, firstPageMd5 string, maxID uint64, needResp bool) (*wechat.SnsUserPageResponseNew, error)
|
||||
// 同步转发朋友圈
|
||||
SendSnsPostRequestByXML(timeLineObj *baseinfo.TimelineObject, blackList []string) error
|
||||
// 获取指定的朋友圈详情
|
||||
SendSnsObjectDetailRequest(snsID uint64) (*wechat.SnsObject, error)
|
||||
// 获取朋友圈首页
|
||||
SendSnsTimeLineRequest(firstPageMD5 string, maxID uint64) error
|
||||
SendSnsTimeLineRequestResult(firstPageMD5 string, maxID uint64) (*wechat.SnsTimeLineResponse, error)
|
||||
// 发送评论/点赞请求
|
||||
SendSnsCommentRequest(commentItem *baseinfo.SnsCommentItem) error
|
||||
// 同步朋友圈
|
||||
SendSnsSyncRequest(toHandler bool) (*wechat.SnsSyncResponse, error)
|
||||
// 获取联系人标签列表
|
||||
SendGetContactLabelListRequest(needResp bool) (*wechat.GetContactLabelListResponse, error)
|
||||
// 添加标签
|
||||
SendAddContactLabelRequest(newLabelList []string, needResp bool) (*wechat.AddContactLabelResponse, error)
|
||||
// 删除标签
|
||||
SendDelContactLabelRequest(labelId string) (*wechat.DelContactLabelResponse, error)
|
||||
// 修改标签
|
||||
SendModifyLabelRequest(userLabelList []baseinfo.UserLabelInfoItem) (*wechat.ModifyContactLabelListResponse, error)
|
||||
// 查询钱包信息
|
||||
SendBindQueryNewRequest(reqItem *baseinfo.TenPayReqItem) error
|
||||
// 获取余额以及银行卡信息
|
||||
SendBandCardRequest(reqItem *baseinfo.TenPayReqItem) (*wechat.TenPayResponse, error)
|
||||
// 支付方法
|
||||
SendTenPayRequest(reqItem *baseinfo.TenPayReqItem) (*wechat.TenPayResponse, error)
|
||||
// 下载请求
|
||||
SendCdnDownloadReuqest(downItem *baseinfo.DownMediaItem) (*baseinfo.CdnDownloadResponse, error)
|
||||
// 下载图片
|
||||
GetMsgBigImg(m req.DownloadParam) (*wechat.GetMsgImgResponse, error)
|
||||
// 下载视频数据
|
||||
GetMsgVideo(m req.DownloadParam) (*wechat.DownloadVideoResponse, error)
|
||||
// Cdn上传高清图片
|
||||
SendCdnSnsUploadImageReuqest(imgData []byte) (*baseinfo.CdnSnsImageUploadResponse, error)
|
||||
// 发送CDN朋友圈视频下载请求
|
||||
SendCdnSnsVideoDownloadReuqest(encKey uint64, tmpURL string) ([]byte, error)
|
||||
// 发送CDN朋友圈上传视频请求
|
||||
SendCdnSnsVideoUploadReuqest(videoData []byte, thumbData []byte) (*baseinfo.CdnSnsVideoUploadResponse, error)
|
||||
// Cdn发送图片给好友
|
||||
SendCdnUploadImageReuqest(imgData []byte, toUserName string) (bool, error)
|
||||
// Cdn发送图片给好友并返回详细信息
|
||||
SendCdnUploadImageReuqestWithDetails(imgData []byte, toUserName string) (*baseinfo.CdnImageUploadResponse, string, error)
|
||||
// Cdn发送图片给好友并返回详细信息调试
|
||||
SendCdnUploadImageReuqestWithSource(imgData []byte, toUserName string, sourceValue uint32) (*baseinfo.CdnImageUploadResponse, string, error)
|
||||
// 发送图片
|
||||
SendUploadImageNewRequest(imgData []byte, toUserName string) (*wechat.UploadMsgImgResponse, error)
|
||||
// cdn发送视频
|
||||
SendCdnUploadVideoRequest(toUserName string, imgData []byte, videoData []byte) (*baseinfo.CdnMsgVideoUploadResponse, error)
|
||||
// Cdn发送图片给文件传输助手
|
||||
SendImageToFileHelper(imgData []byte) (bool, error)
|
||||
// 转发图片
|
||||
ForwardCdnImageRequest(item baseinfo.ForwardImageItem) (*wechat.UploadMsgImgResponse, error)
|
||||
// 转发视频
|
||||
ForwardCdnVideoRequest(item baseinfo.ForwardVideoItem) (*wechat.UploadVideoResponse, error)
|
||||
// 发送app消息
|
||||
SendAppMessage(msgXml, toUSerName string, contentType uint32) (*wechat.SendAppMsgResponse, error)
|
||||
// SendEmojiRequest 发送表情
|
||||
SendEmojiRequest(md5 string, toUSerName string, length int32) (*wechat.SendAppMsgResponse, error)
|
||||
// 发送表情new 动图
|
||||
ForwardEmojiRequest(md5 string, toUSerName string, length int32) (*wechat.UploadEmojiResponse, error)
|
||||
// 群发文字
|
||||
SendGroupMassMsgTextRequest(toUserName []string, content string) (*wechat.MassSendResponse, error)
|
||||
// 群发图片
|
||||
SendGroupMassMsgImageRequest(toUserName []string, ImageBase64 []byte) (*wechat.MassSendResponse, error)
|
||||
// 群拍一拍
|
||||
SendSendPatRequest(chatRoomName string, toUserName string, scene int64) (*wechat.SendPatResponse, error)
|
||||
// 下载语音
|
||||
SendGetMsgVoiceRequest(toUserName, newMsgId, bufid string, length int) (*vo.DownloadVoiceData, error)
|
||||
// 群发
|
||||
// 设置群公告
|
||||
SetChatRoomAnnouncementRequest(roomId, content string) (*wechat.SetChatRoomAnnouncementResponse, error)
|
||||
// 获取群成员详细
|
||||
GetChatroomMemberDetailRequest(roomId string) (*wechat.GetChatroomMemberDetailResponse, error)
|
||||
// 同意进入群聊
|
||||
ConsentToJoinGroupRequest(url string) (*wechat.JoinChatRoomResponse, error)
|
||||
// 获取群详细
|
||||
SetGetChatRoomInfoDetailRequest(roomId string) (*wechat.GetChatRoomInfoDetailRequest, error)
|
||||
// 退出群聊
|
||||
GetQuitChatroomRequest(chatRoomName string) error
|
||||
// 创建群
|
||||
SendCreateChatRoomRequest(topIc string, userList []string) (*wechat.CreateChatRoomResponse, error)
|
||||
// 邀请群成员
|
||||
SendInviteChatroomMembersRequest(chatRoomName string, userList []string) (*wechat.CreateChatRoomResponse, error)
|
||||
// 添加好友进群
|
||||
SendAddChatRoomMemberRequest(chatRoomName string, userList []string) (*wechat.AddChatRoomMemberResponse, error)
|
||||
// 删除群成员
|
||||
SendDelDelChatRoomMemberRequest(chatRoomName string, delUserList []string) (*wechat.DelChatRoomMemberResponse, error)
|
||||
// 转让群
|
||||
SendTransferGroupOwnerRequest(chatRoomName, newOwnerUserName string) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 添加群管理
|
||||
SendAddChatroomAdminRequest(chatRoomName string, userList []string) (*wechat.AddChatRoomAdminResponse, error)
|
||||
// 删除群管理
|
||||
SendDelChatroomAdminRequest(chatRoomName string, userList []string) (*wechat.DelChatRoomAdminResponse, error)
|
||||
// 获取群列表
|
||||
SendWXSyncContactRequest() (*vo.GroupData, error)
|
||||
// 链接授权
|
||||
GetA8KeyRequest(opCode, scene uint32, reqUrl string, getType baseinfo.GetA8KeyType) (*wechat.GetA8KeyResp, error)
|
||||
// 小程序授权
|
||||
JSLoginRequest(appId string) (*wechat.JSLoginResponse, error)
|
||||
// 小程序云函数操作
|
||||
JSOperateWxDataRequest(appId string, opt int32, data string) (*wechat.JSOperateWxDataResponse, error)
|
||||
// APP 授权
|
||||
SdkOauthAuthorizeRequest(appId string, sdkName string, packageName string) (*wechat.SdkOauthAuthorizeConfirmNewResp, error)
|
||||
// 搜索好友
|
||||
SendSearchContactRequest(opCode, fromScene, searchScene uint32, userName string) (*wechat.SearchContactResponse, error)
|
||||
// 好友验证/加好友/关注公众号
|
||||
VerifyUserRequest(opCode uint32, verifyContent string, scene int, V3, V4, ChatRoomUserName string) (*wechat.VerifyUserResponse, error)
|
||||
// 上传手机通讯录好友
|
||||
UploadMContact(mobile string, mobileList []string, opcode int32) (*wechat.UploadMContactResponse, error)
|
||||
// 获取手机通讯录好友
|
||||
GetMFriend() (*wechat.GetMFriendResponse, error)
|
||||
// 获取证书
|
||||
SendCertRequest() (*wechat.GetCertResponse, error)
|
||||
// 发送二维码授权请求
|
||||
SendQRConnectAuthorize(qrUrl string) (*wechat.QRConnectAuthorizeResp, error)
|
||||
// 发送二维码授权请求确认
|
||||
SendQRConnectAuthorizeConfirm(qrUrl string) (*wechat.SdkOauthAuthorizeConfirmNewResp, error)
|
||||
// 授权链接
|
||||
SendGetMpA8Request(url string, opcode uint32) (*wechat.GetA8KeyResp, error)
|
||||
// 获取登录设备信息
|
||||
SendOnlineInfo() (*wechat.GetOnlineInfoResponse, error)
|
||||
// 获取(群聊/个人)二维码
|
||||
SendGetQrCodeRequest(id string, style uint32) (*wechat.GetQRCodeResponse, error)
|
||||
// 查看附近的人
|
||||
SendGetPeopleNearbyResultRequest(longitude float32, latitude float32) (*wechat.LbsResponse, error)
|
||||
// 撤销消息
|
||||
SendRevokeMsgRequest(newMsgId string, clientMsgId uint64, toUserName string) (*wechat.RevokeMsgResponse, error)
|
||||
// 撤回消息New
|
||||
SendRevokeMsgRequestNew(m req.RevokeMsgModel) (*wechat.RevokeMsgResponse, error)
|
||||
// 删除好友
|
||||
SendDelContactRequest(userName string) error
|
||||
// 修改资料
|
||||
SendModifyUserInfoRequest(city, country, nickName, province, signature string, sex uint32, initFlag uint32) error
|
||||
// 修改昵称
|
||||
SendUpdateNickNameRequest(cmd uint32, val string) error
|
||||
// 设置姓名
|
||||
SetNickNameService(cmd uint32, val string) error
|
||||
// 设置性别
|
||||
SetSexService(val uint32, country string, city string, province string) error
|
||||
// 修改加好友需要验证属性
|
||||
UpdateAutopassRequest(SwitchType uint32) error
|
||||
// 修改头像
|
||||
UploadHeadImage(base64 string) (*wechat.UploadHDHeadImgResponse, error)
|
||||
// 修改密码
|
||||
SendChangePwdRequest(oldPwd, NewPwd string, OpCode uint32) (*wechat.BaseResponse, error)
|
||||
// 修改备注
|
||||
SendModifyRemarkRequest(userName string, remarkName string) error
|
||||
// 发送语音
|
||||
SendUploadVoiceRequest(toUserName string, voiceData string, voiceSecond, voiceFormat int32) (*wechat.UploadVoiceResponse, error)
|
||||
// 设置微信号
|
||||
SetWechatRequest(alisa string) (*wechat.GeneralSetResponse, error)
|
||||
// 设置微信步数
|
||||
UpdateStepNumberRequest(number uint64) (*wechat.UploadDeviceStepResponse, error)
|
||||
// 获取步数列表
|
||||
SendGetUserRankLikeCountRequest(rankId string) (*wechat.GetUserRankLikeCountResponse, error)
|
||||
// 提取企业 WX 详情
|
||||
SendQWContactRequest(openIm, chatRoom, t string) (*wechat.GetQYContactResponse, error)
|
||||
// 提取全部的企业通寻录
|
||||
SendQWSyncContactRequest() (*wechat.GetQYContactResponse, error)
|
||||
// 备注企业
|
||||
SendQWRemarkRequest(toUserName string, name string) error
|
||||
// 创建企业群
|
||||
SendQWCreateChatRoomRequest(userList []string) (*wechat.CreateQYChatRoomResponese, error)
|
||||
// 搜手机或企业对外名片链接提取验证
|
||||
SendQWSearchContactRequest(tg string, fromScene uint64, userName string) (*wechat.SearchQYContactResponse, error)
|
||||
// 向企业微信打招呼
|
||||
SendQWApplyAddContactRequest(toUserName, v1, Content string) error
|
||||
// 单向加企业微信
|
||||
SendQWAddContactRequest(toUserName, v1, Content string) error
|
||||
// 拉取企业微信群
|
||||
SendQWSyncChatRoomRequest(key string) (*vo.QYChatroomContactVo, error)
|
||||
// 转让企业群
|
||||
SendQWChatRoomTransferOwnerRequest(chatRoomName string, toUserName string) (*wechat.BaseResponse, error)
|
||||
// 直接拉好友进群
|
||||
SendQWAddChatRoomMemberRequest(chatRoomName string, toUserName []string) (*wechat.QYAddChatRoomMemberResponse, error)
|
||||
// 发送群邀请链接
|
||||
SendQWInviteChatRoomMemberRequest(chatRoomName string, toUserName []string) (*wechat.BaseResponse, error)
|
||||
// 删除企业群群成员
|
||||
SendQWDelChatRoomMemberRequest(chatRoomName string, toUserName []string) (*wechat.QYDelChatRoomMemberResponse, error)
|
||||
// 提取企业群全部成员
|
||||
SendQWGetChatRoomMemberRequest(chatRoomName string) (*wechat.GetQYChatroomMemberDetailResponse, error)
|
||||
// 提取企业群名称公告设定等信息
|
||||
SendQWGetChatroomInfoRequest(chatRoomName string) (*wechat.QYChatroomContactResponse, error)
|
||||
// 提取企业群二维码
|
||||
SendQWGetChatRoomQRRequest(chatRoomName string) (*wechat.QYGetQRCodeResponse, error)
|
||||
// 增加企业管理员
|
||||
SendQWAppointChatRoomAdminRequest(chatRoomName string, toUserName []string) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 移除企业群管理员
|
||||
SendQWDelChatRoomAdminRequest(chatRoomName string, toUserName []string) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 同意进企业群
|
||||
SendQWAcceptChatRoomRequest(link string, opcode uint32) (*wechat.GetA8KeyResp, error)
|
||||
// 设定企业群管理审核进群
|
||||
SendQWAdminAcceptJoinChatRoomSetRequest(chatRoomName string, p int64) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 群管理批准进企业群 1
|
||||
SendQWAdminAcceptJoinChatRoomRequest(chatRoomName, key, toUserName string, toUserNames []string) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 修改企业群名称
|
||||
SendQWModChatRoomNameRequest(chatRoomName, name string) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 修改成员在群中呢称
|
||||
SendQWModChatRoomMemberNickRequest(chatRoomName, name string) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 发布企业群公告
|
||||
SendQWChatRoomAnnounceRequest(chatRoomName, Announcement string) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 删除企业群
|
||||
SendQWDelChatRoomRequest(chatRoomName string) (*wechat.TransferChatRoomOwnerResponse, error)
|
||||
// 视频号搜索
|
||||
SendGetFinderSearchRequest(Index uint32, Userver int32, UserKey string, Uuid string) (*wechat.FinderSearchResponse, error)
|
||||
// 视频号个人中心
|
||||
SendFinderUserPrepareRequest(uServer int32) (*wechat.FinderUserPrepareResponse, error)
|
||||
// 视频号关注
|
||||
SendFinderFollowRequest(FinderUserName string, OpType int32, RefObjectId string, Cook string, Userver int32, PosterUsername string) (*wechat.FinderFollowResponse, error)
|
||||
// 扫码事件上报 (CGI 8887)
|
||||
SendScanQrcodeEventReportRequest(loginUrl string) (*wechat.ScanQrcodeEventReportRequest, error)
|
||||
// 微信小店获取确认信息 (CGI 971)
|
||||
SendExtDeviceLoginConfirmGetRequest(loginUrl string) (*wechat.ExtDeviceLoginConfirmGetResponse, error)
|
||||
// 微信小店确认登录 (CGI 972)
|
||||
SendExtDeviceLoginConfirmOkRequest(loginUrl string) (*wechat.ExtDeviceLoginConfirmOkResponse, error)
|
||||
}
|
||||
11
srv/wxface/iwxresponse.go
Normal file
11
srv/wxface/iwxresponse.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package wxface
|
||||
|
||||
import "xiawan/wx/clientsdk/baseinfo"
|
||||
|
||||
// IWXResponse 微信请求接口
|
||||
type IWXResponse interface {
|
||||
// 获取请求数据
|
||||
GetPackHeader() *baseinfo.PackHeader
|
||||
// 获取WXConncet
|
||||
GetWXConncet() IWXConnect
|
||||
}
|
||||
8
srv/wxface/iwxrouter.go
Normal file
8
srv/wxface/iwxrouter.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package wxface
|
||||
|
||||
// IWXRouter 微信消息处理路由
|
||||
type IWXRouter interface {
|
||||
PreHandle(response IWXResponse) error //在处理conn业务之前的钩子方法
|
||||
Handle(response IWXResponse) error //处理conn业务的方法
|
||||
PostHandle(response IWXResponse) error //处理conn业务之后的钩子方法
|
||||
}
|
||||
17
srv/wxface/iwxserver.go
Normal file
17
srv/wxface/iwxserver.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package wxface
|
||||
|
||||
import "xiawan/wx/srv"
|
||||
|
||||
// IWXServer 微信服务
|
||||
type IWXServer interface {
|
||||
Start()
|
||||
GetWXMsgHandler() IWXMsgHandler
|
||||
GetWXConnectMgr() IWXConnectMgr
|
||||
GetWXFileMgr() *srv.WXFileMgr
|
||||
AddWXRouter(funcID uint32, wxRouter IWXRouter)
|
||||
|
||||
// UpdateExpiryDate 更新授权码过期时间
|
||||
UpdateExpiryDate(key, expiryDate string)
|
||||
// 更新禁用状态
|
||||
UpdateDisable(key string, disable int)
|
||||
}
|
||||
12
srv/wxface/iwxsyncmgr.go
Normal file
12
srv/wxface/iwxsyncmgr.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package wxface
|
||||
|
||||
// IWXSyncMgr 消息同步管理器
|
||||
type IWXSyncMgr interface {
|
||||
Start()
|
||||
Stop()
|
||||
|
||||
// 发送同步请求
|
||||
SendNewSyncRequest()
|
||||
SendFavSyncRequest()
|
||||
SendSyncInitRequest()
|
||||
}
|
||||
7
srv/wxface/iwxtaskmgr.go
Normal file
7
srv/wxface/iwxtaskmgr.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package wxface
|
||||
|
||||
// IWXTaskMgr 任务管理器
|
||||
type IWXTaskMgr interface {
|
||||
Start()
|
||||
Stop()
|
||||
}
|
||||
8
srv/wxface/iwxusermsgmgr.go
Normal file
8
srv/wxface/iwxusermsgmgr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package wxface
|
||||
|
||||
type IWXUserMsgMgr interface {
|
||||
Start()
|
||||
Stop()
|
||||
AddNewTextMsg(newMsg, toUSerName string)
|
||||
AddImageMsg(imgData []byte, toUSerName string)
|
||||
}
|
||||
83
srv/wxfilemgr.go
Normal file
83
srv/wxfilemgr.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package srv
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var baseDIR = string("/.source")
|
||||
|
||||
// FileInfo 文件信息
|
||||
type FileInfo struct {
|
||||
FileData []byte
|
||||
FileName string
|
||||
}
|
||||
|
||||
// WXFileMgr 文件管理器
|
||||
type WXFileMgr struct {
|
||||
fileInfoChan chan *FileInfo
|
||||
currentDirName string
|
||||
endChan chan bool
|
||||
}
|
||||
|
||||
// NewWXFileMgr 新建文件管理器
|
||||
func NewWXFileMgr() *WXFileMgr {
|
||||
// 先创建文件夹
|
||||
os.Mkdir(baseDIR, os.ModePerm)
|
||||
return &WXFileMgr{
|
||||
fileInfoChan: make(chan *FileInfo, 10000),
|
||||
currentDirName: "",
|
||||
endChan: make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// Start 开启
|
||||
func (wxfg *WXFileMgr) Start() {
|
||||
// go wxfg.doDeal()
|
||||
}
|
||||
|
||||
// Stop 关闭
|
||||
func (wxfg *WXFileMgr) Stop() {
|
||||
// wxfg.endChan <- true
|
||||
}
|
||||
|
||||
// AddGroupQrcodeData 添加群二维码
|
||||
func (wxfg *WXFileMgr) AddGroupQrcodeData(fileData []byte, fileName string) {
|
||||
// newFileInfo := &FileInfo{}
|
||||
// newFileInfo.FileData = fileData
|
||||
// newFileInfo.FileName = fileName
|
||||
// wxfg.fileInfoChan <- newFileInfo
|
||||
}
|
||||
|
||||
func (wxfg *WXFileMgr) makeSureDir() {
|
||||
// if wxfg.currentDirName == time.Now().Format("2006-01-02") {
|
||||
// return
|
||||
// }
|
||||
|
||||
// wxfg.currentDirName = time.Now().Format("2006-01-02")
|
||||
// subDirPath := baseDIR + "/" + wxfg.currentDirName
|
||||
// os.Mkdir(subDirPath, os.ModePerm)
|
||||
}
|
||||
|
||||
func (wxfg *WXFileMgr) doDeal() {
|
||||
// for {
|
||||
// select {
|
||||
// case fileInfo := <-wxfg.fileInfoChan:
|
||||
// wxfg.writeToFile(fileInfo)
|
||||
// case <-wxfg.endChan:
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// writeToFile 写入文件
|
||||
func (wxfg *WXFileMgr) writeToFile(fileInfo *FileInfo) {
|
||||
// // 确保目录存在
|
||||
// wxfg.makeSureDir()
|
||||
// tmpFilePath := baseDIR + "/" + wxfg.currentDirName + "/" + fileInfo.FileName
|
||||
// // 如果文件存在
|
||||
// _, err := os.Lstat(tmpFilePath)
|
||||
// if err == nil {
|
||||
// return
|
||||
// }
|
||||
// baseutils.WriteToFile(fileInfo.FileData, tmpFilePath)
|
||||
}
|
||||
34
srv/wxrouter/wxaddcontactlabel.go
Normal file
34
srv/wxrouter/wxaddcontactlabel.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXAddContactLabelRouter 心跳包响应路由
|
||||
type WXAddContactLabelRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXAddContactLabelRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentReqInvoker := currentWXConn.GetWXReqInvoker()
|
||||
|
||||
// 解析退出登陆响应包
|
||||
var addLabelResp wechat.AddContactLabelResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &addLabelResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,应该关闭链接
|
||||
currentWXConn.Stop()
|
||||
return err
|
||||
}
|
||||
|
||||
// 跟新标签列表
|
||||
_, _ = currentReqInvoker.SendGetContactLabelListRequest(false)
|
||||
return nil
|
||||
}
|
||||
146
srv/wxrouter/wxautoauth.go
Normal file
146
srv/wxrouter/wxautoauth.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXAutoAuthRouter token登陆响应路由
|
||||
type WXAutoAuthRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (glqr *WXAutoAuthRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("(glqr *WXAutoAuthRouter) Handle(wxResp wxface.IWXResponse)")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
//currentInvoker := currentWXConn.GetWXReqInvoker()
|
||||
|
||||
// 解析 token 登陆响应
|
||||
var manualResponse wechat.ManualAuthResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &manualResponse)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
retCode := manualResponse.GetBaseResponse().GetRet()
|
||||
currentUserInfo.UpdateLastAuthTime() // 更新上次自动登录的二次登录时间
|
||||
// Mysql 提交登录日志
|
||||
db.SetLoginLog("AutoAuth", currentWXAccount, manualResponse.GetBaseResponse().GetErrMsg().GetStr(), retCode)
|
||||
|
||||
switch retCode {
|
||||
case baseinfo.MMOk: //success
|
||||
WXAutoAuthSuccess(&manualResponse, currentWXConn)
|
||||
//redis 发布消息 发布登录状态
|
||||
//db.PublishLoginState(currentWXAccount.GetUserInfo().UUID, currentWXAccount.GetLoginState())
|
||||
currentWXAccount.SetLoginState(baseinfo.MMLoginStateOnLine)
|
||||
return nil
|
||||
case baseinfo.MMErrDropped: //出现用户主动退出获取被T下线在线状态不存在需要调用Push
|
||||
// -2023 登录出现错误可重新登录
|
||||
/*if strings.Contains(manualResponse.GetBaseResponse().GetErrMsg().GetStr(), "登录出现错误") {
|
||||
currentWXConn.SendAutoAuthWaitingMinutes(5)
|
||||
return nil
|
||||
}*/
|
||||
//fmt.Println(hex.EncodeToString(currentUserInfo.AutoAuthKey))
|
||||
// 登录状态改为登录后退出
|
||||
currentWXAccount.SetLoginState(baseinfo.MMLoginStateLogout)
|
||||
// 保存登录状态到数据库
|
||||
db.UpdateLoginStatus(currentUserInfo.WxId, int32(currentWXAccount.GetLoginState()), "你已退出微信")
|
||||
// 关闭重新启动,再次发送登陆请求
|
||||
currentWXConn.Stop()
|
||||
//redis 发布消息 发布登录状态
|
||||
//db.PublishLoginState(currentWXAccount.GetUserInfo().UUID, currentWXAccount.GetLoginState())
|
||||
return errors.New("WXAutoAuthRouter retCode = - 2023,err: " + manualResponse.GetBaseResponse().GetErrMsg().GetStr())
|
||||
case -100:
|
||||
// 关闭重新启动,再次发送登陆请求
|
||||
currentWXConn.Stop()
|
||||
// 登录状态改为未登录
|
||||
currentWXAccount.SetLoginState(baseinfo.MMLoginStateNoLogin)
|
||||
errMsg := manualResponse.GetBaseResponse().GetErrMsg().GetStr()
|
||||
// 保存登录状态到数据库
|
||||
db.UpdateLoginStatus(currentUserInfo.GetUserName(), int32(currentUserInfo.GetLoginState()), errMsg)
|
||||
//redis 发布消息 发布登录状态
|
||||
//db.PublishLoginState(currentWXAccount.GetUserInfo().UUID, currentWXAccount.GetLoginState())
|
||||
return errors.New("WXAutoAuthRouter retCode = - 100,err: " + manualResponse.GetBaseResponse().GetErrMsg().GetStr())
|
||||
case -6:
|
||||
// 登录状态改为未登录
|
||||
currentWXAccount.SetLoginState(baseinfo.MMLoginStateNoLogin)
|
||||
// 关闭重新启动,再次发送登陆请求
|
||||
currentWXConn.Stop()
|
||||
// 保存登录状态到数据库
|
||||
errMsg := manualResponse.GetBaseResponse().GetErrMsg().GetStr()
|
||||
db.UpdateLoginStatus(currentUserInfo.WxId, int32(currentUserInfo.GetLoginState()), errMsg)
|
||||
//redis 发布消息 发布登录状态
|
||||
//db.PublishLoginState(currentWXAccount.GetUserInfo().UUID, currentWXAccount.GetLoginState())
|
||||
return errors.New("WXAutoAuthRouter err: " + errMsg)
|
||||
default:
|
||||
currentWXAccount.SetLoginState(baseinfo.MMLoginStateNoLogin)
|
||||
// 关闭重新启动,再次发送登陆请求
|
||||
currentWXConn.Stop()
|
||||
// 保存登录状态到数据库
|
||||
errMsg := manualResponse.GetBaseResponse().GetErrMsg().GetStr()
|
||||
db.UpdateLoginStatus(currentUserInfo.WxId, int32(currentUserInfo.GetLoginState()), errMsg)
|
||||
//redis 发布消息 发布登录状态
|
||||
//db.PublishLoginState(currentWXAccount.GetUserInfo().UUID, currentWXAccount.GetLoginState())
|
||||
return errors.New("WXAutoAuthRouter err: " + errMsg)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func WXAutoAuthSuccess(manualResponse *wechat.ManualAuthResponse, connect wxface.IWXConnect) {
|
||||
account := connect.GetWXAccount()
|
||||
userInfo := account.GetUserInfo()
|
||||
reqInvoker := connect.GetWXReqInvoker()
|
||||
// 获取aesKey
|
||||
userInfo.ConsultSessionKey(manualResponse.AuthParam.EcdhKey.Key.GetBuffer(), manualResponse.AuthParam.SessionKey.Key)
|
||||
// SetAutoKey
|
||||
userInfo.SetAutoKey(manualResponse.AuthParam.AutoAuthKey.Buffer)
|
||||
// SetNetworkSect
|
||||
userInfo.SetNetworkSect(manualResponse.DnsInfo)
|
||||
|
||||
// 登录成功可与服务器重新建立长链接
|
||||
isConnected := connect.IsConnected()
|
||||
if !isConnected {
|
||||
connect.Start()
|
||||
}
|
||||
|
||||
// 是否需要初始化cdn信息
|
||||
if userInfo.CheckCdn() {
|
||||
// 获取CDNDns信息
|
||||
_ = reqInvoker.SendGetCDNDnsRequest()
|
||||
}
|
||||
// 获取账号的wxProfile
|
||||
_ = reqInvoker.SendGetProfileRequest()
|
||||
// 登录状态改为在线
|
||||
account.SetLoginState(baseinfo.MMLoginStateOnLine)
|
||||
// 发送心跳
|
||||
GetHeartBeatTime := connect.GetHeartBeatTime()
|
||||
nowTime := time.Now().Unix()
|
||||
HeartBeatWaiting := 175
|
||||
if GetHeartBeatTime == 0 {
|
||||
HeartBeatWaiting = 1
|
||||
} else if nowTime-GetHeartBeatTime >= 60 {
|
||||
HeartBeatWaiting = 1
|
||||
} else {
|
||||
HeartBeatWaiting = 175 - int(nowTime-GetHeartBeatTime)
|
||||
}
|
||||
connect.SendHeartBeatWaitingSeconds(uint32(HeartBeatWaiting))
|
||||
// 等待发送二次登录30分钟
|
||||
connect.SendAutoAuthWaitingMinutes(60)
|
||||
|
||||
// 保存UserInfo
|
||||
db.UpdateUserInfo(userInfo)
|
||||
// 更新状态到数据库
|
||||
db.UpdateLoginStatus(userInfo.GetUserName(), int32(account.GetLoginState()), "登录成功!")
|
||||
}
|
||||
97
srv/wxrouter/wxbatchgetcontactbrief.go
Normal file
97
srv/wxrouter/wxbatchgetcontactbrief.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXBatchGetContactBriefInfoReqRouter 批量获取联系人信息
|
||||
type WXBatchGetContactBriefInfoReqRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (wxbgcbirr *WXBatchGetContactBriefInfoReqRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentWXCache := currentWXConn.GetWXCache()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentReqInvoker := currentWXConn.GetWXReqInvoker()
|
||||
uuid := currentWXAccount.GetUserInfo().UUID
|
||||
// 解析批量获取联系人信息响应包
|
||||
var briefInfoResp wechat.BatchGetContactBriefInfoResp
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &briefInfoResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
// fmt.Println("批量获取联系人信息响应包:")
|
||||
|
||||
tmpContactList := briefInfoResp.GetContactList()
|
||||
tmpCount := len(tmpContactList)
|
||||
for index := 0; index < tmpCount; index++ {
|
||||
tmpContactBriefInfo := tmpContactList[index]
|
||||
userName := tmpContactBriefInfo.GetUsername()
|
||||
tmpModContact := tmpContactBriefInfo.GetContact()
|
||||
nickName := tmpModContact.GetNickName().GetStr()
|
||||
// 公众号
|
||||
hasExternalInfo := false
|
||||
if len(tmpModContact.GetCustomizedInfo().GetExternalInfo()) > 0 {
|
||||
hasExternalInfo = true
|
||||
}
|
||||
if strings.HasPrefix(userName, "gh_") || hasExternalInfo {
|
||||
if len(nickName) <= 0 {
|
||||
continue
|
||||
}
|
||||
// currentWXAccount.AddWXGhContact(tmpModContact)
|
||||
continue
|
||||
}
|
||||
|
||||
// 群
|
||||
if strings.HasSuffix(userName, "@chatroom") {
|
||||
// currentWXAccount.AddWXGroup(tmpModContact)
|
||||
db.SaveOrUpdateContact(tmpModContact, uuid)
|
||||
continue
|
||||
}
|
||||
|
||||
// 好友
|
||||
// currentWXAccount.AddWXFriendContact(tmpModContact)
|
||||
if !isSystemWXID(userName) {
|
||||
db.SaveOrUpdateContact(tmpModContact, uuid)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取剩余20个微信ID列表
|
||||
nextWxidList := currentWXCache.GetNextInitContactWxidList(20)
|
||||
if len(nextWxidList) > 0 {
|
||||
currentReqInvoker.SendBatchGetContactBriefInfoReq(nextWxidList)
|
||||
} else {
|
||||
// 初始化完成
|
||||
db.UpdateInitContactStatus(uuid, 1)
|
||||
// if !currentWXCache.IsInitContactFinished() {
|
||||
// currentWXCache.SetInitContactFinished(true)
|
||||
// }
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isSystemWXID(userName string) bool {
|
||||
if userName == "qqmail" ||
|
||||
userName == "qmessage" ||
|
||||
userName == "mphelper" ||
|
||||
userName == "filehelper" ||
|
||||
userName == "weixin" ||
|
||||
userName == "floatbottle" ||
|
||||
userName == "fmessage" ||
|
||||
userName == "medianote" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
69
srv/wxrouter/wxbatchgetfavitem.go
Normal file
69
srv/wxrouter/wxbatchgetfavitem.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/db"
|
||||
|
||||
"github.com/lunny/log"
|
||||
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXBatchGetFavItemRouter 获取单条收藏详情响应路由
|
||||
type WXBatchGetFavItemRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXBatchGetFavItemRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentTaskMgr := currentWXConn.GetWXTaskMgr()
|
||||
taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
|
||||
currentSnsTransTask := taskMgr.GetSnsTransTask()
|
||||
|
||||
// 解析 获取单条收藏响应包
|
||||
var batchGetFavItemResp wechat.BatchGetFavItemResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &batchGetFavItemResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
// 解析单条收藏响应详情
|
||||
count := batchGetFavItemResp.GetCount()
|
||||
objectList := batchGetFavItemResp.GetObjectList()
|
||||
for index := uint32(0); index < count; index++ {
|
||||
tmpFavObject := objectList[index]
|
||||
// 反序列化
|
||||
objStr := tmpFavObject.GetObject()
|
||||
if len(objStr) <= 0 {
|
||||
continue
|
||||
}
|
||||
favItem := &baseinfo.FavItem{}
|
||||
err := xml.Unmarshal([]byte(objStr), favItem)
|
||||
if err != nil {
|
||||
log.Error("xml 解析error!")
|
||||
continue
|
||||
}
|
||||
if tmpFavObject == nil {
|
||||
continue
|
||||
}
|
||||
// 自动转发
|
||||
favItem.FavItemID = tmpFavObject.GetFavId()
|
||||
currentSnsTransTask.AddFavItem(favItem)
|
||||
//收藏发送mq
|
||||
if favItem != nil {
|
||||
log.Info("----收藏id=", favItem.FavItemID)
|
||||
go db.PublishFavItem(currentWXAccount, favItem)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
156
srv/wxrouter/wxcheckqrcode.go
Normal file
156
srv/wxrouter/wxcheckqrcode.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// WXCheckQrcodeRouter 检测二维码状态响应路由
|
||||
type WXCheckQrcodeRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (cqr *WXCheckQrcodeRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXCheckQrcodeRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentAccount := currentWXConn.GetWXAccount()
|
||||
currentInvoker := currentWXConn.GetWXReqInvoker()
|
||||
currentCache := currentWXConn.GetWXCache()
|
||||
currentUserInfo := currentAccount.GetUserInfo()
|
||||
|
||||
// 解析检测二维码响应
|
||||
var checkResp wechat.CheckLoginQRCodeResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &checkResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
currentWXConn.Stop()
|
||||
return err
|
||||
}
|
||||
|
||||
// 解密出现问题,说明协议出现了问题
|
||||
qrcodeInfo := currentCache.GetQrcodeInfo()
|
||||
retBytes, err := baseutils.AesDecryptByteKey(checkResp.LoginQrcodeNotifyPkg.NotifyData.Buffer, qrcodeInfo.QrCodeKey)
|
||||
|
||||
if err != nil {
|
||||
// 请求出问题了,应该关闭链接
|
||||
currentWXConn.Stop()
|
||||
return err
|
||||
}
|
||||
|
||||
lgQrNotify := &wechat.LoginQRCodeNotify{}
|
||||
err = proto.Unmarshal(retBytes, lgQrNotify)
|
||||
if err != nil {
|
||||
// 请求出问题了,应该关闭链接
|
||||
currentWXConn.Stop()
|
||||
return err
|
||||
}
|
||||
|
||||
errMsg := ""
|
||||
if lgQrNotify.GetState() == 2 {
|
||||
// 每秒查一次数据库太频繁了,这里改为仅在扫码成功后查一次
|
||||
bind, _ := db.IsLicenseBind(currentUserInfo.UUID)
|
||||
if bind != nil && len(lgQrNotify.GetWxid()) > 0 && lgQrNotify.GetWxid() != bind.WxId {
|
||||
errMsg = "该授权码(KEY)已绑定其他微信号, 请换一个KEY"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 添加扫码状态缓存
|
||||
db.AddCheckStatusCache(currentUserInfo.UUID, &baseinfo.CheckLoginQrCodeResult{
|
||||
LoginQRCodeNotify: lgQrNotify,
|
||||
Msg: errMsg,
|
||||
})
|
||||
|
||||
if len(errMsg) != 0 {
|
||||
// 当前 License 已绑定其他微信号, 需要更换 License
|
||||
currentWXConn.Stop()
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
str := byteArrayToString(retBytes)
|
||||
ticketValue := extractTicketValue(str)
|
||||
|
||||
if ticketValue != "" {
|
||||
// 赋值ticketValue
|
||||
currentUserInfo.Ticket = ticketValue
|
||||
currentUserInfo.LoginDataInfo.Ticket = ticketValue
|
||||
db.AddCheckStatusCache(currentUserInfo.UUID, &baseinfo.CheckLoginQrCodeResult{
|
||||
LoginQRCodeNotify: lgQrNotify,
|
||||
Msg: "请提交验证码后登录",
|
||||
Ret: int32(0),
|
||||
})
|
||||
}
|
||||
|
||||
if lgQrNotify.GetState() == 2 {
|
||||
// 扫码成功发送登录包
|
||||
err := currentInvoker.SendManualAuthRequest(lgQrNotify.GetWxnewpass(), lgQrNotify.GetWxid())
|
||||
if err != nil {
|
||||
// 在停止连接前,确保扫码状态被正确持久化保存
|
||||
db.AddCheckStatusCache(currentUserInfo.UUID, &baseinfo.CheckLoginQrCodeResult{
|
||||
LoginQRCodeNotify: lgQrNotify,
|
||||
Msg: "登录包发送失败:" + err.Error(),
|
||||
Ret: int32(300),
|
||||
})
|
||||
// 确保状态被保存后再停止连接
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
currentWXConn.Stop()
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
// 3 秒后发送指令
|
||||
time.Sleep(3 * time.Second)
|
||||
currentCache.SetScanFinish(true)
|
||||
|
||||
// 扫码完成后再次更新状态缓存,确保登录成功的状态被持久化
|
||||
db.AddCheckStatusCache(currentUserInfo.UUID, &baseinfo.CheckLoginQrCodeResult{
|
||||
LoginQRCodeNotify: lgQrNotify,
|
||||
Msg: "登录成功",
|
||||
Ret: int32(0),
|
||||
})
|
||||
}()
|
||||
} else if lgQrNotify.GetState() == 4 {
|
||||
// 在停止连接前,确保状态被正确保存
|
||||
db.AddCheckStatusCache(currentUserInfo.UUID, &baseinfo.CheckLoginQrCodeResult{
|
||||
LoginQRCodeNotify: lgQrNotify,
|
||||
Msg: "二维码失效",
|
||||
Ret: int32(301),
|
||||
})
|
||||
// 确保状态被保存后再停止连接
|
||||
time.Sleep(time.Millisecond * 200)
|
||||
currentWXConn.Stop()
|
||||
return errors.New("WXCheckQrcodeRouter err: 二维码失效")
|
||||
} else {
|
||||
currentUserInfo.HeadURL = lgQrNotify.GetHeadImgUrl()
|
||||
err := currentWXConn.GetWXReqInvoker().SendCheckLoginQrcodeRequest(qrcodeInfo.QrCodeUUID, qrcodeInfo.QrCodeKey)
|
||||
if err != nil {
|
||||
currentWXConn.Stop()
|
||||
return err
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func byteArrayToString(data []byte) string {
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func extractTicketValue(str string) string {
|
||||
index := strings.Index(str, "ticket=")
|
||||
if index == -1 {
|
||||
return ""
|
||||
}
|
||||
return str[index+len("ticket="):]
|
||||
}
|
||||
92
srv/wxrouter/wxfavsync.go
Normal file
92
srv/wxrouter/wxfavsync.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// WXFavSyncRouter 同步收藏响应路由
|
||||
type WXFavSyncRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXFavSyncRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentReqInvoker := currentWXConn.GetWXReqInvoker()
|
||||
currentWXCache := currentWXConn.GetWXCache()
|
||||
currentTaskMgr := currentWXConn.GetWXTaskMgr()
|
||||
// currentSyncMgr := currentWXConn.GetWXSyncMgr()
|
||||
taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
|
||||
currentSnsTransTask := taskMgr.GetSnsTransTask()
|
||||
|
||||
// 解析同步收藏响应包
|
||||
var favSyncResp wechat.FavSyncResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &favSyncResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 保存同步key下次使用
|
||||
// 解析同步收藏列表
|
||||
cmdList := favSyncResp.GetCmdList()
|
||||
tmpCount := cmdList.GetCount()
|
||||
tmpKeyBuf := favSyncResp.KeyBuf.GetBuffer()
|
||||
if len(tmpKeyBuf) <= 0 {
|
||||
currentReqInvoker.SendGetFavInfoRequest()
|
||||
return nil
|
||||
}
|
||||
|
||||
currentUserInfo.FavSyncKey = tmpKeyBuf
|
||||
|
||||
if tmpCount < 1024 {
|
||||
if !currentWXCache.IsInitFavSyncFinished() {
|
||||
// 同步完成
|
||||
currentWXCache.SetInitFavSyncFinished(true)
|
||||
}
|
||||
}
|
||||
currentReqInvoker.SendGetFavInfoRequest()
|
||||
// 如果还没开启转发收藏
|
||||
if !currentSnsTransTask.IsAutoRelay() {
|
||||
return nil
|
||||
}
|
||||
|
||||
itemList := cmdList.GetItemList()
|
||||
// 获取收藏缓存
|
||||
favInfoCache := currentWXCache.GetFavInfoCache()
|
||||
for index := uint32(0); index < tmpCount; index++ {
|
||||
tmpItem := itemList[index]
|
||||
// 判断是否是新增的收藏
|
||||
tmpCmdID := tmpItem.GetCmdId()
|
||||
if tmpCmdID != baseinfo.MMFavSyncCmdAddItem {
|
||||
return nil
|
||||
}
|
||||
// 处理新增的收藏
|
||||
addItem := &wechat.AddFavItem{}
|
||||
err := proto.Unmarshal(tmpItem.GetCmdBuf().GetData(), addItem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 判断是否重复
|
||||
if favInfoCache.LastFavID() == addItem.GetFavId() && favInfoCache.LastFavUpdateTime() == addItem.GetUpdateTime() {
|
||||
continue
|
||||
}
|
||||
favInfoCache.SetLastFavID(addItem.GetFavId())
|
||||
favInfoCache.SetLastFavUpdateTime(addItem.GetUpdateTime())
|
||||
// 获取收藏详情
|
||||
return currentReqInvoker.SendBatchGetFavItemRequest(favInfoCache.LastFavID())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
39
srv/wxrouter/wxgetcdndns.go
Normal file
39
srv/wxrouter/wxgetcdndns.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXGetCDNDnsRouter 获取CDN dns信息
|
||||
type WXGetCDNDnsRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXGetCDNDnsRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXGetCDNDnsRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
// 解析获取CdnDns信息响应包
|
||||
var getCdnDNSResp wechat.GetCDNDnsResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &getCdnDNSResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 跟新DNS信息
|
||||
currentUserInfo.APPDnsInfo = getCdnDNSResp.GetAppDnsInfo()
|
||||
currentUserInfo.FAKEDnsInfo = getCdnDNSResp.GetFakeDnsInfo()
|
||||
currentUserInfo.SNSDnsInfo = getCdnDNSResp.GetSnsDnsInfo()
|
||||
currentUserInfo.DNSInfo = getCdnDNSResp.GetDnsInfo()
|
||||
return nil
|
||||
}
|
||||
65
srv/wxrouter/wxgetcontactlabellist.go
Normal file
65
srv/wxrouter/wxgetcontactlabellist.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/defines"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXGetContactLabelListRouter 获取联系人标签路由
|
||||
type WXGetContactLabelListRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXGetContactLabelListRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentReqInvoker := currentWXConn.GetWXReqInvoker()
|
||||
|
||||
// 解析退出登陆响应包
|
||||
var getContableListResp wechat.GetContactLabelListResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &getContableListResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,应该关闭链接
|
||||
currentWXConn.Stop()
|
||||
return err
|
||||
}
|
||||
|
||||
// 先判断是否有 收藏转发屏蔽,同步转发屏蔽
|
||||
hasFavLabel := false
|
||||
hasSyncLabel := false
|
||||
labelCount := getContableListResp.GetLabelCount()
|
||||
labelPairList := getContableListResp.GetLabelPairList()
|
||||
// 跟新标签列表
|
||||
currentWXAccount.SetLabelPairList(labelPairList)
|
||||
// 判断是否有收藏转发屏蔽组、同步转发屏蔽,如果没有就添加
|
||||
for index := uint32(0); index < labelCount; index++ {
|
||||
tmpLabelPair := labelPairList[index]
|
||||
if tmpLabelPair.GetLabelName() == defines.MFavTransShieldLabelName {
|
||||
hasFavLabel = true
|
||||
continue
|
||||
}
|
||||
|
||||
if tmpLabelPair.GetLabelName() == defines.MSyncTransShieldLabelName {
|
||||
hasSyncLabel = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 创建 屏蔽组
|
||||
newLabelNameList := []string{}
|
||||
if !hasFavLabel {
|
||||
newLabelNameList = append(newLabelNameList, defines.MFavTransShieldLabelName)
|
||||
}
|
||||
if !hasSyncLabel {
|
||||
newLabelNameList = append(newLabelNameList, defines.MSyncTransShieldLabelName)
|
||||
}
|
||||
if len(newLabelNameList) > 0 {
|
||||
currentReqInvoker.SendAddContactLabelRequest(newLabelNameList, false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
42
srv/wxrouter/wxgetfavinfo.go
Normal file
42
srv/wxrouter/wxgetfavinfo.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXGetFavInfoRouter 心跳包响应路由
|
||||
type WXGetFavInfoRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXGetFavInfoRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXGetFavInfoRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentWXCache := currentWXConn.GetWXCache()
|
||||
currentSyncMgr := currentWXConn.GetWXSyncMgr()
|
||||
|
||||
// 解析退出登陆响应包
|
||||
var logoutResp wechat.GetFavInfoResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &logoutResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果没有初始化完成,则继续初始化
|
||||
if !currentWXCache.IsInitFavSyncFinished() {
|
||||
currentSyncMgr.SendFavSyncRequest()
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
42
srv/wxrouter/wxgetprofile.go
Normal file
42
srv/wxrouter/wxgetprofile.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXGetProfileRouter 获取帐号信息路由
|
||||
type WXGetProfileRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXGetProfileRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXGetProfileRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
// 解析账号Profile响应
|
||||
userProfileResp := new(wechat.GetProfileResponse)
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), userProfileResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 设置昵称和头像
|
||||
currentUserInfo.NickName = userProfileResp.GetUserInfo().GetNickName().GetStr()
|
||||
currentUserInfo.HeadURL = userProfileResp.GetUserInfoExt().GetSmallHeadImgUrl()
|
||||
// 设置UserProfile信息
|
||||
currentWXAccount.SetUserProfile(userProfileResp)
|
||||
// 更新用户信息
|
||||
db.UpdateUserInfoByPhone(userProfileResp.GetUserInfo())
|
||||
return nil
|
||||
}
|
||||
51
srv/wxrouter/wxgetqrcoded.go
Normal file
51
srv/wxrouter/wxgetqrcoded.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXGetQrcodeRouter 获取个人/群二维码响应
|
||||
type WXGetQrcodeRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXGetQrcodeRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXGetQrcodeRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
// 解析获取二维码响应包
|
||||
var getQrcodeResp wechat.GetQRCodeResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &getQrcodeResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果获取失败
|
||||
if getQrcodeResp.GetBaseResponse().GetRet() != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断是否是群聊
|
||||
tmpUserName := string(wxResp.GetPackHeader().ReqData)
|
||||
if !strings.HasSuffix(tmpUserName, "@chatroom") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 保存群二维码
|
||||
retList := strings.Split(tmpUserName, "@")
|
||||
qrcodeFileName := retList[0] + ".png"
|
||||
currentWXConn.AddGroupQrcodeData(getQrcodeResp.Qrcode.GetBuffer(), qrcodeFileName)
|
||||
return nil
|
||||
}
|
||||
45
srv/wxrouter/wxheartbeat.go
Normal file
45
srv/wxrouter/wxheartbeat.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
|
||||
"github.com/lunny/log"
|
||||
)
|
||||
|
||||
// WXHeartBeatRouter 心跳包响应路由
|
||||
type WXHeartBeatRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXHeartBeatRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXHeartBeatRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
// 解析心跳包响应
|
||||
var hearBeatResp wechat.HeartBeatResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &hearBeatResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
if hearBeatResp.GetBaseResponse().GetRet() == 0 {
|
||||
log.Printf("[%s],[%s] HeartBeatSuccess \n", currentUserInfo.GetUserName(), currentUserInfo.NickName)
|
||||
currentWXConn.StopShortReader()
|
||||
// 获取当前时间 秒
|
||||
nowTime := time.Now().Unix()
|
||||
currentWXConn.SetHeartBeatTime(nowTime)
|
||||
}
|
||||
//fmt.Println("心跳--->", hearBeatResp.GetBaseResponse().GetRet())
|
||||
// 等待 NextTime后再次发送心跳包
|
||||
currentWXConn.SendHeartBeatWaitingSeconds(hearBeatResp.GetNextTime())
|
||||
return nil
|
||||
}
|
||||
49
srv/wxrouter/wxinitcontact.go
Normal file
49
srv/wxrouter/wxinitcontact.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXInitContactRouter 初始化联系人响应路由
|
||||
type WXInitContactRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXInitContactRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentWXCache := currentWXConn.GetWXCache()
|
||||
currentReqInvoker := currentWXConn.GetWXReqInvoker()
|
||||
|
||||
// 解析初始化通讯录响应
|
||||
var initContactResp wechat.InitContactResp
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &initContactResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 设置ContactSeq
|
||||
newContactSeq := initContactResp.GetCurrentWxcontactSeq()
|
||||
currentWXCache.SetContactSeq(newContactSeq)
|
||||
// 判断 联系人数量
|
||||
contactUserNameList := initContactResp.GetContactUsernameList()
|
||||
currentWXCache.AddInitContactWxidList(contactUserNameList)
|
||||
|
||||
if len(contactUserNameList) >= 100 {
|
||||
currentReqInvoker.SendInitContactRequest(newContactSeq)
|
||||
} else {
|
||||
// 初始化通讯录
|
||||
tmpWxidList := currentWXCache.GetNextInitContactWxidList(20)
|
||||
currentReqInvoker.SendBatchGetContactBriefInfoReq(tmpWxidList)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
39
srv/wxrouter/wxlogout.go
Normal file
39
srv/wxrouter/wxlogout.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXLogoutRouter 心跳包响应路由
|
||||
type WXLogoutRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXLogoutRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXLogoutRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
// 解析退出登陆响应包
|
||||
var logoutResp wechat.LogOutResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &logoutResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
currentUserInfo.SetLoginState(baseinfo.MMLoginQrcodeStateNone)
|
||||
db.UpdateLoginStatus(currentUserInfo.GetUserName(), int32(currentUserInfo.GetLoginState()), "LogOut")
|
||||
// 退出登陆成功
|
||||
currentWXConn.Stop()
|
||||
return nil
|
||||
}
|
||||
148
srv/wxrouter/wxmanualauth.go
Normal file
148
srv/wxrouter/wxmanualauth.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXManualAuthRouter 扫码登陆响应路由
|
||||
type WXManualAuthRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (glqr *WXManualAuthRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXManualAuthRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentCache := currentWXConn.GetWXCache()
|
||||
currentInvoker := currentWXConn.GetWXReqInvoker()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentPackHeader := wxResp.GetPackHeader()
|
||||
currentWXSyncMgr := currentWXConn.GetWXSyncMgr()
|
||||
//currentWXFileHelperMgr := currentWXConn.GetWXFileHelperMgr()
|
||||
|
||||
// 解析扫码登陆响应
|
||||
var manualResponse wechat.ManualAuthResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, currentPackHeader, &manualResponse)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
retCode := manualResponse.GetBaseResponse().GetRet()
|
||||
// 重定向
|
||||
switch retCode {
|
||||
case baseinfo.MMErrIdcRedirect:
|
||||
|
||||
currentUserInfo.ShortHost = manualResponse.GetDnsInfo().GetNewHostList().GetList()[1].GetSubstitute()
|
||||
currentUserInfo.LongHost = manualResponse.GetDnsInfo().GetNewHostList().GetList()[0].GetSubstitute()
|
||||
|
||||
//提交登录日志
|
||||
db.SetLoginLog("ManualAuth", currentWXAccount, fmt.Sprintf("重定向登录 ShortHost :%s,LongHost:%s", currentUserInfo.ShortHost, currentUserInfo.LongHost), retCode)
|
||||
|
||||
// 关闭重新启动,再次发送登陆请求
|
||||
currentWXConn.Stop()
|
||||
time.Sleep(2 * time.Second)
|
||||
_ = currentWXConn.Start()
|
||||
qrcodeInfo := currentCache.GetQrcodeInfo()
|
||||
if qrcodeInfo.QrCodePassword == "" {
|
||||
return currentInvoker.SendManualAuthByDeviceIdRequest()
|
||||
} else {
|
||||
return currentInvoker.SendManualAuthRequest(qrcodeInfo.QrCodePassword, qrcodeInfo.QrCodeWxId)
|
||||
}
|
||||
case baseinfo.MMOk:
|
||||
//取基本信息
|
||||
accountInfo := manualResponse.GetAccountInfo()
|
||||
currentUserInfo.SetWxId(accountInfo.GetWxid())
|
||||
currentUserInfo.NickName = accountInfo.GetNickName()
|
||||
// 协商密钥
|
||||
currentUserInfo.ConsultSessionKey(manualResponse.GetAuthParam().GetEcdhKey().GetKey().GetBuffer(), manualResponse.AuthParam.SessionKey.Key)
|
||||
// AutoAuthKey
|
||||
currentUserInfo.SetAutoKey(manualResponse.AuthParam.AutoAuthKey.Buffer)
|
||||
// 随机一个字符红包AesKey
|
||||
currentUserInfo.GenHBKey()
|
||||
|
||||
// 如果数据库有存储这个微信号的信息
|
||||
if len(currentUserInfo.FavSyncKey) <= 0 {
|
||||
// 刷新收藏同步Key
|
||||
oldUserInfo := db.GetUserInfoByWXID(currentUserInfo.WxId)
|
||||
if oldUserInfo != nil {
|
||||
currentUserInfo.FavSyncKey = oldUserInfo.FavSyncKey
|
||||
}
|
||||
}
|
||||
// 开始发送心跳包
|
||||
currentWXConn.SendHeartBeatWaitingSeconds(10)
|
||||
// 设置登陆状态,发送提示
|
||||
currentWXAccount.SetLoginState(baseinfo.MMLoginStateOnLine)
|
||||
go func() {
|
||||
// 如果开了切号, 不管登录什么, 数据库里面都是iPad的设备信息
|
||||
db.UpdateLoginStatus(currentUserInfo.GetUserName(), int32(currentWXAccount.GetLoginState()), "登录成功!")
|
||||
// 获取账号的wxProfile
|
||||
currentInvoker.SendGetProfileRequest()
|
||||
// 获取联系人标签列表
|
||||
currentInvoker.SendGetContactLabelListRequest(false)
|
||||
// 获取CDNDns信息
|
||||
currentInvoker.SendGetCDNDnsRequest()
|
||||
// 开始发送二次登录包
|
||||
currentWXConn.SendAutoAuthWaitingMinutes(60)
|
||||
// 初始化通讯录
|
||||
// contactSeq := currentCache.GetContactSeq()
|
||||
// currentInvoker.SendInitContactRequest(contactSeq)
|
||||
currentCache.SetInitContactFinished(true)
|
||||
// 同步消息
|
||||
currentWXSyncMgr.SendNewSyncRequest()
|
||||
// 同步收藏
|
||||
// currentWXSyncMgr.SendFavSyncRequest()
|
||||
// 打印当前链接状态
|
||||
currentWXConn.GetWXServer().GetWXConnectMgr().ShowConnectInfo()
|
||||
//currentWXFileHelperMgr.AddNewTipMsg("上线成功!")
|
||||
//currentWXFileHelperMgr.AddNewTipMsg("系统正在初始化...")
|
||||
//redis 发布消息 发布登录状态
|
||||
//db.PublishLoginState(currentWXAccount.GetUserInfo().UUID, currentWXAccount.GetLoginState())
|
||||
//Mysql 提交登录日志
|
||||
currentUserInfo.UpdateLastLoginTime() // 更新上次手动登录时间
|
||||
// 手动登录成功: 扫码登录、62登录、16登录等等
|
||||
db.SetLoginLog("ManualAuth", currentWXAccount, "登录成功!", retCode)
|
||||
fmt.Println("currentUserInfo扫码登录响应路由", currentUserInfo.DeviceInfo)
|
||||
db.SaveUserInfo(currentUserInfo)
|
||||
/*time.Sleep(time.Second * 10)
|
||||
currentWXConn.Stop()*/
|
||||
}()
|
||||
default:
|
||||
// 登陆失败
|
||||
errMsg := manualResponse.GetBaseResponse().GetErrMsg().GetStr()
|
||||
baseutils.PrintLog(errMsg)
|
||||
|
||||
// 将登录失败的错误信息保存到状态缓存中,这样前端就能获取到验证码URL等错误信息
|
||||
db.AddCheckStatusCache(currentUserInfo.UUID, &baseinfo.CheckLoginQrCodeResult{
|
||||
LoginQRCodeNotify: nil,
|
||||
Ret: retCode,
|
||||
Msg: "登录失败:" + errMsg,
|
||||
})
|
||||
|
||||
//Mysql 提交登录日志
|
||||
//db.SetLoginLog("ManualAuth", currentWXAccount, errMsg, retCode)
|
||||
//Mysql 保存用户信息
|
||||
//db.SaveUserInfo(currentUserInfo)
|
||||
//Mysql 保存登录状态
|
||||
//db.UpdateLoginStatus(currentUserInfo.GetUserName(), retCode, errMsg)
|
||||
currentWXConn.Stop()
|
||||
|
||||
//redis 发布消息 发布登录状态
|
||||
//db.PublishLoginState(currentWXAccount.GetUserInfo().UUID, currentWXAccount.GetLoginState())
|
||||
fmt.Println("登录失败:" + errMsg)
|
||||
return errors.New("login failed:" + errMsg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
121
srv/wxrouter/wxnewinit.go
Normal file
121
srv/wxrouter/wxnewinit.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/db/table"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/lunny/log"
|
||||
)
|
||||
|
||||
// WXNewInitRouter 获取二维码响应路由
|
||||
type WXNewInitRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXNewInitRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentWXCache := currentWXConn.GetWXCache()
|
||||
// currentSyncMgr := currentWXConn.GetWXSyncMgr()
|
||||
|
||||
// 同步响应
|
||||
var initResp wechat.NewInitResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &initResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 跟新同步Key
|
||||
syncKey := initResp.GetCurrentSyncKey().GetBuffer()
|
||||
syncKeyMgr := currentUserInfo.SyncKeyMgr()
|
||||
syncKeyMgr.SetMaxKey(initResp.GetMaxSyncKey())
|
||||
syncKeyMgr.SetMaxKey(initResp.GetCurrentSyncKey())
|
||||
|
||||
//保存SyncKey
|
||||
if len(currentUserInfo.SyncKey) <= 0 || !bytes.Equal(currentUserInfo.SyncKey, syncKey) {
|
||||
currentUserInfo.SyncKey = syncKey
|
||||
db.UpdateUserInfo(currentUserInfo)
|
||||
}
|
||||
|
||||
if initResp.GetContinueFlag() <= 0 {
|
||||
if !currentWXCache.IsInitNewSyncFinished() {
|
||||
// 禁用历史消息推送,不设置初始化完成标志
|
||||
currentWXCache.SetInitNewSyncFinished(true)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有同步到数据则返回
|
||||
cmdList := initResp.GetCmdList()
|
||||
syncCount := initResp.GetCmdCount()
|
||||
//log.Info(initResp.GetContinueFlag())
|
||||
|
||||
//log.Info(initResp.GetContinueFlag(), syncCount)
|
||||
//redis 发布结构体
|
||||
messageResp := new(table.SyncMessageResponse)
|
||||
// 遍历同步的信息和群
|
||||
itemList := cmdList
|
||||
for index := uint32(0); index < syncCount; index++ {
|
||||
item := itemList[index]
|
||||
itemID := item.GetCmdId()
|
||||
// 同步到消息
|
||||
if itemID == baseinfo.CmdIDAddMsg {
|
||||
print(currentWXCache.IsInitNewSyncFinished(), 111)
|
||||
if !currentWXCache.IsInitNewSyncFinished() {
|
||||
// fmt.Println("跳过初始化历史消息 - IsInitNewSyncFinished=false")
|
||||
continue
|
||||
}
|
||||
// fmt.Println("处理初始化消息 - IsInitNewSyncFinished=true")
|
||||
|
||||
addMsg := &wechat.AddMsg{}
|
||||
err := proto.Unmarshal(item.CmdBuf.Data, addMsg)
|
||||
if err != nil {
|
||||
baseutils.PrintLog(err.Error())
|
||||
continue
|
||||
}
|
||||
go dealAddMsgRun(currentWXConn, addMsg, "init")
|
||||
}
|
||||
// 同步到联系人
|
||||
if itemID == baseinfo.CmdIDModContact {
|
||||
contact := new(wechat.ModContact)
|
||||
err := proto.Unmarshal(item.GetCmdBuf().GetData(), contact)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
log.Info("dealModContact")
|
||||
// dealModContact(currentWXConn, contact)
|
||||
}
|
||||
|
||||
// 删除联系人
|
||||
if itemID == baseinfo.CmdIDDelContact {
|
||||
delContact := &wechat.DelContact{}
|
||||
err := proto.Unmarshal(item.CmdBuf.Data, delContact)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// go dealDelContact(currentWXConn, delContact.GetUserName().GetStr())
|
||||
}
|
||||
messageResp.SetMessage(item.GetCmdBuf().GetData(), int32(itemID))
|
||||
}
|
||||
//发布同步信息消息
|
||||
_ = db.PublishSyncMsgWxMessage(currentWXAccount, *messageResp)
|
||||
|
||||
// 如果数量超过10条则继续同步
|
||||
if !currentWXCache.IsInitNewSyncFinished() {
|
||||
// currentSyncMgr.SendSyncInitRequest()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
1662
srv/wxrouter/wxnewsync.go
Normal file
1662
srv/wxrouter/wxnewsync.go
Normal file
File diff suppressed because it is too large
Load Diff
55
srv/wxrouter/wxopenhb.go
Normal file
55
srv/wxrouter/wxopenhb.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXOpenHBRouter 接收红包响应处理器
|
||||
type WXOpenHBRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXOpenHBRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXOpenHBRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentTaskMgr := currentWXConn.GetWXTaskMgr()
|
||||
taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
|
||||
currentGrapHBMgr := taskMgr.GetGrabHBTask()
|
||||
|
||||
// 红包响应
|
||||
var hongbaoResp wechat.HongBaoRes
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &hongbaoResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
defer currentGrapHBMgr.GrapNext()
|
||||
// 如果 返回错误码
|
||||
if hongbaoResp.GetErrorType() != 0 {
|
||||
baseutils.PrintLog("WXReceiveHBRouter err: " + hongbaoResp.GetErrorMsg())
|
||||
return nil
|
||||
}
|
||||
|
||||
// 解析
|
||||
retHongBaoOpenResp := &baseinfo.HongBaoOpenResp{}
|
||||
err = json.Unmarshal(hongbaoResp.GetRetText().GetBuffer(), retHongBaoOpenResp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 抢红包成功 可以增加一条记录
|
||||
return nil
|
||||
}
|
||||
48
srv/wxrouter/wxpushqrcodelogin.go
Normal file
48
srv/wxrouter/wxpushqrcodelogin.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/db"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXPushQrCodeLoginRouter 二维码二次登录
|
||||
type WXPushQrCodeLoginRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXPushQrCodeLoginRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXPushQrCodeLoginRouter Handle")
|
||||
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
// 解析获取二维码响应包
|
||||
var getQrcodeResp wechat.PushLoginURLResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &getQrcodeResp)
|
||||
if err != nil {
|
||||
currentWXConn.Stop()
|
||||
return err
|
||||
}
|
||||
|
||||
//第一次push 成功后没有点击确认 第二次push 会报 -2017 需要重新扫码登录
|
||||
if getQrcodeResp.GetBaseResponse().GetRet() == -2017 {
|
||||
// 更改登录状态为未登录状态
|
||||
currentWXAccount.SetLoginState(baseinfo.MMLoginStateNoLogin)
|
||||
// Mysql 更新状态
|
||||
db.UpdateLoginStatus(currentUserInfo.GetUserName(), int32(baseinfo.MMLoginQrcodeStateNone), "需要重新登录,pushLoginResp.RetCode -2017")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 如果获取失败
|
||||
if getQrcodeResp.GetBaseResponse().GetRet() != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
69
srv/wxrouter/wxreceivehb.go
Normal file
69
srv/wxrouter/wxreceivehb.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/clientsdk/baseutils"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXReceiveHBRouter 接收红包响应处理器
|
||||
type WXReceiveHBRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXReceiveHBRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXReceiveHBRouter Handle")
|
||||
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentTaskMgr := currentWXConn.GetWXTaskMgr()
|
||||
currentReqInvoker := currentWXConn.GetWXReqInvoker()
|
||||
taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
|
||||
currentGrabHBMgr := taskMgr.GetGrabHBTask()
|
||||
|
||||
// 心跳包响应
|
||||
var hongbaoResp wechat.HongBaoRes
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &hongbaoResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果 返回错误码
|
||||
if hongbaoResp.GetErrorType() != 0 {
|
||||
baseutils.PrintLog("WXReceiveHBRouter err: " + hongbaoResp.GetErrorMsg())
|
||||
// 抢下一个红包
|
||||
currentGrabHBMgr.GrapNext()
|
||||
return nil
|
||||
}
|
||||
|
||||
// 解析
|
||||
retHongBaoReceiveResp := &baseinfo.HongBaoReceiverResp{}
|
||||
err = json.Unmarshal(hongbaoResp.GetRetText().GetBuffer(), retHongBaoReceiveResp)
|
||||
baseutils.PrintLog("WXReceiveHBRouter retHongBaoReceiveResp: " + retHongBaoReceiveResp.TimingIdentifier)
|
||||
if err != nil {
|
||||
// 抢下一个红包
|
||||
currentGrabHBMgr.GrapNext()
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果都没问题,就打开红包
|
||||
currentHBItem := currentGrabHBMgr.GetCurrentHBItem()
|
||||
err = currentReqInvoker.SendOpenWxHBRequest(currentHBItem, retHongBaoReceiveResp.TimingIdentifier)
|
||||
if err != nil {
|
||||
// 抢下一个红包
|
||||
currentGrabHBMgr.GrapNext()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
34
srv/wxrouter/wxsnscomment.go
Normal file
34
srv/wxrouter/wxsnscomment.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXSnsCommentRouter 发送朋友圈响应路由
|
||||
type WXSnsCommentRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXSnsCommentRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXSnsCommentRouter Handle")
|
||||
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
// 解析发送朋友圈响应包
|
||||
var snsCommentResp wechat.SnsCommentResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &snsCommentResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
33
srv/wxrouter/wxsnspost.go
Normal file
33
srv/wxrouter/wxsnspost.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXSnsPostRouter 发送朋友圈响应路由
|
||||
type WXSnsPostRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXSnsPostRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
|
||||
// 解析发送朋友圈响应包
|
||||
var snsPostResp wechat.SnsPostResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &snsPostResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
57
srv/wxrouter/wxsnssync.go
Normal file
57
srv/wxrouter/wxsnssync.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/clientsdk/baseinfo"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXSnsSyncRouter 同步朋友圈
|
||||
type WXSnsSyncRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (ssr *WXSnsSyncRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXSnsSyncRouter Handle")
|
||||
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
//currentTaskMgr := currentWXConn.GetWXTaskMgr()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
//taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
|
||||
//currentSnsTransTask := taskMgr.GetSnsTransTask()
|
||||
currentReqInvoker := currentWXConn.GetWXReqInvoker()
|
||||
// 解析 同步朋友圈响应包
|
||||
var snsSyncResp wechat.SnsSyncResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &snsSyncResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果请求失败
|
||||
retCode := snsSyncResp.GetBaseResponse().GetRet()
|
||||
errMsg := snsSyncResp.GetBaseResponse().GetErrMsg().GetStr()
|
||||
if retCode != baseinfo.MMOk {
|
||||
return errors.New("WXSnsSyncRouter err:" + strconv.Itoa(int(retCode)) + " msg = " + errMsg)
|
||||
}
|
||||
|
||||
// 跟新key
|
||||
currentUserInfo.SnsSyncKey = snsSyncResp.GetKeyBuf().GetBuffer()
|
||||
// 遍历同步到的朋友圈
|
||||
tmpCmdList := snsSyncResp.GetCmdList()
|
||||
tmpCount := tmpCmdList.GetCount()
|
||||
if tmpCount > 0 {
|
||||
_, _ = currentReqInvoker.SendSnsSyncRequest(true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
67
srv/wxrouter/wxsnstimeline.go
Normal file
67
srv/wxrouter/wxsnstimeline.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
)
|
||||
|
||||
// WXSnsTimeLineRouter 心跳包响应路由
|
||||
type WXSnsTimeLineRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (oplog *WXSnsTimeLineRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
defer wxcore.TryE("WXSnsTimeLineRouter Handle")
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
currentTaskMgr := currentWXConn.GetWXTaskMgr()
|
||||
taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
|
||||
snsTask := taskMgr.GetSnsTask()
|
||||
|
||||
// 解析退出登陆响应包
|
||||
var timeLineResp wechat.SnsTimeLineResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &timeLineResp)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
currentTime := snsTask.GetCurrentCreateTime()
|
||||
tmpObjList := timeLineResp.GetObjectList()
|
||||
tmpCount := len(tmpObjList)
|
||||
// 判断是否有初始化
|
||||
if currentTime == 0 {
|
||||
snsTask.SetCurrentCreateTime(1)
|
||||
if tmpCount > 0 {
|
||||
snsTask.SetCurrentCreateTime(tmpObjList[0].GetCreateTime())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 自动添加评论
|
||||
for index := 0; index < tmpCount; index++ {
|
||||
tmpSnsObj := tmpObjList[index]
|
||||
if tmpSnsObj.GetCreateTime() <= currentTime {
|
||||
break
|
||||
}
|
||||
if snsTask.IsAutoThumbUP() {
|
||||
snsTask.AddCommentItemObj(tmpSnsObj)
|
||||
}
|
||||
if snsTask.IsAutoComment() {
|
||||
snsTask.AddCommentItemObjcomment(tmpSnsObj)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置最新的朋友圈创建时间
|
||||
if tmpCount > 0 {
|
||||
snsTask.SetCurrentCreateTime(tmpObjList[0].GetCreateTime())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
77
srv/wxrouter/wxsnsuserpage.go
Normal file
77
srv/wxrouter/wxsnsuserpage.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package wxrouter
|
||||
|
||||
import (
|
||||
"time"
|
||||
"xiawan/wx/clientsdk"
|
||||
"xiawan/wx/protobuf/wechat"
|
||||
"xiawan/wx/srv/wxcore"
|
||||
"xiawan/wx/srv/wxface"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
// WXSnsUserPageRouter 获取好友朋友圈路由
|
||||
type WXSnsUserPageRouter struct {
|
||||
wxcore.WXBaseRouter
|
||||
}
|
||||
|
||||
// Handle 处理conn业务的方法
|
||||
func (hbr *WXSnsUserPageRouter) Handle(wxResp wxface.IWXResponse) error {
|
||||
currentWXConn := wxResp.GetWXConncet()
|
||||
currentTaskMgr := currentWXConn.GetWXTaskMgr()
|
||||
currentWXAccount := currentWXConn.GetWXAccount()
|
||||
currentUserInfo := currentWXAccount.GetUserInfo()
|
||||
taskMgr, _ := currentTaskMgr.(*wxcore.WXTaskMgr)
|
||||
currentSnsTransTask := taskMgr.GetSnsTransTask()
|
||||
|
||||
// 解析 获取好友朋友圈响应
|
||||
var userPageResponse wechat.SnsUserPageResponse
|
||||
err := clientsdk.ParseResponseData(currentUserInfo, wxResp.GetPackHeader(), &userPageResponse)
|
||||
if err != nil {
|
||||
// 请求出问题了,判断是否掉线,并重连
|
||||
time.Sleep(1 * time.Second)
|
||||
go currentWXConn.CheckOnLineStatusLogin()
|
||||
return err
|
||||
}
|
||||
|
||||
// 关联
|
||||
tmpRequest := &wechat.SnsUserPageRequest{}
|
||||
proto.Unmarshal(wxResp.GetPackHeader().ReqData, tmpRequest)
|
||||
transItem := currentSnsTransTask.GetTransFriendItem(tmpRequest.GetUsername())
|
||||
if transItem == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 初始化
|
||||
if !transItem.IsInited {
|
||||
// 初始化ID
|
||||
transItem.FirstPageMd5 = userPageResponse.GetFirstPageMd5()
|
||||
objectCount := userPageResponse.GetObjectCount()
|
||||
if objectCount > 0 {
|
||||
objectList := userPageResponse.GetObjectList()
|
||||
transItem.CreateTime = objectList[0].GetCreateTime()
|
||||
}
|
||||
transItem.IsInited = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// 转发新的朋友圈
|
||||
objectCount := userPageResponse.GetObjectCount()
|
||||
objectList := userPageResponse.GetObjectList()
|
||||
for index := uint32(0); index < objectCount; index++ {
|
||||
tmpObject := objectList[index]
|
||||
if tmpObject.GetCreateTime() > transItem.CreateTime {
|
||||
// 转发
|
||||
currentSnsTransTask.AddSyncItem(tmpObject)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// 跟新设置
|
||||
if objectCount > 0 {
|
||||
transItem.FirstPageMd5 = userPageResponse.GetFirstPageMd5()
|
||||
transItem.CreateTime = objectList[0].GetCreateTime()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
21
srv/wxtask/message_wrapper.go
Normal file
21
srv/wxtask/message_wrapper.go
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
469
srv/wxtask/wxfriendtask.go
Normal file
469
srv/wxtask/wxfriendtask.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
357
srv/wxtask/wxgrabhbtask.go
Normal file
357
srv/wxtask/wxgrabhbtask.go
Normal file
@@ -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
|
||||
}
|
||||
192
srv/wxtask/wxgrouptask.go
Normal file
192
srv/wxtask/wxgrouptask.go
Normal file
@@ -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
|
||||
}
|
||||
120
srv/wxtask/wxrevoketask.go
Normal file
120
srv/wxtask/wxrevoketask.go
Normal file
@@ -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
|
||||
}
|
||||
271
srv/wxtask/wxsnstask.go
Normal file
271
srv/wxtask/wxsnstask.go
Normal file
@@ -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
|
||||
}
|
||||
696
srv/wxtask/wxsnstranstask.go
Normal file
696
srv/wxtask/wxsnstranstask.go
Normal file
@@ -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
|
||||
}
|
||||
268
srv/wxtask/wxsocketmsg.go
Normal file
268
srv/wxtask/wxsocketmsg.go
Normal file
@@ -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()
|
||||
}
|
||||
}
|
||||
68
srv/wxtask/wxverifytask.go
Normal file
68
srv/wxtask/wxverifytask.go
Normal file
@@ -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