支付和广告调试

This commit is contained in:
2026-09-15 22:11:05 +08:00
parent 3a79d6a10c
commit 97c9588e5d
12 changed files with 328 additions and 198 deletions
+128 -94
View File
@@ -9,16 +9,17 @@ import (
"sort"
"strconv"
"strings"
"time"
"sync"
"91porn-server/app/appg"
"91porn-server/app/service/activityclient"
"91porn-server/common"
"91porn-server/common/crypt"
"91porn-server/common/httputil"
"91porn-server/common/log"
"91porn-server/models/v/usermod"
"91porn-server/models/v/walletmod"
"github.com/robfig/cron/v3"
)
/*
@@ -120,115 +121,148 @@ func (ad AdDetailInfo) GetAdvertiseType() int {
return ad.AdvertiseType
}
// JtAdvertiseThreeServer 集团广告中心
func JtAdvertiseThreeServer() ([]AdSlot, error) {
var foreverCacheKey = fmt.Sprintf("jtAdForever-%s-%s", appg.Conf.AdCenter.MerchantCode, appg.Conf.AdCenter.AppCode)
redisKey := fmt.Sprintf("jtAd-%s-%s", appg.Conf.AdCenter.MerchantCode, appg.Conf.AdCenter.AppCode)
str, err := appg.Redis.Get(redisKey)
if err != nil {
log.Error(fmt.Sprintf("JtAdvertiseThreeServer 缓存获取广告列表信息异常:%v", err))
}
var resp []AdSlot
if str != nil {
if err = json.Unmarshal([]byte(*str), &resp); err == nil {
return resp, nil
}
log.Error(fmt.Sprintf("JtAdvertiseThreeServer 解析缓存数据异常:%v", err))
}
req := JtAdvertiseReq{
MerchantCode: appg.Conf.AdCenter.MerchantCode,
AppCode: appg.Conf.AdCenter.AppCode,
AdStatus: 1,
}
// advertiseAppId 广告中心应用ID
const advertiseAppId int32 = 2
var serverResp *JtAdvertiseRes
url := appg.Conf.AdCenter.ApiDomain + "/openapi/getAdvertiseList"
type advertiseClickReq struct {
Id int64 `json:"id"` // 广告id
AppId int32 `json:"appId"` // 应用id
}
type advertiseClickResp struct {
Code int64 `json:"code"` // 错误码
}
// AdvertiseClickCenter 上报广告点击到广告中心
func AdvertiseClickCenter(advertiseId int64) error {
req := advertiseClickReq{
Id: advertiseId,
AppId: advertiseAppId,
}
resp := advertiseClickResp{}
url := appg.Conf.URL.VersionUrl + "/api/stat/advitise/v2/click"
bodyStr, _ := json.Marshal(req)
code, err := httputil.DefaultClientPostJsonWithResp(&serverResp, url, nil, bodyStr)
code, err := httputil.DefaultClientPostJsonWithResp(&resp, url, nil, bodyStr)
if err != nil {
log.Error("JtAdvertiseThreeServer POSTWithJResp ", log.Any("url", url), log.E(err))
// 从最后请求成功的一次拿数据
return getFromLastTime(foreverCacheKey, err)
log.Error("AdvertiseClickCenter POSTWithJResp", log.Any("url", url), log.Any("req", req), log.E(err))
return err
}
if code != http.StatusOK {
log.Error("JtAdvertiseThreeServer response status ", log.Any("code", code))
// 从最后请求成功的一次拿数据
return getFromLastTime(foreverCacheKey, errors.New("response status err"))
log.Error("AdvertiseClickCenter response status", log.Any("code", code), log.Any("req", req))
return fmt.Errorf("response status err")
}
if serverResp.Code != 0 {
log.Error("JtAdvertiseThreeServer response code ", log.Any("code", serverResp.Code), log.Any("msg", serverResp.Msg))
// 从最后请求成功的一次拿数据
return getFromLastTime(foreverCacheKey, errors.New("response code err"))
}
adsData, err := crypt.AdDecrypt(serverResp.Data, appg.Conf.AdCenter.AesKey)
if err != nil {
log.Error(fmt.Sprintf("JtAdvertiseThreeServer 解密广告数据异常:%v", err))
return nil, errors.New("response data err")
}
err = json.Unmarshal([]byte(adsData), &resp)
if err != nil {
log.Error(fmt.Sprintf("JtAdvertiseThreeServer 解析 JSON 失败:%v", err))
return nil, errors.New("data format error")
}
// 对广告进行升序排序
for i := range resp {
sort.Slice(resp[i].AdDetailInfoList, func(j, k int) bool {
return resp[i].AdDetailInfoList[j].Sort < resp[i].AdDetailInfoList[k].Sort
})
}
// 将最后一次请求成功的数据更新到二级缓存
common.Go(func() {
setAdsCache(foreverCacheKey, resp)
})
common.Go(func() {
data, err := json.Marshal(&resp)
if err != nil {
log.Error(fmt.Sprintf("JtAdvertiseThreeServer json序列化缓存数据异常:%v", err))
return
}
if err = appg.Redis.Set(redisKey, data, time.Minute); err != nil {
log.Error(fmt.Sprintf("JtAdvertiseThreeServer 保存缓存数据异常:%v", err))
}
})
return resp, nil
return nil
}
// getFromLastTime 返回最后一次请求的广告数据
func getFromLastTime(foreverCacheKey string, e error) ([]AdSlot, error) {
str, err := appg.Redis.Get(foreverCacheKey)
// AsyncAdvertiseClick 异步上报广告点击,广告id非数字时忽略
func AsyncAdvertiseClick(id string) {
advertiseId, err := strconv.ParseInt(strings.TrimSpace(id), 10, 64)
if err != nil {
log.Error(fmt.Sprintf("getFromLastTime 缓存获取广告列表信息异常:%v", err))
return nil, e
log.Warn("AsyncAdvertiseClick invalid advertise id", log.Any("id", id))
return
}
var resp []AdSlot
if str != nil {
if err = json.Unmarshal([]byte(*str), &resp); err == nil {
return resp, nil
}
log.Error(fmt.Sprintf("getFromLastTime 解析缓存数据异常:%v", err))
}
return nil, e
common.Go(func() {
_ = AdvertiseClickCenter(advertiseId)
})
}
// setAdsCache 更新最后一次请求的广告数据
func setAdsCache(foreverCacheKey string, resp []AdSlot) {
data, err := json.Marshal(&resp)
var (
advertiseCacheOnce sync.Once
advertiseCacheMu sync.RWMutex
advertiseCache []AdSlot
advertiseCacheOK bool
)
// JtAdvertiseThreeServer 获取广告位列表(内存缓存,每两分钟从广告中心刷新一次)
func JtAdvertiseThreeServer() ([]AdSlot, error) {
advertiseCacheOnce.Do(startAdvertiseCache)
advertiseCacheMu.RLock()
defer advertiseCacheMu.RUnlock()
if !advertiseCacheOK {
return nil, errors.New("advertise cache not ready")
}
res := make([]AdSlot, len(advertiseCache))
copy(res, advertiseCache)
return res, nil
}
// startAdvertiseCache 首次加载广告并启动定时刷新
func startAdvertiseCache() {
updataAdvertiseInfo()
c := cron.New(cron.WithSeconds())
_, _ = c.AddFunc("0 */2 * * * ?", updataAdvertiseInfo) // 两分钟更新一次
c.Start()
}
// updataAdvertiseInfo 从广告中心拉取广告并更新缓存,列表为空时重试一次
func updataAdvertiseInfo() {
advertiseResp, err := advertiseCenterServer()
if err != nil {
log.Error(fmt.Sprintf("setAdsCache json序列化缓存数据异常:%v", err))
log.Error("advertiseCenterServer", log.E(err))
return
}
if err := appg.Redis.Set(foreverCacheKey, data, time.Hour*72); err != nil {
log.Error(fmt.Sprintf("setAdsCache 保存缓存数据异常:%v", err))
log.Error("advertiseCenterServer", log.Any("advertiseResp", advertiseResp))
if len(advertiseResp.AdvertiseList) == 0 {
advertiseResp, err = advertiseCenterServer()
if err != nil {
log.Error("advertiseCenterServer", log.E(err))
return
}
}
list := advertiseResp.AdvertiseList
sort.SliceStable(list, func(i, j int) bool {
if list[i].LocId != list[j].LocId {
return list[i].LocId < list[j].LocId
}
return list[i].Sort < list[j].Sort
})
// 每条广告单独作为一个广告位返回,广告位名称取广告标题
slots := make([]AdSlot, 0, len(list))
for _, value := range list {
slots = append(slots, AdSlot{
AdvertiseLocationCode: strconv.FormatInt(int64(value.LocId), 10),
AdvertiseLocationName: value.Title,
AdDetailInfoList: []AdDetailInfo{{
AdvertiseCode: strconv.FormatInt(value.Id, 10),
AdvertiseName: value.Title,
AdvertiseUrl: value.Link,
AdvertiseIcon: value.CoverImg,
AdvertiseDesc: value.Remark,
Sort: int(value.Sort),
}},
})
}
advertiseCacheMu.Lock()
advertiseCache = slots
advertiseCacheOK = true
advertiseCacheMu.Unlock()
}
// advertiseCenterServer 请求广告中心广告列表
func advertiseCenterServer() (resp AdvertiseRes, err error) {
req := AdvertiseReq{
AppId: advertiseAppId,
}
url := appg.Conf.URL.VersionUrl + "/api/stat/advitise/v2/get"
bodyStr, _ := json.Marshal(req)
code, err := httputil.DefaultClientPostJsonWithResp(&resp, url, nil, bodyStr)
if err != nil {
log.Error("advertiseCenterServer POSTWithJResp ", log.Any("url", url), log.E(err))
return
}
log.Info("*************\n\n\n", log.Any("", resp))
if code != http.StatusOK {
log.Error("advertiseCenterServer response status ", log.Any("code", code))
err = fmt.Errorf("response status err")
return
}
return
}
func GetAdvertiseLocation(adverId string) (res proto.AdsInfo) {