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 }