Files
stat_center/service/advitiseV2Ser/get_click.go
T
rootandClaude Opus 5 01d9f7bc86 新增广告V2模块,双端下载落地页调整
- 新增 advitise v2: info/location/bind/click-stat/day-click-stat 模型与
  对应的 service、api、router、proto 定义
- models/index.go 注册 5 个新模型的索引初始化
- 鉴权白名单: /rsdownload/ 改为 /download/,放行 advitise v2 的
  get/click 接口
- statg/config: proxyUrl 增加 fileRes1
- common/genId: lid 生成逻辑补充
- 新增 91fans / huangguo 的 mobileconfig 描述文件
- 新增 deploy/nginx/cpcdownload.mfcg.me.conf 网关配置

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 16:53:23 +08:00

215 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package advitiseV2Ser
import (
"context"
"errors"
"stat/api/proto"
"stat/common/log"
"stat/models/advitiseBindMod"
"stat/models/advitiseClickStatMod"
"stat/models/advitiseDayClickStatMod"
"stat/models/advitiseInfoMod"
"stat/models/advitiseLocationMod"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
// idScale 把 (bindId, locId) 编码进单个 int64 id 的乘数
// 约束:locId < idScale。int64 上限允许 bindId 最大约 9.2e13,远超实际 LID 生成量
const idScale = int64(100000)
// GetAdvitises 外部拉广告:响应结构与老 GetAdvertise (proto.AdvertiseRes) 一致
// - 每条广告绑定一个 (bindId, locId) 组合
// - CoverImg 依据 location.AdvitiseSize 选 info 里对应尺寸组的第一张
// - 返回的 id = bindId*idScale + locId,client 点击时原样回传,后端解码定位 (bind, locId)
// - BindId 也单独返回,给愿意用二维接口的 client 用
func GetAdvitises(ctx context.Context, req *proto.GetAdvitiseV2Req) (*proto.AdvertiseRes, error) {
resp := &proto.AdvertiseRes{AdvertiseList: make([]*proto.AdvertiseInfo, 0)}
// 1) 拉 bind
filter := bson.M{advitiseBindMod.FN.AdvitiseBind.AppId: req.AppId}
if req.LocationId != nil {
filter[advitiseBindMod.FN.AdvitiseBind.LocationId] = *req.LocationId
}
opt := &options.FindOptions{}
opt.SetSort(bson.D{
{Key: advitiseBindMod.FN.AdvitiseBind.Sort, Value: -1},
{Key: advitiseBindMod.FN.AdvitiseBind.CreatedAt, Value: -1},
})
binds, err := advitiseBindMod.FindManyAdvitiseBinds(ctx, filter, opt)
if err != nil {
return nil, err
}
if len(binds) == 0 {
return resp, nil
}
// 2) 批量拉当前生效 info
advitiseIds := uniqInt64(func() []int64 {
out := make([]int64, 0, len(binds))
for _, b := range binds {
out = append(out, b.AdvitiseId)
}
return out
}())
now := time.Now()
infos, err := advitiseInfoMod.FindManyAdvitiseInfos(ctx, bson.M{
advitiseInfoMod.FN.AdvitiseInfo.Id: bson.M{"$in": advitiseIds},
advitiseInfoMod.FN.AdvitiseInfo.Status: true,
advitiseInfoMod.FN.AdvitiseInfo.StartTime: bson.M{"$lte": now},
advitiseInfoMod.FN.AdvitiseInfo.EndTime: bson.M{"$gte": now},
})
if err != nil {
return nil, err
}
infoMap := make(map[int64]*advitiseInfoMod.AdvitiseInfo, len(infos))
for _, info := range infos {
infoMap[info.Id] = info
}
// 3) 批量拉 location(用于 CoverImg 尺寸匹配)
locIdsAll := uniqInt32(func() []int32 {
out := make([]int32, 0)
for _, b := range binds {
out = append(out, b.LocationId...)
}
return out
}())
locMap := make(map[int32]*advitiseLocationMod.AdvitiseLocation)
if len(locIdsAll) > 0 {
locs, lerr := advitiseLocationMod.FindManyAdvitiseLocations(ctx, bson.M{
advitiseLocationMod.FN.AdvitiseLocation.AppId: req.AppId,
advitiseLocationMod.FN.AdvitiseLocation.LocId: bson.M{"$in": locIdsAll},
})
if lerr == nil {
for _, l := range locs {
locMap[l.LocId] = l
}
}
}
// 4) 展开 bind × location 为 item
for _, b := range binds {
info, ok := infoMap[b.AdvitiseId]
if !ok {
continue
}
for _, locId := range b.LocationId {
if req.LocationId != nil && locId != *req.LocationId {
continue
}
var size advitiseLocationMod.AdvitiseSizeType
if loc, ok := locMap[locId]; ok && loc != nil {
size = loc.AdvitiseSize
}
resp.AdvertiseList = append(resp.AdvertiseList, &proto.AdvertiseInfo{
Id: b.Id*idScale + int64(locId),
Title: info.Title,
CoverImg: pickCoverImg(info, size),
LocId: locId,
JumpType: 0, // V2 素材未维护跳转类型,默认外部浏览器
Link: info.Link,
Sort: b.Sort,
Type: 0,
Tags: "",
Remark: info.Remark,
AmbientColor: "",
BindId: b.Id,
})
}
}
return resp, nil
}
// pickCoverImg 按位置尺寸选一张封面;取不到就用任一非空数组的第一张兜底
func pickCoverImg(info *advitiseInfoMod.AdvitiseInfo, size advitiseLocationMod.AdvitiseSizeType) string {
var arr []string
switch size {
case advitiseLocationMod.AdvitiseSizeFullScreen:
arr = info.FullScreenImgs
case advitiseLocationMod.AdvitiseSizeBanner720300:
arr = info.Banner720300Imgs
case advitiseLocationMod.AdvitiseSizeBanner720150:
arr = info.Banner720150Imgs
case advitiseLocationMod.AdvitiseSizeBanner750700:
arr = info.Banner750700Imgs
case advitiseLocationMod.AdvitiseSizeBanner800450:
arr = info.Banner800450Imgs
case advitiseLocationMod.AdvitiseSizePopUps600800:
arr = info.PopUps600800Imgs
case advitiseLocationMod.AdvitiseSizePopUps512512:
arr = info.PopUps512512Imgs
case advitiseLocationMod.AdvitiseSizeSmallCube:
arr = info.SmallCubeImgs
case advitiseLocationMod.AdvitiseSizeVerticalCube:
arr = info.VerticalCubeImgs
}
if len(arr) > 0 {
return arr[0]
}
// 兜底:任一非空数组的第一张
for _, cand := range [][]string{
info.FullScreenImgs, info.Banner720300Imgs, info.Banner720150Imgs,
info.Banner750700Imgs, info.Banner800450Imgs,
info.PopUps600800Imgs, info.PopUps512512Imgs,
info.SmallCubeImgs, info.VerticalCubeImgs,
} {
if len(cand) > 0 {
return cand[0]
}
}
return ""
}
func uniqInt64(in []int64) []int64 {
seen := make(map[int64]struct{}, len(in))
out := make([]int64, 0, len(in))
for _, v := range in {
if _, ok := seen[v]; ok {
continue
}
seen[v] = struct{}{}
out = append(out, v)
}
return out
}
func uniqInt32(in []int32) []int32 {
seen := make(map[int32]struct{}, len(in))
out := make([]int32, 0, len(in))
for _, v := range in {
if _, ok := seen[v]; ok {
continue
}
seen[v] = struct{}{}
out = append(out, v)
}
return out
}
// ClickAdvitise 点击回传:media 逻辑
// 1. advitise_click_stat upsert +1 (appId, advitiseId, locationId, day)
// 2. advitise_day_click_stat upsert +1 (advitiseId, day)
func ClickAdvitise(ctx context.Context, req *proto.ClickAdvitiseV2Req) error {
bindId := req.Id / idScale
location := int32(req.Id % idScale)
bind, err := advitiseBindMod.FindOneAdvitiseBind(ctx, bson.M{advitiseBindMod.FN.AdvitiseBind.Id: bindId})
if err != nil || bind == nil {
return errors.New("bind not found")
}
day := time.Now().Truncate(24 * time.Hour)
if err := advitiseClickStatMod.InsertOrUpdate(ctx, bind.AppId, bind.AdvitiseId, location, day); err != nil {
log.Warn("v2 click: fine stat upsert failed", log.E(err))
return err
}
if err := advitiseDayClickStatMod.InsertOrUpdate(ctx, bind.AdvitiseId, day); err != nil {
// 汇总表失败不阻断细维度已成功的记录
log.Warn("v2 click: day rollup upsert failed", log.E(err))
}
return nil
}