@@ -0,0 +1,379 @@
package statcenterctl
import (
"net/http"
"strings"
"time"
"91porn-server/common"
"91porn-server/common/log"
"91porn-server/common/stderr"
"91porn-server/models/l/visitlogmod"
"91porn-server/models/v/rchgordmod"
"91porn-server/models/v/txnmod"
"91porn-server/models/v/usermod"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 数据中心同步协议(与哔哩 statcenter 第三版协议保持一致)
// statAppId 数据中心同步使用的应用ID
const statAppId int32 = 2
type StatJob string
const (
StatJobRegister StatJob = "register" // 用户注册
StatJobRecharge StatJob = "recharge" // 用户充值
StatJobVisit StatJob = "visit" // 用户访问
StatJobVip StatJob = "vip" // VIP
StatJobRechargeAll StatJob = "rechargeAll" // 充值订单
StatJobRegisterLight StatJob = "registerLight" // 注册轻量(H5注册)
)
type StatcenterSyncReq struct {
Job string ` json:"job" bson:"job" ` // 同步
UserId uint64 ` json:"userId" bson:"userId" ` // 用户(注册)
PlatformId string ` json:"platformId" bson:"platformId" ` // 原始平台Id(访问)
SuccessTime time . Time ` json:"successTime" ` // 成功时间(购买会员、提现、充值)
MaxSize int64 ` json:"maxSize" bson:"maxSize" ` // 最大条数
}
type StatcenterSyncResp struct {
Code int ` json:"code" ` // 200正常 其他异常
Msg string ` json:"msg" ` // 错误消息
Job string ` json:"job" bson:"job" ` // 类型
VisitList [ ] UserVisitMsg ` json:"visitList" ` // 日活记录
RegisterList [ ] UserRegisterMsg ` json:"registerList" ` // 注册记录
WithdrawList [ ] UserWithdrawMsg ` json:"withdrawList" ` // 提现记录
RechargeList [ ] UserRechargeMsg ` json:"rechargeList" ` // 充值记录
VipList [ ] UserBuyVIPMsg ` json:"buyVipList" ` // VIP购买记录
GameRecharge [ ] UserRechargeMsg ` json:"gameRecharge" ` // 游戏充值订单
GameWithdraw [ ] UserWithdrawMsg ` json:"gameWithdraw" ` // 游戏提现订单
}
type UserVisitMsg struct {
UserId uint64 ` json:"userId" bson:"userId" ` // 用户ID
PlatformId string ` json:"platformId" bson:"platformId" ` // 原始平台流水Id
AppId int32 ` json:"appId" bson:"appId" ` // appID
SysType string ` json:"sysType" bson:"sysType" ` // 操作系统类型 安卓 IOS
DevType string ` json:"devType,omitempty" bson:"devType" ` // 设备型号
IP string ` json:"ip,omitempty" bson:"ip" ` // IP
Version string ` json:"version,omitempty" bson:"version" ` // APP版本号
DevID string ` json:"devID,omitempty" bson:"devID" ` // 设备ID
VisitAt time . Time ` json:"visitAt,omitempty" bson:"visitAt" ` // 访问时间
}
type UserRegisterMsg struct {
UserId uint64 ` json:"userId" bson:"userId" ` // 用户ID
AppId int32 ` json:"appId" bson:"appId" ` // appID
SysType string ` json:"sysType" bson:"sysType" ` // 操作系统类型 安卓 IOS
PlatformId string ` json:"platformId" bson:"platformId" ` // 原始平台流水Id
DevType string ` json:"devType" bson:"devType" ` // 设备类型
Mobile string ` json:"mobile" bson:"mobile" ` // 手机号
IP string ` json:"ip,omitempty" bson:"ip" ` // IP
Name string ` json:"name" bson:"name" ` // 名称
IsDirect bool ` json:"isDirect" bson:"isDirect" ` // true:是直推用户
DistrictCode string ` json:"districtCode" bson:"districtCode" ` // 渠道码
PromSeqe string ` json:"promSeqe" bson:"promSeqe" ` // 全名代理
PromCode string ` json:"promCode" bson:"promCode" ` // 推广序列
RegisterTime time . Time ` json:"registerTime" bson:"registerTime" ` // 注册时间时间
}
type UserRechargeMsg struct {
UserId uint64 ` json:"userId" bson:"userId" ` // 用户ID
AppId int32 ` json:"appId" bson:"appId" ` // appID
PlatformId string ` json:"platformId" bson:"platformId" ` // 原始平台流水Id
SysType string ` json:"sysType" bson:"sysType" ` // 操作系统类型 安卓 IOS
DevType string ` json:"devType" bson:"devType" ` // 设备类型
ChannelName string ` json:"channelName" bson:"channelName" ` // 支付渠道名字
CID string ` json:"cid" bson:"cid" ` // 渠道id
Type string ` bson:"type" json:"type" ` // 充值方式
OrderId string ` json:"orderId" bson:"orderId" ` // 流水id
Money int64 ` json:"money" bson:"money" ` // 充值金额 订单金额
PayMoney int64 ` json:"payMoney" bson:"payMoney" ` // 实际到账金额 用户实际支付金额
Status int ` json:"status" bson:"status" ` // 2付款失败 3付款成功(目前只有成功才发送)
Rate string ` json:"rate" ` // 渠道费率
SuccessAt time . Time ` json:"successAt" bson:"successAt" ` // 成功时间
CreatedAt time . Time ` json:"createdAt" bson:"createdAt" ` // 创建时间
}
type UserWithdrawMsg struct {
AppId int32 ` json:"appId" bson:"appId" ` //appID
UID uint64 ` json:"uid" bson:"uid" ` //用户id
PlatformId string ` json:"platformId" bson:"platformId" ` //原始平台流水Id
Name string ` json:"name" bson:"name" ` //用户名
OID string ` json:"oid" bson:"oid" ` //第三方支付平台id
Money int64 ` json:"money" bson:"money" ` //提现金额
PayMoney int64 ` json:"payMoney" bson:"payMoney" ` //实际到账
PayType string ` json:"payType" bson:"payType" ` //提现方式,alipay, bankcard
ActName string ` json:"actName" bson:"actName" ` //交易账户持有人
Act string ` json:"act" bson:"act" ` //交易账户
DeviceType string ` json:"deviceType" bson:"deviceType" ` //设备类型
DevID string ` json:"devID" bson:"devID" ` //设备id
Status int ` json:"status" bson:"status" ` //5提现成功
SuccessAt time . Time ` json:"successAt" bson:"successAt" ` //回调成功时间
UpdatedAt time . Time ` json:"updatedAt" bson:"updatedAt" ` //刷新时间
CreatedAt time . Time ` json:"createdAt" bson:"createdAt" ` //提现申请时间
IsDirect bool ` json:"isDirect" bson:"isDirect" ` //true:是直推用户
DistrictCode string ` json:"districtCode" bson:"districtCode" ` //渠道码
PromCode string ` json:"promCode" bson:"promCode" ` //用户推广序列
}
type BuyVIPType int64
const (
BuyVIPTypeMoney BuyVIPType = 0 + iota // 访问
BuyVIPTypeGold // 金币
)
type UserBuyVIPMsg struct {
AppId int32 ` json:"appId" bson:"appId" ` //appID
UID uint64 ` json:"uid" bson:"uid" ` //用户id
PlatformId string ` json:"platformId" bson:"platformId" ` //原始平台流水Id
Name string ` json:"name" bson:"name" ` //用户名
Money int64 ` json:"money" bson:"money" ` //提现金额
Amount int64 ` json:"amount" bson:"amount" ` //金币
BuyVIPType BuyVIPType ` json:"buyVIPType" bson:"buyVIPType" ` //支付方式
OID string ` json:"oid" bson:"oid" ` //第三方支付平台id
DeviceType string ` json:"deviceType" bson:"deviceType" ` //设备类型
Status int ` json:"status" bson:"status" ` //1未审核 5提现成功
SuccessAt time . Time ` json:"successTime" ` // 成功时间(购买会员、提现、充值)
IsDirect bool ` json:"isDirect" bson:"isDirect" ` //true:是直推用户
DistrictCode string ` json:"districtCode" bson:"districtCode" ` //渠道码
PromCode string ` json:"promCode" bson:"promCode" ` //用户推广序列
}
// StatcenterSyncList doc
// @Tags 数据通过
// @Summary 拉去数据同步信息
// @Description 返回用户收益详情
// @Accept json
// @Produce json
// @Param param body StatcenterSyncReq true "参数"
// @Success 200 {object} StatcenterSyncResp "成功"
// @Success 400 {string} string "失败"
// @Router /api/web/statcenter/sync [POST]
func StatcenterSyncList ( ctx * gin . Context ) {
var request StatcenterSyncReq
if err := ctx . ShouldBind ( & request ) ; err != nil {
common . ServeJSON ( ctx , stderr . ErrParamError , err . Error ( ) )
return
}
var (
resp StatcenterSyncResp
err error
)
resp . Job = request . Job
resp . Code = 200
log . Info ( "StatcenterSyncList" , log . Any ( "job" , request . Job ) )
switch StatJob ( request . Job ) {
case StatJobVisit :
resp . VisitList , err = syncUserVisitList ( request )
case StatJobRegister :
resp . RegisterList , err = syncUserRegisterList ( request )
case StatJobRegisterLight :
resp . RegisterList , err = syncH5UserRegisterList ( request )
case StatJobRecharge :
resp . RechargeList , err = syncUserRechargeList ( request )
case StatJobRechargeAll :
resp . RechargeList , err = syncUserAllRechargeList ( request )
case StatJobVip :
resp . VipList , err = syncUserVipList ( request )
default :
resp . Code = 501
resp . Msg = "job is error"
}
if err != nil {
resp . Code = 502
resp . Msg = err . Error ( )
}
ctx . JSON ( http . StatusOK , resp )
}
// syncUserVisitList 日活数据同步
func syncUserVisitList ( request StatcenterSyncReq ) ( [ ] UserVisitMsg , error ) {
visitList , err := visitlogmod . AccessSyncById ( request . PlatformId , request . MaxSize )
if err != nil {
log . Error ( "syncUserVisitList visitlogmod.AccessSyncById" , log . Any ( "request" , request ) , log . E ( err ) )
return nil , err
}
list := make ( [ ] UserVisitMsg , 0 , len ( visitList ) )
for _ , v := range visitList {
list = append ( list , UserVisitMsg {
UserId : v . UID ,
AppId : statAppId ,
SysType : v . SysType ,
DevType : v . SysType ,
IP : v . IP ,
Version : v . Ver ,
DevID : v . DevID ,
VisitAt : v . CreatedAt ,
PlatformId : v . ID . Hex ( ) ,
} )
}
return list , nil
}
// syncUserRegisterList 注册数据同步
func syncUserRegisterList ( request StatcenterSyncReq ) ( [ ] UserRegisterMsg , error ) {
filter := bson . M {
"createdAt" : bson . M { "$gt" : request . SuccessTime } ,
"userType" : bson . M { "$in" : [ ] usermod . UserType { usermod . UserUnkown , usermod . UserLoufengAgent } } ,
}
opts := options . Find ( ) . SetLimit ( request . MaxSize ) . SetSort ( bson . D { { Key : "uid" , Value : 1 } } )
userList , _ , err := usermod . FetchList ( filter , opts )
if err != nil {
log . Error ( "syncUserRegisterList usermod.FetchList" , log . Any ( "request" , request ) , log . E ( err ) )
return nil , err
}
list := make ( [ ] UserRegisterMsg , 0 , len ( userList ) )
for _ , u := range userList {
list = append ( list , toUserRegisterMsg ( u , u . CreatedAt ) )
}
return list , nil
}
// syncH5UserRegisterList H5注册数据同步(按绑定手机时间)
func syncH5UserRegisterList ( request StatcenterSyncReq ) ( [ ] UserRegisterMsg , error ) {
userList , err := usermod . StatcenterSyncBindUserList ( request . SuccessTime , request . MaxSize )
if err != nil {
log . Error ( "syncH5UserRegisterList usermod.StatcenterSyncBindUserList" , log . Any ( "request" , request ) , log . E ( err ) )
return nil , err
}
list := make ( [ ] UserRegisterMsg , 0 , len ( userList ) )
for _ , u := range userList {
if strings . Contains ( u . DevType , "aosp:" ) {
continue
}
if ! isH5SysType ( u . SysType ) {
continue
}
var registerTime time . Time
if u . MobileBindAt != nil {
registerTime = * u . MobileBindAt
}
list = append ( list , toUserRegisterMsg ( & u , registerTime ) )
}
return list , nil
}
func toUserRegisterMsg ( u * usermod . User , registerTime time . Time ) UserRegisterMsg {
return UserRegisterMsg {
UserId : u . UID ,
AppId : statAppId ,
SysType : u . SysType ,
DevType : u . DevType ,
Mobile : u . Mobile ,
Name : u . Name ,
IP : u . RegisterIP ,
IsDirect : u . IsDirect ,
DistrictCode : u . DistrictCode ,
PromSeqe : u . PromSeqe ,
PromCode : u . PromCode ,
RegisterTime : registerTime ,
}
}
// isH5SysType 是否H5端
func isH5SysType ( sysType string ) bool {
s := strings . ToLower ( sysType )
switch s {
case "light" , "tg" , "web" :
return true
}
return strings . Contains ( s , "h5" )
}
// syncUserRechargeList 成功充值订单同步
func syncUserRechargeList ( request StatcenterSyncReq ) ( [ ] UserRechargeMsg , error ) {
orders , err := rchgordmod . StatCenterSyncRecharge ( request . SuccessTime , request . MaxSize )
if err != nil {
log . Error ( "syncUserRechargeList rchgordmod.StatCenterSyncRecharge" , log . Any ( "request" , request ) , log . E ( err ) )
return nil , err
}
list := make ( [ ] UserRechargeMsg , 0 , len ( orders ) )
for _ , o := range orders {
msg := toUserRechargeMsg ( o )
msg . SuccessAt = o . SuccessAt
list = append ( list , msg )
}
return list , nil
}
// syncUserAllRechargeList 全部充值订单同步(不含失败订单)
func syncUserAllRechargeList ( request StatcenterSyncReq ) ( [ ] UserRechargeMsg , error ) {
orders , err := rchgordmod . StatCenterSyncOrder ( request . SuccessTime , request . MaxSize )
if err != nil {
log . Error ( "syncUserAllRechargeList rchgordmod.StatCenterSyncOrder" , log . Any ( "request" , request ) , log . E ( err ) )
return nil , err
}
list := make ( [ ] UserRechargeMsg , 0 , len ( orders ) )
for _ , o := range orders {
if o . Status == rchgordmod . FAILURE {
continue
}
msg := toUserRechargeMsg ( o )
msg . CreatedAt = o . CreatedAt
list = append ( list , msg )
}
return list , nil
}
func toUserRechargeMsg ( o rchgordmod . RechargeOrder ) UserRechargeMsg {
return UserRechargeMsg {
UserId : o . UID ,
AppId : statAppId ,
SysType : o . DevType ,
DevType : o . DevType ,
PlatformId : o . ID . Hex ( ) ,
ChannelName : o . Channel ,
CID : o . OID ,
Type : o . RechargeType ,
OrderId : o . ID . Hex ( ) ,
Money : o . Money ,
PayMoney : o . PayMoney ,
Status : o . Status ,
Rate : o . Rate ,
}
}
// syncUserVipList 充值购买会员卡同步
func syncUserVipList ( request StatcenterSyncReq ) ( [ ] UserBuyVIPMsg , error ) {
endTime := time . Now ( ) . Add ( - time . Minute * 2 )
filter := bson . M {
"tranTypeInt" : int64 ( txnmod . BuyVIP ) ,
"createdAt" : bson . M { "$gt" : request . SuccessTime , "$lt" : endTime } ,
}
opts := options . Find ( ) . SetLimit ( request . MaxSize ) . SetSort ( bson . D { { Key : "createdAt" , Value : 1 } } )
_ , logs , err := txnmod . FindTransactionLogs ( filter , opts )
if err != nil {
log . Error ( "syncUserVipList txnmod.FindTransactionLogs" , log . Any ( "request" , request ) , log . E ( err ) )
return nil , err
}
list := make ( [ ] UserBuyVIPMsg , 0 , len ( logs ) )
for _ , l := range logs {
money := l . Amount
if money < 0 {
money = - money
}
list = append ( list , UserBuyVIPMsg {
UID : l . UID ,
AppId : statAppId ,
PlatformId : l . ID . Hex ( ) ,
Money : money * 10 , // 流水金额为会员卡价格(角),转换为分
BuyVIPType : BuyVIPTypeMoney ,
OID : l . TransNo . Hex ( ) ,
DeviceType : l . SysType ,
Status : 3 ,
SuccessAt : l . CreatedAt ,
} )
}
return list , nil
}