oceanEngine.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. package service
  2. import (
  3. "bytes"
  4. "context"
  5. "designs/global"
  6. "encoding/json"
  7. "go.mongodb.org/mongo-driver/v2/bson"
  8. "io"
  9. "net/http"
  10. "net/url"
  11. "time"
  12. )
  13. type EReportType string
  14. type EReportResCode = int
  15. const (
  16. ERTypeGameAddiction EReportType = "game_addiction" //关键行为
  17. ReportOk EReportResCode = 0 //上报成功
  18. ReportIOErr EReportResCode = -50
  19. Reported EReportResCode = -100 //已经上报过
  20. ReportNoNeed EReportResCode = -200 //不需要上报,一般为非广告来源用户
  21. ReportParseErr EReportResCode = -300
  22. ReportRequestErr EReportResCode = -300
  23. )
  24. // 需要核对bson的值是否与数据库中的字段一致
  25. type AdDataDetail struct {
  26. Pid string `json:"pid"`
  27. Aid string `json:"aid"`
  28. Cid string `json:"cid"`
  29. ReportUrl string `json:"reportUrl"`
  30. Reported bool `json:"reported"`
  31. Duration int64 `json:"duration"`
  32. AdReqCount uint8 `json:"adReqCount"`
  33. AdEposedcount uint8 `json:"adEposedcount"`
  34. CreateTime int `json:"createTime"`
  35. }
  36. type UserBehavior struct {
  37. Id string `bson:"_id,omitempty"`
  38. Gid string `bson:"gid"`
  39. Pf string `bson:"pf"`
  40. OpenId string `bson:"openId"`
  41. AdData *AdDataDetail `bson:"adData"`
  42. AdFromCount int `bson:"adFromCount"`
  43. TotalDuration int `bson:"totalDuration"`
  44. TotalAdReqCount int `bson:"totalAdReqCount"`
  45. TotalAdEposedCount int `bson:"totalAdEposedCount"`
  46. }
  47. // ReportResult 执行巨量引擎上报函数的返回结果的数据结构
  48. type ReportResult struct {
  49. Code int
  50. Message string
  51. }
  52. // ReportResponse 执行巨量引擎上报时请求结果的数据结构
  53. type ReportResponse struct {
  54. Code int `json:"code"`
  55. Message string `json:"message"`
  56. }
  57. // ReportData 巨量引擎上报时提交的数据结构
  58. type ReportData struct {
  59. EventType string `json:"event_type"`
  60. Context struct {
  61. Ad struct {
  62. Callback string `json:"callback"`
  63. } `json:"ad"`
  64. } `json:"context"`
  65. Timestamp int64 `json:"timestamp"`
  66. }
  67. func createReportData(evtType EReportType, clickId string) *ReportData {
  68. dat := &ReportData{}
  69. dat.EventType = string(evtType)
  70. dat.Context.Ad.Callback = clickId
  71. dat.Timestamp = time.Now().UnixMilli()
  72. return dat
  73. }
  74. func OceanReportAction(behavior string) *ReportResult {
  75. collection := global.App.MongoDB.Database("chunhao").Collection("userBehavior")
  76. //
  77. filter := bson.M{"_id": behavior}
  78. result := make(map[string]interface{})
  79. collection.FindOne(context.Background(), filter).Decode(&result)
  80. //转换成合适的格式
  81. var user UserBehavior
  82. resultString, _ := json.Marshal(result)
  83. json.Unmarshal(resultString, &user)
  84. if user.AdData.AdReqCount < 1 {
  85. //没有看过广告,无需上传
  86. return &ReportResult{Code: ReportNoNeed, Message: "没有看过广告,无需上报"}
  87. }
  88. if user.AdData == nil {
  89. //非广告来源的用户,无需上传
  90. return &ReportResult{Code: ReportNoNeed, Message: "非广告用户,无需上报"}
  91. }
  92. if user.AdData.Reported {
  93. //已经上传过了
  94. return &ReportResult{Code: Reported, Message: "已经上报过"}
  95. }
  96. //后续通过广告的不同优化目标判断不同上报行为的逻辑判断模块,暂时仅上传关键行为数据
  97. //if !specialReportType("Action", user.AdData.Pid, user.AdData.Aid) {
  98. // return false, nil
  99. //}
  100. //事件上报详见:
  101. //https://event-manager.oceanengine.com/docs/8650/app_api_docs#%E8%AF%B7%E6%B1%82%E6%96%B9%E6%B3%95
  102. //https://event-manager.oceanengine.com/docs/8650/api_docs
  103. //事件取值详见https://event-manager.oceanengine.com/docs/8650/all_events
  104. reportDat := createReportData(ERTypeGameAddiction, user.AdData.Cid)
  105. //payload, err := json.Marshal(reportDat)
  106. //if err != nil {
  107. // return &ReportResult{Code: ReportParseErr, Message: err.Error()}
  108. //}
  109. content, err := CurlPost("https://analytics.oceanengine.com/api/v2/conversion", reportDat, nil)
  110. if err != nil {
  111. return &ReportResult{Code: ReportRequestErr, Message: err.Error()}
  112. }
  113. resp := &ReportResponse{}
  114. if str2oErr := json.Unmarshal([]byte(content), resp); str2oErr != nil {
  115. return &ReportResult{Code: ReportParseErr, Message: str2oErr.Error()}
  116. }
  117. if resp.Code != 0 {
  118. return &ReportResult{Code: resp.Code, Message: resp.Message}
  119. }
  120. //数据上传后更新用户数据
  121. //更新到MongoDB 中
  122. user.AdData.Reported = true
  123. update := bson.M{
  124. "$set": struct {
  125. Gid string `bson:"gid"`
  126. Pf string `bson:"pf"`
  127. OpenId string `bson:"openId"`
  128. AdData interface{} `bson:"adData"`
  129. AdFromCount int `bson:"adFromCount"`
  130. TotalDuration int `bson:"totalDuration"`
  131. TotalAdReqCount int `bson:"totalAdReqCount"`
  132. TotalAdEposedCount int `bson:"totalAdEposedCount"`
  133. }{
  134. Gid: user.Gid,
  135. Pf: user.Pf,
  136. OpenId: user.OpenId,
  137. AdData: user.AdData,
  138. AdFromCount: user.AdFromCount,
  139. TotalDuration: user.TotalDuration,
  140. TotalAdReqCount: user.TotalAdReqCount,
  141. TotalAdEposedCount: user.TotalAdEposedCount,
  142. },
  143. }
  144. _, err = collection.UpdateOne(context.Background(), filter, update)
  145. if err != nil {
  146. return &ReportResult{Code: resp.Code, Message: err.Error()}
  147. }
  148. return &ReportResult{Code: ReportOk, Message: resp.Message}
  149. }
  150. func CurlPost(requestUrl string, requestBody interface{}, headerMap map[string]string) (string, error) {
  151. //转换json
  152. jsonBytes, err := json.Marshal(requestBody)
  153. if err != nil {
  154. return "", err
  155. }
  156. //创建请求
  157. req, err := http.NewRequest("POST", requestUrl, bytes.NewReader(jsonBytes))
  158. if err != nil {
  159. return "", err
  160. }
  161. //设置请求头
  162. req.Header.Set("Content-Type", "application/json;charset=UTF-8")
  163. for k, v := range headerMap {
  164. //req.Header.Set("Accept-Encoding", "gzip, deflate, br")
  165. req.Header.Set(k, v)
  166. }
  167. //发送请求
  168. clt := http.Client{Timeout: 30 * time.Second}
  169. res, err := clt.Do(req)
  170. if err != nil {
  171. return "", err
  172. }
  173. //获取结果
  174. body, err := io.ReadAll(res.Body)
  175. data := string(body)
  176. return data, err
  177. }
  178. // specialReportType 是否时指定上传的类型
  179. func specialReportType(reportType EReportType, pid string, aid string) bool {
  180. //通过pid和aid查找广告,判断其是否
  181. return true
  182. }
  183. func CurlGet(url string, values url.Values, header http.Header) (string, error) {
  184. req, reqErr := http.NewRequest(http.MethodGet, url, nil)
  185. if reqErr != nil {
  186. return "", reqErr
  187. }
  188. if header != nil {
  189. req.Header = header
  190. }
  191. if values != nil {
  192. req.URL.RawQuery = values.Encode()
  193. }
  194. //fmt.Println(req.URL.Host, req.URL.RawQuery)
  195. resp, resErr := http.DefaultClient.Do(req)
  196. if resErr != nil {
  197. return "", resErr
  198. }
  199. defer func() { _ = resp.Body.Close() }()
  200. content, readErr := io.ReadAll(resp.Body)
  201. if readErr != nil {
  202. return "", readErr
  203. }
  204. //if decodeErr := json.Unmarshal(content, result); decodeErr != nil {
  205. // return "", decodeErr
  206. //}
  207. return string(content), nil
  208. }
  209. type HttpResult struct {
  210. Code int `bson:"code"`
  211. Msg string `bson:"msg"`
  212. }