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)
|
||
}
|
||
}
|
||
}
|