ecpm.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package crons
  2. import (
  3. "context"
  4. "designs/config"
  5. "designs/global"
  6. "designs/service"
  7. "encoding/json"
  8. "fmt"
  9. "github.com/pkg/errors"
  10. "net/http"
  11. "net/url"
  12. "strconv"
  13. "time"
  14. )
  15. func SetEcpm() {
  16. //读取所有游戏
  17. gidKey := config.Get("app.gid") + "*"
  18. keys, _ := global.App.Redis.Keys(context.Background(), gidKey).Result()
  19. for _, gid := range keys {
  20. err := Ecpm(gid)
  21. if err != nil {
  22. global.App.Log.Error("Set "+gid+" Ecpm error:", err)
  23. } else {
  24. global.App.Log.Info("Set " + gid + " Ecpm success")
  25. }
  26. }
  27. ////先只统计linkup的
  28. //err := Ecpm("linkup")
  29. //if err != nil {
  30. // global.App.Log.Error("Ecpm error", err)
  31. //}
  32. //global.App.Log.Info("ser Ecpm success")
  33. }
  34. func GetAccessToken(gid string, ttAppid string, ttSecret string) (string, error) {
  35. tokenKey := gid + "||" + "ttToken"
  36. AccessToken := global.App.Redis.Get(context.Background(), tokenKey).Val()
  37. if AccessToken == "" {
  38. reportDat := map[string]string{
  39. "appid": ttAppid,
  40. "secret": ttSecret,
  41. "grant_type": "client_credential",
  42. }
  43. //请求接口获取token
  44. content, err := service.CurlPost("https://minigame.zijieapi.com/mgplatform/api/apps/v2/token", reportDat, nil)
  45. if err != nil {
  46. return "", err
  47. }
  48. var resp struct {
  49. Data struct {
  50. AccessToken string `json:"access_token"`
  51. ExpiresIn int `json:"expires_in"`
  52. ExpiresAt int `json:"expiresAt"`
  53. } `json:"data"`
  54. ErrTips string `json:"err_tips"`
  55. ErrNo int `json:"err_no"`
  56. }
  57. str2oErr := json.Unmarshal([]byte(content), &resp)
  58. if str2oErr != nil {
  59. return "", err
  60. }
  61. if resp.ErrNo != 0 {
  62. return "", errors.New(resp.ErrTips)
  63. }
  64. AccessToken = resp.Data.AccessToken
  65. global.App.Redis.Set(context.Background(), tokenKey, AccessToken, time.Second*30)
  66. }
  67. return AccessToken, nil
  68. }
  69. type UserJoinSeeAds struct {
  70. ID int `json:"id" gorm:"not null;"`
  71. Pf string `json:"pf" gorm:"not null;"`
  72. Gid string `json:"gid" gorm:"not null;"`
  73. UserId int `json:"userId" gorm:"not null;column:userId;"`
  74. OpenId string `json:"openId" gorm:"not null;column:openId;"`
  75. Date string `json:"date" gorm:"not null;"`
  76. CreatedAt time.Time `json:"createdAt" gorm:"column:createdAt;"`
  77. StartTime time.Time `json:"startTime" gorm:"column:startTime;"`
  78. AdsId string `json:"adsId" gorm:"not null;column:adsId;"`
  79. AdsType string `json:"adsType" gorm:"not null;column:adsType;"`
  80. AdsScene string `json:"adsScene" gorm:"not null;column:adsScene;"`
  81. AdsState int `json:"adsState" gorm:"not null;column:adsState;"`
  82. }
  83. func Ecpm(gid string) error {
  84. res, _ := global.App.Redis.HGetAll(context.Background(), gid).Result()
  85. if len(res["ttAppid"]) == 0 || len(res["ttSecret"]) == 0 {
  86. return errors.New("ttAppid/ttSecret is empty")
  87. }
  88. //获取和存储accessToken
  89. accessToken, err := GetAccessToken(gid, res["ttAppid"], res["ttSecret"])
  90. if err != nil {
  91. return err
  92. }
  93. //请求获取结果
  94. dateHour := time.Now().AddDate(0, 0, 0).Format("2006-01-02")
  95. ecpmRes, err := GetEcpm(res["ttAppid"], accessToken, dateHour)
  96. if err != nil {
  97. return err
  98. }
  99. //ecpm没数据的话,就不需要往后走
  100. if ecpmRes.Data.Total == 0 {
  101. global.App.Log.Info(fmt.Sprintf("%s 没有需要写入的ecpm数据", gid))
  102. return nil
  103. }
  104. //查询出当日的所有数据
  105. gid = gid[4:]
  106. var userSeeAds []UserJoinSeeAds
  107. err = global.App.DB.Table("user_see_ads").
  108. LeftJoin("user", "user.userId = user_see_ads.userId and user.gid = user_see_ads.gid").
  109. Where("user_see_ads.createdAt", ">=", dateHour).
  110. Select("user_see_ads.*", "user.openId").
  111. Where("user_see_ads.gid", gid).
  112. Where("user_see_ads.pf", "tt").
  113. Order("user_see_ads.createdAt asc").
  114. Scan(&userSeeAds).Error
  115. if err != nil {
  116. return err
  117. }
  118. //按照openId 分组
  119. userSeeAdsMap := make(map[string][]UserJoinSeeAds)
  120. for _, userSeeAd := range userSeeAds {
  121. userSeeAdsMap[userSeeAd.OpenId] = append(userSeeAdsMap[userSeeAd.OpenId], userSeeAd)
  122. }
  123. ecpmMap := make(map[string][]EcpmItem)
  124. for _, record := range ecpmRes.Data.Records {
  125. ecpmMap[record.OpenId] = append(ecpmMap[record.OpenId], record)
  126. }
  127. for k, item := range ecpmMap {
  128. //跳过数据对不上的
  129. if len(userSeeAdsMap[k]) == 0 {
  130. continue
  131. }
  132. pf := userSeeAdsMap[k][0].Pf
  133. openId := userSeeAdsMap[k][0].OpenId
  134. userId := userSeeAdsMap[k][0].UserId
  135. for key, v := range item {
  136. ecpmData := struct {
  137. Id int `json:"id" gorm:"not null;"`
  138. }{}
  139. global.App.DB.Table("ecpm_data").Where("ecmpId", v.Id).Select("id").First(&ecpmData)
  140. if ecpmData.Id == 0 {
  141. err = global.App.DB.Table("ecpm_data").Create(map[string]interface{}{
  142. "gid": gid,
  143. "pf": pf,
  144. "openId": openId,
  145. "cost": v.Cost,
  146. "userId": userId,
  147. "ecmpId": v.Id,
  148. "createdAt": v.EventTime,
  149. }).Error
  150. if err != nil {
  151. return err
  152. }
  153. }
  154. //关联到看广告表中
  155. if key < len(userSeeAdsMap[k]) {
  156. err = global.App.DB.Table("user_see_ads").Where("id", userSeeAdsMap[k][key].ID).Update("cost", v.Cost).Error
  157. if err != nil {
  158. global.App.Log.Error("id:"+strconv.Itoa(userSeeAdsMap[k][key].ID)+"user_see_ads update cost err:", err.Error())
  159. return err
  160. }
  161. }
  162. }
  163. }
  164. return nil
  165. }
  166. type EcpmItem struct {
  167. Aid string `json:"aid"`
  168. Cost int `json:"cost"`
  169. Did string `json:"did"`
  170. EventName string `json:"event_name"`
  171. EventTime string `json:"event_time"`
  172. OpenId string `json:"open_id"`
  173. Id int `json:"id"`
  174. }
  175. type Result struct {
  176. ErrMsg string `json:"err_msg"`
  177. ErrNo int `json:"err_no"`
  178. LogId string `json:"log_id"`
  179. Data struct {
  180. Total int `json:"total"`
  181. Records []EcpmItem `json:"records"`
  182. } `json:"data"`
  183. }
  184. // GetEcpm 获取用户的ecpm值,用于巨量引擎下小游戏的关键行为转化指标
  185. func GetEcpm(appId string, accessToken string, dateHour string) (*Result, error) {
  186. pageNo := 0
  187. pageSize := 100
  188. var resData Result
  189. header := http.Header{
  190. "Content-type": []string{"application/json"},
  191. }
  192. for {
  193. pageNo++
  194. params := url.Values{
  195. "access_token": {accessToken},
  196. "mp_id": {appId},
  197. "date_hour": {dateHour},
  198. "page_no": {strconv.Itoa(pageNo)},
  199. "page_size": {strconv.Itoa(pageSize)},
  200. }
  201. res, err := service.CurlGet("https://minigame.zijieapi.com/mgplatform/api/apps/data/get_ecpm", params, header)
  202. if err != nil {
  203. return nil, err
  204. }
  205. var resp Result
  206. err = json.Unmarshal([]byte(res), &resp)
  207. if err != nil {
  208. return nil, err
  209. }
  210. resData.Data.Records = append(resData.Data.Records, resp.Data.Records...)
  211. resData.Data.Total = resp.Data.Total
  212. //当获取到所有数据的时候,停止获取数据
  213. if pageNo*pageSize >= resp.Data.Total {
  214. break
  215. }
  216. }
  217. return &resData, nil
  218. }