197 lines
5.7 KiB
Go
197 lines
5.7 KiB
Go
package botser
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"sort"
|
|
"stat/common/log"
|
|
"stat/common/utils"
|
|
"stat/models/accessmod"
|
|
"stat/models/channelmod"
|
|
"stat/models/rechargegamemod"
|
|
"stat/models/rechargemod"
|
|
"stat/models/registermod"
|
|
"stat/models/withdrawGameOrdermod"
|
|
"time"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
)
|
|
|
|
type IpCount struct {
|
|
Ip string
|
|
Count int64
|
|
}
|
|
|
|
type IpCountList []*IpCount
|
|
|
|
func (a IpCountList) Len() int { return len(a) }
|
|
func (a IpCountList) Less(i, j int) bool {
|
|
return a[i].Count > a[j].Count
|
|
}
|
|
func (a IpCountList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
|
|
type AnalyzeItem struct {
|
|
Channel string
|
|
RegisterIpMap map[string]int64
|
|
RegisterUserMap map[string]int64
|
|
RegisterCount int64 // 注册总数
|
|
RegisterIpCount int64 // 注册IP数
|
|
VisitCountMap map[string]int64 // 访问总数
|
|
ValidVisitAfterHourMap map[string]int64 // 1小时后访问总数
|
|
ValidVisitAfterDayMap map[string]int64 // 1天后访问总数
|
|
ValidVisitAfterTowDayMap map[string]int64 // 2天后访问总数
|
|
RechargeCount int64 // 充值次数
|
|
RechargeAmount int64 // 充值钱数
|
|
RechargeUsers int64 // 充值用户数
|
|
GameRecharge int64 // 游戏充值
|
|
GameWithdraw int64 // 游戏提现
|
|
}
|
|
|
|
func NewAnalyzeItem(channel string) *AnalyzeItem {
|
|
return &AnalyzeItem{
|
|
Channel: channel,
|
|
RegisterIpMap: make(map[string]int64),
|
|
RegisterUserMap: make(map[string]int64),
|
|
VisitCountMap: make(map[string]int64),
|
|
ValidVisitAfterHourMap: make(map[string]int64),
|
|
ValidVisitAfterDayMap: make(map[string]int64),
|
|
ValidVisitAfterTowDayMap: make(map[string]int64),
|
|
}
|
|
}
|
|
|
|
func (s *AnalyzeItem) AddIp(ip string) {
|
|
s.RegisterCount++
|
|
s.RegisterIpMap[ip]++
|
|
s.RegisterIpCount = int64(len(s.RegisterIpMap))
|
|
}
|
|
|
|
func (s *AnalyzeItem) IpRank(topCount int) IpCountList {
|
|
list := make(IpCountList, 0)
|
|
for ip, count := range s.RegisterIpMap {
|
|
list = append(list, &IpCount{
|
|
Ip: ip,
|
|
Count: count,
|
|
})
|
|
}
|
|
sort.Sort(list)
|
|
ret := make(IpCountList, 0)
|
|
for _, item := range list {
|
|
if len(ret) < topCount {
|
|
ret = append(ret, item)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func ChannelAnalyze(ctx context.Context, channel string, start time.Time, end time.Time) (*AnalyzeItem, error) {
|
|
ret := NewAnalyzeItem(channel)
|
|
key := func(appid int32, userid uint64) string {
|
|
return fmt.Sprintf("%d-%d", appid, userid)
|
|
}
|
|
channelDeductionRules, err := channelmod.FindManyChannelDeductionRule(ctx, bson.M{
|
|
channelmod.FN.ChannelDeductionRule.Channel: channel,
|
|
})
|
|
if err != nil {
|
|
log.Error("ChannelSettlementMethod FindManyChannelDeductionRule", log.E(err))
|
|
return nil, err
|
|
}
|
|
if len(channelDeductionRules) <= 0 {
|
|
return nil, nil
|
|
}
|
|
channelInfo, err := channelmod.FindOneChannelInfo(ctx, bson.M{
|
|
channelmod.FN.ChannelInfo.Channel: channel})
|
|
if err != nil {
|
|
log.Error("ChannelAnalyze FindOneChannelInfo", log.E(err))
|
|
return nil, err
|
|
}
|
|
if channelInfo.Channel != channel {
|
|
return nil, errors.New("channel not found")
|
|
}
|
|
registerDict := make(map[string]*registermod.RegisterMod)
|
|
for _, ruleInfo := range channelDeductionRules {
|
|
// 统计注册用户
|
|
registerList, err := registermod.RegisterChannelUsersInfoByTime(ctx, channel, ruleInfo.AppId, start, end)
|
|
if err != nil {
|
|
log.Error("NewCountMethod RegisterUsersInfoByDistrict ", log.E(err))
|
|
return nil, err
|
|
}
|
|
uids := make([]uint64, 0)
|
|
for _, register := range registerList {
|
|
ret.AddIp(register.IP)
|
|
registerDict[key(ruleInfo.AppId, register.UserId)] = register
|
|
uids = append(uids, register.UserId)
|
|
}
|
|
err1 := utils.SlicePaged(uids, 5000, func(piece []uint64) error {
|
|
vList, err2 := accessmod.FindManyVisitInfo(ctx, bson.M{
|
|
"userId": bson.M{"$in": piece},
|
|
"appId": ruleInfo.AppId,
|
|
"visitAt": bson.M{"$gte": start, "$lt": end},
|
|
})
|
|
// 访问统计
|
|
for _, visit := range vList {
|
|
skey := key(ruleInfo.AppId, visit.UserId)
|
|
regUser := registerDict[skey]
|
|
if regUser == nil {
|
|
continue
|
|
}
|
|
ret.VisitCountMap[skey]++
|
|
if visit.VisitAt.After(regUser.RegisterTime.Add(time.Hour)) {
|
|
ret.ValidVisitAfterHourMap[skey]++
|
|
}
|
|
if visit.VisitAt.After(regUser.RegisterTime.Add(24 * time.Hour)) {
|
|
ret.ValidVisitAfterDayMap[skey]++
|
|
}
|
|
if visit.VisitAt.After(regUser.RegisterTime.Add(48 * time.Hour)) {
|
|
ret.ValidVisitAfterTowDayMap[skey]++
|
|
}
|
|
}
|
|
return err2
|
|
})
|
|
if err1 != nil {
|
|
log.Error("FindManyVisitInfo error ", log.E(err1))
|
|
return nil, err1
|
|
}
|
|
// 充值统计
|
|
rechargeFilter := bson.M{"districtCode": channel, "appId": ruleInfo.AppId, "successAt": bson.M{"$gte": start, "$lt": end}}
|
|
rechargeList, _ := rechargemod.FindManyRechargeInfo(ctx, rechargeFilter)
|
|
for _, item := range rechargeList {
|
|
skey := key(ruleInfo.AppId, item.UserId)
|
|
regUser := registerDict[skey]
|
|
if regUser == nil {
|
|
continue
|
|
}
|
|
ret.RegisterUserMap[skey]++
|
|
ret.RechargeCount++
|
|
ret.RechargeAmount += item.PayMoney
|
|
}
|
|
// 游戏充值
|
|
gamerechageList, err := rechargegamemod.FindManyRechargeInfo(ctx, rechargeFilter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, item := range gamerechageList {
|
|
skey := key(ruleInfo.AppId, item.UserId)
|
|
regUser := registerDict[skey]
|
|
if regUser == nil {
|
|
continue
|
|
}
|
|
ret.RegisterUserMap[skey]++
|
|
ret.GameRecharge += item.Money
|
|
}
|
|
gamewithdrawList, err := withdrawGameOrdermod.FindManyGameWithdrawOrder(ctx, rechargeFilter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, item := range gamewithdrawList {
|
|
skey := key(ruleInfo.AppId, item.UID)
|
|
regUser := registerDict[skey]
|
|
if regUser == nil {
|
|
continue
|
|
}
|
|
ret.GameWithdraw += item.Money
|
|
}
|
|
}
|
|
return ret, nil
|
|
}
|