Files
2026-05-20 16:13:58 +08:00

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
}