Files
2026-02-17 13:06:23 +08:00

553 lines
19 KiB
Go

package service
import (
"encoding/hex"
"fmt"
"strconv"
"time"
"xiawan/wx/api/req"
"xiawan/wx/api/vo"
"xiawan/wx/clientsdk/baseinfo"
"xiawan/wx/clientsdk/baseutils"
"xiawan/wx/clientsdk/proxynet"
"xiawan/wx/db"
"xiawan/wx/db/table"
"xiawan/wx/protobuf/wechat"
"xiawan/wx/srv/wxcore"
"xiawan/wx/srv/wxface"
"github.com/gin-gonic/gin"
"github.com/gogo/protobuf/proto"
)
// logOutService 退出登录
func LogOutService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
// 在退出登录前,先清理WebSocket连接
currentTaskMgr := connect.GetWXTaskMgr()
if taskMgr, ok := currentTaskMgr.(*wxcore.WXTaskMgr); ok {
wsTask := taskMgr.SocketMsgTask
userUUID := wxAccount.GetUserInfo().UUID
// 清理WebSocket连接
existingConn := wsTask.GetWebSocket(userUUID)
if existingConn != nil {
fmt.Println("退出登录时清理WebSocket连接:", userUUID)
existingConn.Close()
wsTask.DeleteWebSocket(userUUID)
}
// 禁用WebSocket功能
wsTask.SetWebSocketEnabled(false)
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendLogoutRequest()
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccess(gin.H{}, "退出成功!")
})
}
// SendDelContactService 删除好友
func SendDelContactService(queryKey string, m req.DelContactModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendDelContactRequest(m.DelUserName)
if err != nil {
return vo.NewFail(err.Error())
}
return vo.NewSuccess(gin.H{}, "删除成功!")
})
}
// OnlineInfoService 获取登录设备信息
func OnlineInfoService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendOnlineInfo()
if err != nil {
return vo.NewFail(err.Error())
}
deviceInfoList := make([]gin.H, 0)
for _, deviceInfo := range resp.GetOnlineList() {
deviceInfoList = append(deviceInfoList, gin.H{
"deviceType": deviceInfo.GetDeviceType(),
"deviceId": hex.EncodeToString(deviceInfo.GetDeviceID()),
"clientKey": deviceInfo.GetClientKey(),
"onlineStatus": deviceInfo.GetOnlineStatus(),
})
}
return vo.NewSuccessObj(gin.H{
"onlineCount": resp.GetOnlineCount(),
"onlineList": deviceInfoList,
}, "")
})
}
// GetProfileService 获取个人资料详细信息
func GetProfileService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := iwxConnect.GetWXReqInvoker()
/*err := reqInvoker.SendGetProfileRequest()
if err != nil {
return vo.NewFail("获取个人资料失败")
}*/
profile, err := reqInvoker.SendGetProfileNewRequest()
if err != nil {
return vo.NewFail("获取个人资料失败")
}
return vo.NewSuccessObj(profile, "")
})
}
// SendModifyUserInfoRequest 修改资料
func SendModifyUserInfoRequestService(queryKey string, m req.ModifyUserInfo) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendModifyUserInfoRequest(m.City, m.Country, m.NickName, m.Province, m.Signature, m.Sex, m.InitFlag)
if err != nil {
return vo.NewFail("修改资料失败!")
}
return vo.NewSuccessObj(nil, "修改资料成功!")
})
}
// 修改名称
func UpdateNickNameService(queryKey string, m req.UpdateNickNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendUpdateNickNameRequest(m.Scene, m.Val)
if err != nil {
return vo.NewFail("修改名称失败!")
}
return vo.NewSuccessObj(nil, "修改成功!")
})
}
// 设置名称
func SetNickNameService(queryKey string, m req.UpdateNickNameModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SendUpdateNickNameRequest(m.Scene, m.Val)
if err != nil {
return vo.NewFail("修改失败!")
}
return vo.NewSuccessObj(nil, "修改成功!")
})
}
// 修改姓别
func SetSexService(queryKey string, m req.UpdateSexModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !connect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := connect.GetWXReqInvoker()
err := reqInvoker.SetSexService(m.Sex, m.Country, m.City, m.Province)
if err != nil {
return vo.NewFail("修改失败!")
}
return vo.NewSuccessObj(nil, "修改成功!")
})
}
func GetRedisSyncMsgService(queryKey string) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := connect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
} else if !connect.CheckOnLineStatus() {
return vo.NewFail("账号离线,自动上线失败!loginState == " + strconv.Itoa(int(wxAccount.GetLoginState())))
}
reqInvoker := connect.GetWXReqInvoker()
resp, err := reqInvoker.SendWxSyncMsg(queryKey)
// 如果没有同步到数据则返回
cmdList := resp.GetCmdList()
syncCount := cmdList.GetCount()
messageResp := new(table.SyncMessageResponse)
// 遍历同步的信息和群
itemList := cmdList.GetItemList()
for index := uint32(0); index < syncCount; index++ {
item := itemList[index]
itemID := item.GetCmdId()
// 同步到消息
if itemID == baseinfo.CmdIDAddMsg {
addMsg := &wechat.AddMsg{}
err := proto.Unmarshal(item.CmdBuf.Data, addMsg)
if err != nil {
baseutils.PrintLog(err.Error())
continue
}
}
messageResp.SetMessage(item.GetCmdBuf().GetData(), int32(itemID))
}
//发布同步信息消息
if err != nil {
return vo.NewFail(err.Error())
}
messageResp.Key = resp.KeyBuf
return vo.NewSuccessObj(*messageResp, "成功")
})
}
// SendChangePwdRequestService 更改密码
func SendChangePwdRequestService(queryKey string, m req.SendChangePwdRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.SendChangePwdRequest(m.OldPass, m.NewPass, m.OpCode)
if err != nil {
return vo.NewFail("SendChangePwdRequestService err:" + err.Error())
}
return vo.NewSuccessObj(resp, "")
})
}
// 上传头像
func UploadHeadImageService(queryKey string, m req.UploadHeadImageModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
resp, err := reqInvoker.UploadHeadImage(m.Base64)
if err != nil {
return vo.NewFail("SendChangePwdRequestService err:" + err.Error())
}
return vo.NewSuccessObj(resp, "成功")
})
}
// endModifyRemarkRequestService 修改备注
func SendModifyRemarkRequestService(queryKey string, m req.SendModifyRemarkRequestModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
err := reqInvoker.SendModifyRemarkRequest(m.UserName, m.RemarkName)
if err != nil {
return vo.NewFail("SendChangePwdRequestService err:" + err.Error())
}
return vo.NewSuccessObj(nil, "成功")
})
}
// UpdateAutoPassService 修改加好友需要验证属性
func UpdateAutoPassService(queryKey string, m req.UpdateAutopassModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
err := reqInvoker.UpdateAutopassRequest(m.SwitchType)
if err != nil {
return vo.NewFail("UpdateAutoPassService err:" + err.Error())
}
return vo.NewSuccessObj(nil, "成功")
})
}
// 设置微信号
func SetWechatService(queryKey string, m req.AlisaModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.SetWechatRequest(m.Alisa)
if err != nil {
return vo.NewFail("UpdateAutoPassService err:" + err.Error())
}
return vo.NewSuccessObj(rsp, "成功")
})
}
// 修改步数
func UpdateStepNumberService(queryKey string, m req.UpdateStepNumberModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.UpdateStepNumberRequest(m.Number)
if err != nil {
return vo.NewFail("UpdateStepNumberService err:" + err.Error())
}
return vo.NewSuccessObj(rsp, "成功")
})
}
// 获取步数
func GetUserRankLikeCountService(queryKey string, m req.UserRankLikeModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
rsp, err := reqInvoker.SendGetUserRankLikeCountRequest(m.RankId)
if err != nil {
return vo.NewFail("UpdateStepNumberService err:" + err.Error())
}
return vo.NewSuccessObj(rsp, "成功")
})
}
// 设置添加我的方式
func SetFunctionSwitchService(queryKey string, m req.WxFunctionSwitchModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
req := &wechat.FunctionSwitch{
FunctionId: proto.Uint32(m.Function),
SwitchValue: proto.Uint32(m.Value),
}
buffer, err := proto.Marshal(req)
cmdItem := baseinfo.ModifyItem{
CmdID: 0x17,
Len: uint32(len(buffer)),
Data: buffer,
}
var cmdItems []*baseinfo.ModifyItem
cmdItems = append(cmdItems, &cmdItem)
err = reqInvoker.SendOplogRequest(cmdItems)
if err != nil {
return vo.NewFail("SetFunctionSwitchService err:" + err.Error())
}
return vo.NewSuccessObj("ok", "成功")
})
}
// 设置拍一拍名称
func SetSendPatService(queryKey string, m req.SetSendPatModel) vo.DTO {
return checkExIdPerformNoCreateConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
wxAccount := iwxConnect.GetWXAccount()
loginState := wxAccount.GetLoginState()
//判断在线情况
if !iwxConnect.CheckOnLineStatus() {
return vo.NewFail("你已退出登录")
} else if loginState == baseinfo.MMLoginStateNoLogin {
return vo.NewFail("该账号需要重新登录!loginState == MMLoginStateNoLogin ")
}
reqInvoker := iwxConnect.GetWXReqInvoker()
req := &wechat.PatMod{
Value: proto.Int64(8),
Name: proto.String(m.Value),
}
buffer, err := proto.Marshal(req)
cmdItem := baseinfo.ModifyItem{
CmdID: 222,
Len: uint32(len(buffer)),
Data: buffer,
}
var cmdItems []*baseinfo.ModifyItem
cmdItems = append(cmdItems, &cmdItem)
err = reqInvoker.SendOplogRequest(cmdItems)
if err != nil {
return vo.NewFail("SetSendPatService err:" + err.Error())
}
return vo.NewSuccessObj("ok", "成功")
})
}
// SetProxyService 修改socks5代理
func SetProxyService(queryKey string, model req.GetLoginQrCodeModel) vo.DTO {
key := fmt.Sprintf("%s%s", "wechat:Proxy:", queryKey)
// 判断代理为空,清除 redis 缓存
if len(model.Proxy) == 0 {
//删除缓存
db.DelObj(key)
}
return getExistWxConnect(queryKey, func(iwxConnect wxface.IWXConnect, newIWXConnect bool) vo.DTO {
if iwxConnect == nil {
return vo.NewFail("链接不存在! 但代理缓存已重置!Proxy:【" + model.Proxy + "】")
}
wxAccount := iwxConnect.GetWXAccount()
errMsg := ""
newProxyUrl := ""
oldProxyUrl := wxAccount.GetUserInfo().GetProxyUrl()
// 断开连接后 之后重新使用新代理建立连接
iwxConnect.Stop()
// 等待 500 毫秒
time.Sleep(time.Millisecond * 500)
// 判断是否删除代理
if len(model.Proxy) == 0 {
// 删除代理
wxAccount.GetUserInfo().RemoveProxy()
newProxyUrl = ""
} else {
// 修改代理
proxyInfo := proxynet.ParseWXProxyInfo(model.Proxy)
dialer := proxyInfo.GetDialer()
if dialer != nil {
wxAccount := iwxConnect.GetWXAccount()
wxAccount.GetUserInfo().SetProxy(proxyInfo)
newProxyUrl = wxAccount.GetUserInfo().GetProxyUrl()
} else {
errMsg = "代理链接格式错误, 正确示例:socks5://username:password@ipv4:port"
}
}
if len(errMsg) > 0 {
return vo.NewFail(errMsg)
}
// 重新二次登录
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("设置代理: %v\n", r)
}
}()
// 等 500 毫秒后重新初始化
time.Sleep(time.Millisecond * 500)
InitLoginStatusService(queryKey, false, true, model)
//存redis缓存
error := db.SETObj(key, model)
if error != nil {
}
}()
return vo.NewSuccess(gin.H{
"oldProxyUrl": oldProxyUrl,
"newProxyUrl": newProxyUrl,
}, errMsg)
})
}