430 lines
16 KiB
Go
430 lines
16 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"xiawan/wx/api/req"
|
|
"xiawan/wx/api/vo"
|
|
"xiawan/wx/clientsdk"
|
|
"xiawan/wx/clientsdk/baseinfo"
|
|
"xiawan/wx/clientsdk/proxynet"
|
|
"xiawan/wx/db"
|
|
"xiawan/wx/db/table"
|
|
"xiawan/wx/protobuf/wechat"
|
|
"xiawan/wx/srv"
|
|
"xiawan/wx/srv/srvconfig"
|
|
"xiawan/wx/srv/websrv"
|
|
"xiawan/wx/srv/wxcore"
|
|
"xiawan/wx/srv/wxface"
|
|
"xiawan/wx/srv/wxrouter"
|
|
|
|
"github.com/lunny/log"
|
|
)
|
|
|
|
// 基础服务功能
|
|
var WXServer wxface.IWXServer
|
|
|
|
type BusinessFunc = func(connect wxface.IWXConnect, newIWXConnect bool) vo.DTO
|
|
type USerInfoCallFunc = func(account *srv.WXAccount, invoker wxface.IWXReqInvoker, state uint32) vo.DTO
|
|
|
|
// 初始化微信响应路由
|
|
func InitWXServerRouter() {
|
|
// 开启服务器
|
|
wxServer := wxcore.NewWXServer()
|
|
// 注册微信响应路由
|
|
// wxServer.AddWXRouter(baseinfo.MMRequestTypeGetLoginQRCode, new(wxrouter.WXGetLoginQrcodeRouter)) // 获取登陆二维码响应
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeCheckLoginQRCode, new(wxrouter.WXCheckQrcodeRouter)) // 检测二维码状态请求
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypePushQrLogin, new(wxrouter.WXPushQrCodeLoginRouter)) // 唤醒登录
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeManualAuth, new(wxrouter.WXManualAuthRouter))
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeHybridManualAuth, new(wxrouter.WXManualAuthRouter)) // 登录
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeLogout, new(wxrouter.WXLogoutRouter)) // 退出登录
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeAutoAuth, new(wxrouter.WXAutoAuthRouter)) // token登陆
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeNewSync, new(wxrouter.WXNewSyncRouter)) // 同步消息,联系人
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeNewInit, new(wxrouter.WXNewInitRouter)) // 首次登录初始化
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeHeartBeat, new(wxrouter.WXHeartBeatRouter)) // 心跳包
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetProfile, new(wxrouter.WXGetProfileRouter)) // 获取帐号信息
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetCdnDNS, new(wxrouter.WXGetCDNDnsRouter)) // 获取CDNDns信息
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeInitContact, new(wxrouter.WXInitContactRouter)) // 初始化联系人
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeBatchGetContactBriefInfo, new(wxrouter.WXBatchGetContactBriefInfoReqRouter)) // 初始化联系人
|
|
// wxServer.AddWXRouter(baseinfo.MMRequestTypeGetContact, new(wxrouter.WXGetContactRouter)) // 批量获取联系人信息
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeReceiveWxHB, new(wxrouter.WXReceiveHBRouter)) // 接收红包
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeOpenWxHB, new(wxrouter.WXOpenHBRouter)) // 打开红包
|
|
// wxServer.AddWXRouter(baseinfo.MMRequestTypeOplog, new(wxrouter.WXOplogRouter)) // Oplog请求
|
|
// wxServer.AddWXRouter(baseinfo.MMRequestTypeNewSendMsg, new(wxrouter.WXNewSendMsgRouter)) // 发送文本消息
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeFavSync, new(wxrouter.WXFavSyncRouter)) // 同步收藏
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetFavInfo, new(wxrouter.WXGetFavInfoRouter)) // 获取收藏信息
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeBatchGetFavItem, new(wxrouter.WXBatchGetFavItemRouter)) // 获取单条收藏(收藏转发)
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsPost, new(wxrouter.WXSnsPostRouter)) // 发送朋友圈
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsSync, new(wxrouter.WXSnsSyncRouter)) // 同步朋友圈
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsUserPage, new(wxrouter.WXSnsUserPageRouter)) // 朋友圈同步转发
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsTimeLine, new(wxrouter.WXSnsTimeLineRouter)) // 同步朋友圈
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeMMSnsComment, new(wxrouter.WXSnsCommentRouter)) // 评论/点赞朋友圈
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetContactLabelList, new(wxrouter.WXGetContactLabelListRouter)) // 获取标签列表
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeAddContactLabel, new(wxrouter.WXAddContactLabelRouter)) // 新增标签列表
|
|
wxServer.AddWXRouter(baseinfo.MMRequestTypeGetQrCode, new(wxrouter.WXGetQrcodeRouter)) // 获取二维码
|
|
// wxServer.AddWXRouter(baseinfo.MMRequestTypeBindQueryNew, new(wxrouter.WXBindQueryNewRouter)) // 获取钱包信息
|
|
wxServer.Start()
|
|
WXServer = wxServer
|
|
}
|
|
|
|
func CreateWXConnectByQueryKey(queryKey, proxy string, wxAccount *srv.WXAccount) wxface.IWXConnect {
|
|
var proxyInfo *proxynet.WXProxyInfo
|
|
if proxy != "" {
|
|
proxyInfo = proxynet.ParseWXProxyInfo(proxy)
|
|
}
|
|
|
|
if wxAccount == nil {
|
|
wxAccount = srv.NewWXAccount(&websrv.TaskInfo{
|
|
UUID: queryKey,
|
|
}, proxyInfo, uint32(0), nil)
|
|
|
|
}
|
|
|
|
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
|
|
return wxConnect
|
|
}
|
|
|
|
// checkExIdReturn 检测实例Id并返回实例
|
|
func checkExIdReturn(queryKey string, ClientVersion uint32) wxface.IWXConnect {
|
|
// 判断 ClientVersion == 0
|
|
if !(int(ClientVersion) > 0) {
|
|
ClientVersion = baseinfo.ClientVersion
|
|
}
|
|
//获取实例管理器
|
|
connectMgr := WXServer.GetWXConnectMgr()
|
|
//查询的queryKey为空创建一个链接实例
|
|
if queryKey == "" {
|
|
return nil
|
|
}
|
|
|
|
//查询该链接是否存在
|
|
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
|
|
if iwxConnect != nil {
|
|
//执行回调方法
|
|
return iwxConnect
|
|
} else {
|
|
//如果链接管理器不存在该链接查询数据库是否存在
|
|
dbUserInfo := db.GetUSerInfoByUUID(queryKey)
|
|
//数据库存在该链接数据 重新实例化一个链接对象
|
|
if dbUserInfo != nil {
|
|
if !(int(dbUserInfo.ClientVersion) > 0) {
|
|
dbUserInfo.ClientVersion = ClientVersion
|
|
}
|
|
//创建一个用户信息
|
|
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
|
|
UUID: queryKey,
|
|
}, nil, dbUserInfo.ClientVersion, dbUserInfo)
|
|
//创建一个新链接
|
|
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
|
|
//设置用户信息
|
|
wxAccount.SetUserInfo(dbUserInfo)
|
|
return wxConnect
|
|
} else {
|
|
//创建新一个用户信息
|
|
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
|
|
UUID: queryKey,
|
|
}, nil, ClientVersion, dbUserInfo)
|
|
//创建一个新链接
|
|
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
|
|
return wxConnect
|
|
}
|
|
}
|
|
}
|
|
|
|
// 检查实例Id是否存在 不存在创建新的链接
|
|
func checkExIdPerform(queryKey string, ClientVersion uint32, businessFunc BusinessFunc) vo.DTO {
|
|
// 判断 ClientVersion == 0
|
|
if !(int(ClientVersion) > 0) {
|
|
ClientVersion = baseinfo.ClientVersion
|
|
}
|
|
//获取实例管理器
|
|
connectMgr := WXServer.GetWXConnectMgr()
|
|
//查询的queryKey为空创建一个链接实例
|
|
if queryKey == "" {
|
|
return businessFunc(nil, true)
|
|
}
|
|
//查询该链接是否存在
|
|
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
|
|
if iwxConnect != nil {
|
|
//执行回调方法
|
|
return businessFunc(iwxConnect, false)
|
|
} else {
|
|
//如果链接管理器不存在该链接查询数据库是否存在
|
|
dbUserInfo := db.GetUSerInfoByUUID(queryKey)
|
|
//数据库存在该链接数据 重新实例化一个链接对象
|
|
if dbUserInfo != nil {
|
|
if !(int(dbUserInfo.ClientVersion) > 0) {
|
|
dbUserInfo.ClientVersion = ClientVersion
|
|
}
|
|
// 设置代理信息
|
|
key := fmt.Sprintf("%s%s", "wechat:Proxy:", queryKey)
|
|
exists, _ := db.Exists(key)
|
|
newModel := &req.GetLoginQrCodeModel{
|
|
Proxy: "",
|
|
Check: false,
|
|
}
|
|
if exists {
|
|
db.GETObj(key, &newModel)
|
|
}
|
|
var proxyInfo *proxynet.WXProxyInfo
|
|
if newModel.Proxy != "" {
|
|
proxyInfo = proxynet.ParseWXProxyInfo(newModel.Proxy)
|
|
} else {
|
|
proxyInfo = nil
|
|
}
|
|
//创建一个用户信息
|
|
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
|
|
UUID: queryKey,
|
|
}, proxyInfo, dbUserInfo.ClientVersion, dbUserInfo)
|
|
//创建一个新链接
|
|
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
|
|
//设置用户信息
|
|
wxAccount.SetUserInfo(dbUserInfo)
|
|
return businessFunc(wxConnect, false)
|
|
} else {
|
|
// 设置代理信息
|
|
key := fmt.Sprintf("%s%s", "wechat:Proxy:", queryKey)
|
|
exists, _ := db.Exists(key)
|
|
newModel := &req.GetLoginQrCodeModel{
|
|
Proxy: "",
|
|
Check: false,
|
|
}
|
|
if exists {
|
|
db.GETObj(key, &newModel)
|
|
}
|
|
var proxyInfo *proxynet.WXProxyInfo
|
|
if newModel.Proxy != "" {
|
|
proxyInfo = proxynet.ParseWXProxyInfo(newModel.Proxy)
|
|
} else {
|
|
proxyInfo = nil
|
|
}
|
|
//创建新一个用户信息
|
|
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
|
|
UUID: queryKey,
|
|
}, proxyInfo, ClientVersion, dbUserInfo)
|
|
//创建一个新链接
|
|
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
|
|
return businessFunc(wxConnect, true)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 检查实例Id是否存在 链接不存在返回错误不创建新链接
|
|
func checkExIdPerformNoCreateConnect(queryKey string, businessFunc BusinessFunc) vo.DTO {
|
|
ClientVersion := baseinfo.ClientVersion
|
|
//获取实例管理器
|
|
connectMgr := WXServer.GetWXConnectMgr()
|
|
//查询的queryKey为空创建一个链接实例
|
|
if queryKey == "" {
|
|
return businessFunc(nil, true)
|
|
}
|
|
|
|
//查询该链接是否存在
|
|
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
|
|
if iwxConnect != nil {
|
|
//执行回调方法
|
|
return businessFunc(iwxConnect, false)
|
|
} else {
|
|
//如果链接管理器不存在该链接查询数据库是否存在
|
|
dbUserInfo := db.GetUSerInfoByUUID(queryKey)
|
|
//数据库存在该链接数据 重新实例化一个链接对象
|
|
if dbUserInfo != nil {
|
|
if !(int(dbUserInfo.ClientVersion) > 0) {
|
|
dbUserInfo.ClientVersion = ClientVersion
|
|
}
|
|
// 设置代理信息
|
|
key := fmt.Sprintf("%s%s", "wechat:Proxy:", dbUserInfo.UUID)
|
|
exists, _ := db.Exists(key)
|
|
newModel := &req.GetLoginQrCodeModel{
|
|
Proxy: "",
|
|
Check: false,
|
|
}
|
|
if exists {
|
|
db.GETObj(key, &newModel)
|
|
}
|
|
var proxyInfo *proxynet.WXProxyInfo
|
|
if newModel.Proxy != "" {
|
|
proxyInfo = proxynet.ParseWXProxyInfo(newModel.Proxy)
|
|
} else {
|
|
proxyInfo = nil
|
|
}
|
|
|
|
//创建一个用户信息
|
|
wxAccount := srv.NewWXAccount(&websrv.TaskInfo{
|
|
UUID: queryKey,
|
|
}, proxyInfo, dbUserInfo.ClientVersion, dbUserInfo)
|
|
|
|
//创建一个新链接
|
|
wxConnect := wxcore.NewWXConnect(WXServer, wxAccount)
|
|
|
|
//设置用户信息
|
|
wxAccount.SetUserInfo(dbUserInfo)
|
|
return businessFunc(wxConnect, false)
|
|
} else {
|
|
// 诊断逻辑:为什么查不到?
|
|
reason := "未知原因"
|
|
var uEntity table.UserInfoEntity
|
|
err := db.MysqlDB.Where("uuid = ?", queryKey).First(&uEntity).Error
|
|
if err != nil {
|
|
reason = fmt.Sprintf("数据库UserInfo表未找到该UUID记录: %v", err)
|
|
} else {
|
|
// UUID 存在,检查 TargetIp
|
|
if srvconfig.GlobalSetting.TargetIp != "" && uEntity.TargetIp != srvconfig.GlobalSetting.TargetIp {
|
|
reason = fmt.Sprintf("TargetIp不匹配(DB:%s, Config:%s)", uEntity.TargetIp, srvconfig.GlobalSetting.TargetIp)
|
|
} else {
|
|
// 检查 DeviceInfo
|
|
// 判断是62还是A16
|
|
key := fmt.Sprintf("%s%s", "wechat:a16DeviceInfo:", uEntity.WxId)
|
|
exists, _ := db.Exists(key)
|
|
if !exists {
|
|
var dEntity table.DeviceInfoEntity
|
|
if err := db.MysqlDB.Where("wxId = ?", uEntity.WxId).First(&dEntity).Error; err != nil {
|
|
reason = fmt.Sprintf("缺少设备信息(DeviceInfo表无记录且Redis无A16缓存), WxId: %s, Err: %v", uEntity.WxId, err)
|
|
} else {
|
|
reason = "UserInfo和DeviceInfo都存在,但GetUSerInfoByUUID返回nil,可能是其他数据完整性问题"
|
|
}
|
|
} else {
|
|
reason = "UserInfo存在且有A16缓存,但GetUSerInfoByUUID返回nil,可能是反序列化或其他问题"
|
|
}
|
|
}
|
|
}
|
|
|
|
return vo.DTO{
|
|
Code: vo.FAIL_UUID,
|
|
Data: nil,
|
|
Text: fmt.Sprintf("%s 该链接不存在!调试信息: %s", queryKey, reason),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取缓存中已存在的 wx 链接
|
|
func getExistWxConnect(queryKey string, businessFunc BusinessFunc) vo.DTO {
|
|
//获取实例管理器
|
|
connectMgr := WXServer.GetWXConnectMgr()
|
|
//查询的queryKey为空创建一个链接实例
|
|
if queryKey == "" {
|
|
return businessFunc(nil, true)
|
|
}
|
|
|
|
//查询该链接是否存在
|
|
iwxConnect := connectMgr.GetWXConnectByUserInfoUUID(queryKey)
|
|
if iwxConnect != nil {
|
|
//执行回调方法
|
|
userInfo := iwxConnect.GetWXAccount().GetUserInfo()
|
|
iwxConnect.GetWXAccount().SetUserInfo(userInfo)
|
|
return businessFunc(iwxConnect, false)
|
|
}
|
|
return businessFunc(nil, true)
|
|
}
|
|
|
|
func DeepFields(ifaceType reflect.Type) []reflect.StructField {
|
|
var fields []reflect.StructField
|
|
|
|
for i := 0; i < ifaceType.NumField(); i++ {
|
|
v := ifaceType.Field(i)
|
|
if v.Anonymous && v.Type.Kind() == reflect.Struct {
|
|
fields = append(fields, DeepFields(v.Type)...)
|
|
} else {
|
|
fields = append(fields, v)
|
|
}
|
|
}
|
|
|
|
return fields
|
|
}
|
|
|
|
func StructCopy(DstStructPtr interface{}, SrcStructPtr interface{}) {
|
|
srcv := reflect.ValueOf(SrcStructPtr)
|
|
dstv := reflect.ValueOf(DstStructPtr)
|
|
srct := reflect.TypeOf(SrcStructPtr)
|
|
dstt := reflect.TypeOf(DstStructPtr)
|
|
if srct.Kind() != reflect.Ptr || dstt.Kind() != reflect.Ptr ||
|
|
srct.Elem().Kind() == reflect.Ptr || dstt.Elem().Kind() == reflect.Ptr {
|
|
panic("Fatal error:type of parameters must be Ptr of value")
|
|
}
|
|
if srcv.IsNil() || dstv.IsNil() {
|
|
panic("Fatal error:value of parameters should not be nil")
|
|
}
|
|
srcV := srcv.Elem()
|
|
dstV := dstv.Elem()
|
|
srcfields := DeepFields(reflect.ValueOf(SrcStructPtr).Elem().Type())
|
|
for _, v := range srcfields {
|
|
if v.Anonymous {
|
|
continue
|
|
}
|
|
dst := dstV.FieldByName(v.Name)
|
|
src := srcV.FieldByName(v.Name)
|
|
if !dst.IsValid() {
|
|
continue
|
|
}
|
|
if src.Type() == dst.Type() && dst.CanSet() {
|
|
dst.Set(src)
|
|
continue
|
|
}
|
|
if src.Kind() == reflect.Ptr && !src.IsNil() && src.Type().Elem() == dst.Type() {
|
|
dst.Set(src.Elem())
|
|
continue
|
|
}
|
|
if dst.Kind() == reflect.Ptr && dst.Type().Elem() == src.Type() {
|
|
dst.Set(reflect.New(src.Type()))
|
|
dst.Elem().Set(src)
|
|
continue
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
/*
|
|
*
|
|
获取DeviceToken
|
|
*/
|
|
func checkDeviceToken(tmpUserInfo *baseinfo.UserInfo) {
|
|
//如果是android
|
|
if strings.HasPrefix(tmpUserInfo.LoginDataInfo.LoginData, "A") {
|
|
key := fmt.Sprintf("%s%s", "wechat:deviceTokenA16:", tmpUserInfo.LoginDataInfo.UserName)
|
|
exists, _ := db.Exists(key)
|
|
if exists {
|
|
//A16存redis
|
|
trustRes := &wechat.TrustResp{}
|
|
error := db.GETObj(key, &trustRes)
|
|
if error != nil {
|
|
log.Error("redis deviceToken is error=" + error.Error())
|
|
}
|
|
tmpUserInfo.DeviceInfoA16.DeviceToken = trustRes
|
|
} else {
|
|
tmpUserInfo.DeviceInfoA16.DeviceId = []byte(tmpUserInfo.LoginDataInfo.LoginData[:15])
|
|
tmpUserInfo.DeviceInfoA16.DeviceIdStr = tmpUserInfo.LoginDataInfo.LoginData
|
|
deviceTokenRsp, err := clientsdk.SendAndroIdDeviceTokenRequest(tmpUserInfo)
|
|
if err != nil {
|
|
log.Error("android 请求 deviceTokenRequest error!")
|
|
}
|
|
//保存5天
|
|
db.SETExpirationObj(key, &deviceTokenRsp, 60*60*24*5)
|
|
tmpUserInfo.DeviceInfoA16.DeviceToken = deviceTokenRsp
|
|
}
|
|
} else if strings.HasPrefix(tmpUserInfo.LoginDataInfo.LoginData, "62") {
|
|
key := fmt.Sprintf("%s%s", "wechat:deviceTokenIos:", tmpUserInfo.LoginDataInfo.UserName)
|
|
exists, _ := db.Exists(key)
|
|
if exists {
|
|
//ios存redis
|
|
trustRes := &wechat.TrustResp{}
|
|
error := db.GETObj(key, &trustRes)
|
|
if error != nil {
|
|
log.Error("ios redis deviceTokenIos is error=" + error.Error())
|
|
}
|
|
|
|
tmpUserInfo.DeviceInfo.DeviceToken = trustRes
|
|
} else {
|
|
deviceTokenRsp, err := clientsdk.SendIosDeviceTokenRequest(tmpUserInfo)
|
|
if err != nil {
|
|
log.Error("ios 请求 deviceTokenRequest error!")
|
|
}
|
|
//保存5天
|
|
db.SETExpirationObj(key, &deviceTokenRsp, 60*60*24*5)
|
|
tmpUserInfo.DeviceInfo.DeviceToken = deviceTokenRsp
|
|
fmt.Println(deviceTokenRsp, 333)
|
|
}
|
|
}
|
|
}
|