@@ -0,0 +1,83 @@
|
||||
package adser
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"91porn-server/app/proto"
|
||||
"91porn-server/app/service/annouser"
|
||||
"91porn-server/common"
|
||||
"91porn-server/models/v/adsmod"
|
||||
"91porn-server/models/v/annoumod"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func toAdsResSlice(slice adsmod.AdsSlice) []proto.AdsInfo {
|
||||
ads := make([]proto.AdsInfo, len(slice))
|
||||
for i, v := range slice {
|
||||
ads[i] = proto.AdsInfo{
|
||||
// ID: v.ID,
|
||||
Cover: v.Cover,
|
||||
Href: v.Href,
|
||||
Position: int(v.Position),
|
||||
SortCode: v.SortCode,
|
||||
}
|
||||
}
|
||||
return ads
|
||||
}
|
||||
|
||||
var sysAds = adsmod.SysAds
|
||||
|
||||
func AdsList(adsType adsmod.AdsType, discCode string) (res proto.AdsRes) {
|
||||
var ads []proto.AdsInfo
|
||||
var announ []*annouser.Annou
|
||||
wait := sync.WaitGroup{}
|
||||
wait.Add(2)
|
||||
common.Go(func() {
|
||||
defer wait.Done()
|
||||
if adsType == adsmod.SysAds {
|
||||
adSlice, _ := adsmod.ActiveStartAndEndList(adsmod.Sort_sortCode_N1, nil, nil, (&adsmod.AdsTypeMatch{AdsType: &sysAds}).New())
|
||||
ads = toAdsResSlice(adSlice)
|
||||
} else {
|
||||
ads = toAdsResSlice(GetDiscAdSlice(discCode))
|
||||
}
|
||||
})
|
||||
common.Go(func() {
|
||||
defer wait.Done()
|
||||
announInfo, _ := annouser.GetAnnouList(annoumod.TotalType)
|
||||
announ = append(announ, announInfo)
|
||||
})
|
||||
wait.Wait()
|
||||
res.AdsList = ads
|
||||
if gin.Mode() == gin.DebugMode { //测试模式下向外暴露链接
|
||||
res.AnnounInfo = announ
|
||||
return
|
||||
}
|
||||
res.AnnounInfo = announ
|
||||
return
|
||||
}
|
||||
|
||||
func GetDiscAdSlice(discCode string) adsmod.AdsSlice {
|
||||
mats := []adsmod.Matcher{
|
||||
(&adsmod.DistrictCodeMatch{DistrictCode: &discCode}).New(),
|
||||
}
|
||||
discADSlice, _ := adsmod.ActiveStartAndEndList(adsmod.Sort_sortCode_N1, nil, nil, mats...)
|
||||
//未配置渠道广告的广告位,展示系统广告
|
||||
mats = []adsmod.Matcher{
|
||||
(&adsmod.AdsTypeMatch{AdsType: &sysAds}).New(),
|
||||
(&adsmod.AdPositionNinMatch{PositionList: discADSlice.ToPositions()}).New(),
|
||||
}
|
||||
ads, _ := adsmod.ActiveStartAndEndList(adsmod.Sort_sortCode_N1, nil, nil, mats...)
|
||||
ads = append(ads, discADSlice...)
|
||||
sort.Sort(ads)
|
||||
return ads
|
||||
}
|
||||
|
||||
func AdList(adsType adsmod.AdsType, discCode string) []proto.AdsInfo {
|
||||
if adsType == adsmod.SysAds {
|
||||
adSlice, _ := adsmod.ActiveStartAndEndList(adsmod.Sort_sortCode_N1, nil, nil, (&adsmod.AdsTypeMatch{AdsType: &sysAds}).New())
|
||||
return toAdsResSlice(adSlice)
|
||||
}
|
||||
return toAdsResSlice(GetDiscAdSlice(discCode))
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package adser
|
||||
|
||||
import (
|
||||
"91porn-server/models/v/dailytaskmod"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/app/service/taskser"
|
||||
"91porn-server/common/constant/redisconst"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/models/commod"
|
||||
"91porn-server/models/l/adsclicklogmod"
|
||||
"91porn-server/models/v/usermod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
type AdvertiseReq struct {
|
||||
AppId int32 `form:"appId" json:"appId" binding:"required"` // 应用id
|
||||
LocId *int32 `form:"locId" json:"locId" binding:"omitempty"` // 位置id
|
||||
UserId *uint64 `form:"userId" json:"userId" binding:"omitempty"` // 用户ID
|
||||
IP *string `form:"ip" json:"ip" binding:"omitempty"` // 用户IP
|
||||
}
|
||||
|
||||
type AdvertiseRes struct {
|
||||
AdvertiseList []AdvertiseInfo `json:"advertiseList"` // 广告列表
|
||||
}
|
||||
|
||||
type AdsClickReq struct {
|
||||
Id string `from:"id" json:"id" binding:"required"` // 广告id
|
||||
AppId int32 `from:"appId" json:"appId" binding:"required"` // 应用id
|
||||
ChannelCode string `from:"channelCode" json:"channelCode" binding:"channelCode"`
|
||||
}
|
||||
|
||||
type AdsClickResp struct {
|
||||
Code int64 `from:"code" json:"code"` // 错误骂
|
||||
}
|
||||
|
||||
// 外部广告信息
|
||||
type AdvertiseInfo struct {
|
||||
Id int64 `json:"id"` // 广告id
|
||||
Title string `json:"title"` // 广告标题
|
||||
CoverImg string `json:"coverImg"` // 封面
|
||||
LocId int32 `json:"locId"` // 位置id
|
||||
JumpType int32 `json:"jumpType"` // 跳转方式 0:外部浏览器跳转 1:内部浏览器跳转 2:app内部跳转
|
||||
Link string `json:"link"` // 链接地址
|
||||
Sort int64 `json:"sort"` // 排序
|
||||
}
|
||||
|
||||
func AdvertiseThreeServer(userId uint64, ip string) (*AdvertiseRes, error) {
|
||||
str, err := appg.Redis.Get(redisconst.CenterAdvertiseCache)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("用户ID:%d;IP:%s;缓存获取广告列表信息异常:%v", userId, ip, err))
|
||||
}
|
||||
var resp AdvertiseRes
|
||||
if str != nil {
|
||||
if err = json.Unmarshal([]byte(*str), &resp); err == nil {
|
||||
return &resp, nil
|
||||
}
|
||||
log.Warn(fmt.Sprintf("用户ID:%d;IP:%s;解析缓存数据异常:%v", userId, ip, err))
|
||||
}
|
||||
req := AdvertiseReq{
|
||||
AppId: commod.KFK_APPID,
|
||||
IP: &ip,
|
||||
}
|
||||
if userId > 0 {
|
||||
req.UserId = &userId
|
||||
}
|
||||
url := appg.Conf.URL.ProductUrl + "/api/stat/ads/get"
|
||||
bodyStr, _ := json.Marshal(req)
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&resp, url, nil, bodyStr)
|
||||
if err != nil {
|
||||
log.Error("AdvertiseThreeServer POSTWithJResp ", log.Any("url", url), log.E(err))
|
||||
return nil, err
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
log.Error("AdvertiseThreeServer response status ", log.Any("code", code))
|
||||
return nil, fmt.Errorf("response status err")
|
||||
}
|
||||
data, err := json.Marshal(&resp)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("用户ID:%d;IP:%s;json序列化缓存数据异常:%v", userId, ip, err))
|
||||
return &resp, nil
|
||||
}
|
||||
if err = appg.Redis.Set(redisconst.CenterAdvertiseCache, data, 45*time.Second); err != nil {
|
||||
log.Warn(fmt.Sprintf("用户ID:%d;IP:%s;保存缓存数据异常:%v", userId, ip, err))
|
||||
}
|
||||
// log.Info("AdvertiseThreeServer response", log.Any("resp", resp))
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func AdvertiseClickThreeServer(advertiseId string, uid uint64) error {
|
||||
//查询用户信息
|
||||
u, err := usermod.FindUserByUID(uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if u.DistrictCode == "" {
|
||||
u.DistrictCode = "system"
|
||||
}
|
||||
req := AdsClickReq{
|
||||
AppId: commod.KFK_APPID,
|
||||
Id: advertiseId,
|
||||
ChannelCode: u.DistrictCode,
|
||||
}
|
||||
resp := AdsClickResp{}
|
||||
url := appg.Conf.URL.ProductUrl + "/api/product/ads/dayClick"
|
||||
bodyStr, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
log.Info(fmt.Sprintf("AdvertiseClickThreeServer json.Marshal is fail error:%+v/data:%+v", err, req))
|
||||
return err
|
||||
}
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&resp, url, nil, bodyStr)
|
||||
if err != nil {
|
||||
log.Error("AdvertiseClickThreeServer POSTWithJResp ", log.Any("url", url), log.E(err))
|
||||
return err
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
log.Error("AdvertiseClickThreeServer response status ", log.Any("code", code))
|
||||
return fmt.Errorf("response status err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AdvertiseNavigate(advertiseId string, uid uint64, ua, logType string) error {
|
||||
advId, err := primitive.ObjectIDFromHex(advertiseId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if advId.IsZero() {
|
||||
return errors.New("empty advid")
|
||||
}
|
||||
header := map[string]string{
|
||||
"log-id": advertiseId,
|
||||
"User-Agent": ua,
|
||||
"log-type": logType,
|
||||
}
|
||||
targetUrl := appg.Conf.URL.NavigateUrl + "/api/application/dHH9h0Kp1074"
|
||||
if _, _, err = httputil.DefaultClientGetBytes(targetUrl, header, nil); err != nil {
|
||||
log.Error("navigate report fail", log.E(err))
|
||||
return err
|
||||
}
|
||||
if err := adsclicklogmod.AddClick(uid, advId, logType, 1); err != nil {
|
||||
log.Error("adclick fail", log.E(err))
|
||||
return err
|
||||
}
|
||||
go func() { _ = taskser.CompleteDailyTask(nil, uid, dailytaskmod.DailyTaskTypeAdsClick) }()
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
package adser
|
||||
|
||||
import (
|
||||
"91porn-server/app/proto"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
/*
|
||||
测试:
|
||||
部门CODE:1991129769626804224
|
||||
商户CODE:1991129808640122880
|
||||
应用CODE:jh_appid01
|
||||
客户CODE:1991129948159451136
|
||||
*/
|
||||
|
||||
type JtAdvertiseReq struct {
|
||||
MerchantCode string `json:"merchantCode"` // 商户 code,必填
|
||||
AppCode string `json:"appCode"` // 应用 code,必填
|
||||
AdStatus int `json:"adStatus"` // 广告状态 1-上架,0-下架,2-未开始,3-已过期,4-即将到期 默认查询全部
|
||||
//AdvertiseLocationCode string `json:"advertiseLocationCode,omitempty"` // 广告位唯一标识,选填
|
||||
//AdvertiseCode string `json:"advertiseCode,omitempty"` // 广告唯一标识,选填
|
||||
//PageNo int `json:"pageNo,omitempty"` // 页码,全量查询不需要传,选填
|
||||
//PageSize int `json:"pageSize,omitempty"` // 每页条数,全量查询不需要传,选填
|
||||
}
|
||||
|
||||
type JtAdvertiseRes struct {
|
||||
Code int `json:"code"` // 返回状态码
|
||||
Msg string `json:"msg"` // 返回消息
|
||||
Data string `json:"data"` // 广告信息 - 加密
|
||||
}
|
||||
|
||||
// AdSlot 广告位信息
|
||||
type AdSlot struct {
|
||||
DeptCode string `json:"deptCode"` // 部门 code
|
||||
MerchantCode string `json:"merchantCode"` // 商户 code
|
||||
AppCode string `json:"appCode"` // 应用 code
|
||||
LocationType int `json:"locationType"` // 广告位类型:0 → 开屏广告 1 → 弹窗广告 2 → 图标广告 3 → 九宫格广告 4 → 信息流广告 5 → 瀑布流广告 6 → 详情广告 7 → 片头广告
|
||||
AdvertiseLocationCode string `json:"advertiseLocationCode"` // 广告位标识
|
||||
AdvertiseLocationName string `json:"advertiseLocationName"` // 广告位名称
|
||||
DisplayMode int `json:"displayMode"` // 展示模式:0 → 多个轮播, 1 → 单体, 2 → 三分屏, 3 → 四分屏, 4 → 小图标, 5 → 大图标
|
||||
AdvertiseHeight int `json:"advertiseHeight"` // 高
|
||||
AdvertiseWidth int `json:"advertiseWidth"` // 宽
|
||||
MaterialType int `json:"materialType"` // 素材类型(视频/图片):1 → 视频, 2 → 图片, 3 → 视频、图片
|
||||
AdLimit int `json:"adLimit"` // 广告限制数量
|
||||
AdDetailInfoList []AdDetailInfo `json:"adDetailInfoList"` // 广告详情信息列表
|
||||
}
|
||||
|
||||
// AdDetailInfo 广告详情信息
|
||||
type AdDetailInfo struct {
|
||||
AdvertiseCode string `json:"advertiseCode"` // 广告业务code
|
||||
CustomerCode string `json:"customerCode"` // 客户code
|
||||
AdvertiseName string `json:"advertiseName"` // 广告名称
|
||||
AdvertiseUrl string `json:"advertiseUrl"` // 广告链接
|
||||
AdvertiseIcon string `json:"advertiseIcon"` // 广告图片地址
|
||||
AdvertiseType int `json:"advertiseType"` // 广告类型:1 → 播放器, 2 → 药台, 3 → 炮台, 4 → 黄游, 5 → 直播, 6 → BC
|
||||
AdMode string `json:"adMode"` // 广告模式
|
||||
AppCode string `json:"appCode"` // 应用 code
|
||||
LocationType int `json:"locationType"` // 广告位类型:0 → 开屏广告 1 → 弹窗广告 2 → 图标广告 3 → 九宫格广告 4 → 信息流广告 5 → 瀑布流广告 6 → 详情广告 7 → 片头广告
|
||||
AdvertiseDesc string `json:"advertiseDesc"` // 广告描述
|
||||
PageType string `json:"pageType"` // 内部路由页面类型:如 rechange_page → 会员充值页, gold_rechange_page → 金币充值页, invite_page → 邀请分享页
|
||||
StartTimeStamp int64 `json:"startTimeStamp"` // 广告开始时间 时间戳
|
||||
EndTimeStamp int64 `json:"endTimeStamp"` // 广告结束时间 时间戳
|
||||
Sort int `json:"sort"` // 排序
|
||||
AdExtData string `json:"adExtData"` // 扩展字段1 = CoverImgSize
|
||||
}
|
||||
|
||||
type Extra struct {
|
||||
CoverImgSize string `json:"coverImgSize"`
|
||||
WatchTime int `json:"watchTime"`
|
||||
DownloadCount int64 `json:"downloadCount"`
|
||||
Type string `json:"type"` // 应用类型 app:APP、web:网页
|
||||
Location string `json:"location"` // 位置 1:顶部 2:底部
|
||||
DisplayType string `json:"displayType"` // 展示类型 heng:横版 shu:竖版
|
||||
}
|
||||
|
||||
func (ad AdDetailInfo) GetExtraData() (res Extra) {
|
||||
_ = json.Unmarshal([]byte(ad.AdExtData), &res)
|
||||
return
|
||||
}
|
||||
|
||||
func (ad AdDetailInfo) GetRealLink(user *usermod.User, w *walletmod.Wallet) string {
|
||||
ad.AdvertiseUrl = activityclient.ReplaceActivityDomain(ad.AdvertiseUrl, user, w)
|
||||
return strings.ReplaceAll(ad.AdvertiseUrl, "inner://yinseinner/", "yinseinner://")
|
||||
}
|
||||
|
||||
func (ad AdDetailInfo) GetCoverLsj() string {
|
||||
if ad.AdvertiseIcon == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.TrimLeft(ad.AdvertiseIcon, "/")
|
||||
}
|
||||
|
||||
func (ad AdDetailInfo) GetAdvertiseType() int {
|
||||
// 内部顺序:1 应用 2 游戏 3 炮台 4 棋牌 5 直播
|
||||
// 外部顺序:1:应用 2:药台、3:炮台、4:游戏、5:直播、6:棋牌
|
||||
if ad.AdvertiseType == 4 {
|
||||
return 2
|
||||
}
|
||||
if ad.AdvertiseType == 6 {
|
||||
return 4
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
var serverResp *JtAdvertiseRes
|
||||
url := appg.Conf.AdCenter.ApiDomain + "/openapi/getAdvertiseList"
|
||||
bodyStr, _ := json.Marshal(req)
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&serverResp, url, nil, bodyStr)
|
||||
if err != nil {
|
||||
log.Error("JtAdvertiseThreeServer POSTWithJResp ", log.Any("url", url), log.E(err))
|
||||
// 从最后请求成功的一次拿数据
|
||||
return getFromLastTime(foreverCacheKey, err)
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
log.Error("JtAdvertiseThreeServer response status ", log.Any("code", code))
|
||||
// 从最后请求成功的一次拿数据
|
||||
return getFromLastTime(foreverCacheKey, errors.New("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
|
||||
}
|
||||
|
||||
// getFromLastTime 返回最后一次请求的广告数据
|
||||
func getFromLastTime(foreverCacheKey string, e error) ([]AdSlot, error) {
|
||||
str, err := appg.Redis.Get(foreverCacheKey)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("getFromLastTime 缓存获取广告列表信息异常:%v", err))
|
||||
return nil, e
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// setAdsCache 更新最后一次请求的广告数据
|
||||
func setAdsCache(foreverCacheKey string, resp []AdSlot) {
|
||||
data, err := json.Marshal(&resp)
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("setAdsCache json序列化缓存数据异常:%v", err))
|
||||
return
|
||||
}
|
||||
|
||||
if err := appg.Redis.Set(foreverCacheKey, data, time.Hour*72); err != nil {
|
||||
log.Error(fmt.Sprintf("setAdsCache 保存缓存数据异常:%v", err))
|
||||
}
|
||||
}
|
||||
|
||||
func GetAdvertiseLocation(adverId string) (res proto.AdsInfo) {
|
||||
list, err := JtAdvertiseThreeServer()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, adverLocation := range list {
|
||||
for _, ad := range adverLocation.AdDetailInfoList {
|
||||
if ad.AdvertiseCode == adverId {
|
||||
pos, _ := strconv.Atoi(adverLocation.AdvertiseLocationCode)
|
||||
extra := ad.GetExtraData()
|
||||
res = proto.AdsInfo{
|
||||
ID: ad.AdvertiseCode,
|
||||
Title: ad.AdvertiseName,
|
||||
Description: ad.AdvertiseDesc,
|
||||
Cover: ad.GetCoverLsj(),
|
||||
Href: ad.GetRealLink(nil, nil),
|
||||
Position: pos,
|
||||
PositionName: adverLocation.AdvertiseLocationName,
|
||||
SortCode: ad.Sort,
|
||||
CoverImgSize: extra.CoverImgSize,
|
||||
WatchTime: extra.WatchTime,
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package adser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/constant/redisconst"
|
||||
"91porn-server/common/httputil"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/models/commod"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
)
|
||||
|
||||
/*
|
||||
福利-游戏广告 100001 GameAppList
|
||||
福利-直播广告 100002 ZbAppList
|
||||
福利-炮台广告 100003 YpAppList
|
||||
福利-棋牌广告 100004 QpAppList
|
||||
福利-视频广告 100005
|
||||
福利-横版广告 100006 HengAppList
|
||||
福利-横一广告 100007
|
||||
福利-竖版广告 100008 ShuAppList
|
||||
福利-文字广告 100009
|
||||
福利-Banner广告 100099 AdvList
|
||||
*/
|
||||
const (
|
||||
AdPosGame = 100001 // 游戏
|
||||
AdPosZhiBo = 100002 // 直播
|
||||
AdPosPaoTai = 100003 // 约炮
|
||||
AdPosQiPai = 100004 // 棋牌
|
||||
AdPosShiPin = 100005 // 视频
|
||||
AdPosHeng = 100006 // 横
|
||||
AdPosHeng1 = 100007 // 横1
|
||||
AdPosShu = 100008 // 竖
|
||||
AdPosWenZi = 100009 // 文字
|
||||
AdPosAds = 100099 // BANNER广告
|
||||
)
|
||||
|
||||
// RecreationListRes 娱乐广告列表请求返回
|
||||
type RecreationListRes struct {
|
||||
HengAppList []AppInfo `json:"hengApp" bson:"hengApp"`
|
||||
ShuAppList []AppInfo `json:"shuApp" bson:"shuApp"`
|
||||
AdvList []AdvInfo `json:"adv" bson:"adv"`
|
||||
GameAppList []AppInfo `json:"gameApp" bson:"gameApp"` // 游戏
|
||||
YpAppList []AppInfo `json:"ypApp" bson:"ypApp"` // 约炮
|
||||
QpAppList []AppInfo `json:"qpApp" bson:"qpApp"` // 棋牌
|
||||
ZbAppList []AppInfo `json:"zbApp" bson:"zbApp"` // 直播
|
||||
}
|
||||
|
||||
type CommonListRes struct {
|
||||
Code int64 `json:"code"`
|
||||
Data RecreationListRes `json:"data"`
|
||||
Msg string `json:"msg"`
|
||||
Time string `json:"time"`
|
||||
Tip string `json:"tip"`
|
||||
}
|
||||
|
||||
// AppInfo 娱乐app实体信息
|
||||
type AppInfo struct {
|
||||
Id string `json:"id"` // ID
|
||||
Name string `json:"name"` // 应用名称
|
||||
Desc string `json:"desc"` // 应用描述
|
||||
Icon string `json:"icon"` // 应用图标
|
||||
Url string `json:"url"` // 应用链接
|
||||
Type string `json:"type"` // 应用类型
|
||||
DownloadNum int64 `json:"downloadNum"` // 应用下载次数
|
||||
//广告-集团上报数据
|
||||
Position int `json:"position"` // 集团广告code
|
||||
PositionName string `json:"positionName"` // 集团广告名称
|
||||
}
|
||||
|
||||
// AdvInfo 娱乐广告实体信息
|
||||
type AdvInfo struct {
|
||||
Id string `json:"id"` // ID
|
||||
Name string `json:"name"` // 广告名称
|
||||
Image string `json:"image"` // 广告图片
|
||||
Url string `json:"url"` // 广告链接
|
||||
Location string `json:"location"` // 位置 1:顶部 2:底部
|
||||
ModuleType int `json:"moduleType"` // 广告模块 1:应用 2:游戏 3:约炮 4:棋牌 5:直播
|
||||
//广告-集团上报数据
|
||||
Position int `json:"position"` // 集团广告code
|
||||
PositionName string `json:"positionName"` // 集团广告名称
|
||||
}
|
||||
|
||||
// RecreationClickInfo 娱乐广告点击参数信息
|
||||
type RecreationClickInfo struct {
|
||||
Id string `form:"id" json:"id" binding:"required"` // 数据id
|
||||
Type string `form:"type" json:"type" binding:"required"` // 数据类型,app or adv
|
||||
SysType string `form:"sysType" json:"sysType" binding:"required"` // 用户设备类型. ios or android
|
||||
}
|
||||
|
||||
// RecreationThreeServer 娱乐广告列表,数据来源于导航站(navigate)
|
||||
func RecreationThreeServer() (RecreationListRes, error) {
|
||||
str, err := appg.Redis.Get(redisconst.NavigateRecreationCache)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("缓存获取娱乐广告信息异常:%v", err))
|
||||
return RecreationListRes{}, err
|
||||
}
|
||||
|
||||
var resp CommonListRes
|
||||
if str != nil && *str != "" {
|
||||
if err = msgpack.Unmarshal([]byte(*str), &resp); err == nil {
|
||||
return resp.Data, nil
|
||||
}
|
||||
log.Warn(fmt.Sprintf("娱乐广告解析缓存数据异常:%v", err))
|
||||
}
|
||||
//请求url
|
||||
url := appg.Conf.URL.NavigateUrl + "/api/application/list/" + strconv.FormatInt(int64(commod.KFK_APPID), 10)
|
||||
//请求
|
||||
code, err := httputil.DefaultClientPostJsonWithResp(&resp, url, nil, nil)
|
||||
if err != nil {
|
||||
log.Error("RecreationThreeServer POSTWithJResp", log.Any("url", url), log.E(err))
|
||||
return resp.Data, err
|
||||
}
|
||||
if code != http.StatusOK {
|
||||
log.Error("RecreationThreeServer response status", log.Any("code", code))
|
||||
return resp.Data, errors.New("response status err")
|
||||
}
|
||||
if len(resp.Data.AdvList) > 0 || len(resp.Data.HengAppList) > 0 || len(resp.Data.ShuAppList) > 0 ||
|
||||
len(resp.Data.GameAppList) > 0 || len(resp.Data.YpAppList) > 0 || len(resp.Data.QpAppList) > 0 || len(resp.Data.ZbAppList) > 0 {
|
||||
common.Go(func() {
|
||||
data, err := msgpack.Marshal(resp)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("娱乐广告json序列化缓存数据异常:%v", err))
|
||||
return
|
||||
}
|
||||
if err = appg.Redis.Set(redisconst.NavigateRecreationCache, data, 6*time.Minute); err != nil {
|
||||
log.Warn(fmt.Sprintf("娱乐广告保存缓存数据异常:%v", err))
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
return resp.Data, nil
|
||||
}
|
||||
|
||||
// RecreationClick 娱乐广告点击记录,请求第三方(navigate)
|
||||
func RecreationClick(p RecreationClickInfo) {
|
||||
//请求url
|
||||
url := appg.Conf.URL.NavigateUrl + "/api/application/click"
|
||||
//请求
|
||||
res, err := httputil.DefaultClientPostJson(url, nil, p)
|
||||
if err != nil {
|
||||
log.Error("RecreationClick POSTWithJResp", log.Any("url", url), log.E(err))
|
||||
return
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
log.Error("RecreationClick response status", log.Any("code", res.StatusCode))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// RecreationFromJt 从广告中心拉取福利页广告
|
||||
func RecreationFromJt() (RecreationListRes, error) {
|
||||
var resp RecreationListRes
|
||||
|
||||
jtAds, err := JtAdvertiseThreeServer()
|
||||
if err != nil {
|
||||
log.Error("JtAdvertiseThreeServer error occur", log.E(err))
|
||||
return resp, err
|
||||
}
|
||||
|
||||
for _, loc := range jtAds {
|
||||
pos, err := strconv.Atoi(loc.AdvertiseLocationCode)
|
||||
if err != nil {
|
||||
log.Error("广告位置代码错误,必须为数字", log.Any("code", loc.AdvertiseLocationCode))
|
||||
continue
|
||||
}
|
||||
if pos < AdPosGame {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ad := range loc.AdDetailInfoList {
|
||||
extra := ad.GetExtraData()
|
||||
if pos == AdPosAds {
|
||||
resp.AdvList = append(resp.AdvList, AdvInfo{
|
||||
Id: ad.AdvertiseCode,
|
||||
Name: ad.AdvertiseName,
|
||||
Image: ad.GetCoverLsj(),
|
||||
Url: ad.GetRealLink(nil, nil),
|
||||
Location: extra.Location,
|
||||
ModuleType: ad.GetAdvertiseType(),
|
||||
Position: pos,
|
||||
PositionName: loc.AdvertiseLocationName,
|
||||
})
|
||||
continue
|
||||
}
|
||||
appInfo := AppInfo{
|
||||
Id: ad.AdvertiseCode,
|
||||
Name: ad.AdvertiseName,
|
||||
Desc: ad.AdvertiseDesc,
|
||||
Icon: ad.GetCoverLsj(),
|
||||
Url: ad.GetRealLink(nil, nil),
|
||||
Type: extra.Type,
|
||||
DownloadNum: extra.DownloadCount,
|
||||
Position: pos,
|
||||
PositionName: loc.AdvertiseLocationName,
|
||||
}
|
||||
switch pos {
|
||||
case AdPosGame:
|
||||
resp.GameAppList = append(resp.GameAppList, appInfo)
|
||||
case AdPosZhiBo:
|
||||
resp.ZbAppList = append(resp.ZbAppList, appInfo)
|
||||
case AdPosPaoTai:
|
||||
resp.YpAppList = append(resp.YpAppList, appInfo)
|
||||
case AdPosQiPai:
|
||||
resp.QpAppList = append(resp.QpAppList, appInfo)
|
||||
case AdPosHeng:
|
||||
resp.HengAppList = append(resp.HengAppList, appInfo)
|
||||
case AdPosShu:
|
||||
resp.ShuAppList = append(resp.ShuAppList, appInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package adser
|
||||
|
||||
import (
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/constant"
|
||||
"91porn-server/common/version"
|
||||
"91porn-server/models/s/useradverstatmod"
|
||||
"91porn-server/models/v/usermod"
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func CanRecord(user *usermod.User) bool {
|
||||
if user.SysType == constant.SysTypeAndroid &&
|
||||
//user.OriVer != "" &&
|
||||
user.AdGroup.InABC() {
|
||||
return VersionCompare(user.OriVer, constant.AdGroupClientVersion)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func VersionCompare(v1, v2 string) bool {
|
||||
ver1, err := version.New(v1)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
ver2, err := version.New(v2)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ver1.GTE(ver2)
|
||||
}
|
||||
|
||||
func UpsertAdStat(ctx context.Context, user *usermod.User, now time.Time, incAppClick, incAdClick int64, payAmount int64) error {
|
||||
if !CanRecord(user) && appg.Conf.Base.Env != "test" {
|
||||
return errors.New("user not eligible for ad stat recording")
|
||||
}
|
||||
local, _ := time.LoadLocation("Asia/Shanghai")
|
||||
|
||||
// 把 day 归一化到当天 0 点,保证和索引一致
|
||||
now = now.In(local)
|
||||
day := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, local)
|
||||
|
||||
filter := bson.M{
|
||||
"userId": user.UID,
|
||||
"date": day,
|
||||
}
|
||||
|
||||
inc := bson.M{}
|
||||
if incAppClick != 0 {
|
||||
inc["appClick"] = incAppClick
|
||||
}
|
||||
if incAdClick != 0 {
|
||||
inc["adClick"] = incAdClick
|
||||
}
|
||||
deltaTotal := incAppClick + incAdClick
|
||||
if deltaTotal != 0 {
|
||||
inc["totalClick"] = deltaTotal
|
||||
}
|
||||
if payAmount != 0 {
|
||||
inc["payCount"] = 1
|
||||
inc["payTotal"] = payAmount
|
||||
}
|
||||
createdAt := user.CreatedAt.In(local)
|
||||
regDay := time.Date(createdAt.Year(), createdAt.Month(), createdAt.Day(), 0, 0, 0, 0, createdAt.Location())
|
||||
|
||||
update := bson.M{
|
||||
// 只在插入时写入的字段
|
||||
"$setOnInsert": bson.M{
|
||||
"userId": user.UID,
|
||||
"date": day,
|
||||
"createdAt": now,
|
||||
"districtCode": user.DistrictCode,
|
||||
"sysType": user.SysType,
|
||||
"adGroup": user.AdGroup,
|
||||
"regDay": regDay,
|
||||
"version": user.OriVer,
|
||||
},
|
||||
// 每次更新都要改的字段
|
||||
"$set": bson.M{
|
||||
"updatedAt": now,
|
||||
},
|
||||
}
|
||||
if len(inc) > 0 {
|
||||
update["$inc"] = inc
|
||||
}
|
||||
return useradverstatmod.UpsertOne(filter, update)
|
||||
}
|
||||
Reference in New Issue
Block a user