ecpm.go 6.9 KB

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