HonorClient.java 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package com.adx.tencent.honor;
  2. import com.adx.tencent.baidu.model.PaymentInfo;
  3. import com.adx.tencent.honor.model.HonorBidRecord;
  4. import com.adx.tencent.honor.model.HonorMediaCallbackRecord;
  5. import com.fasterxml.jackson.databind.ObjectMapper;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import java.net.URI;
  9. import java.net.URLEncoder;
  10. import java.net.http.HttpClient;
  11. import java.net.http.HttpRequest;
  12. import java.net.http.HttpResponse;
  13. import java.nio.charset.StandardCharsets;
  14. import java.time.Duration;
  15. import java.time.Instant;
  16. import java.util.LinkedHashMap;
  17. import java.util.Locale;
  18. import java.util.Map;
  19. public class HonorClient {
  20. private static final Logger log = LoggerFactory.getLogger(HonorClient.class);
  21. private static final String FIXED_CHANNEL_ID = "9";
  22. private final String baseUrl;
  23. private final ObjectMapper objectMapper;
  24. private final HttpClient httpClient;
  25. public HonorClient(String baseUrl, String channelId, ObjectMapper objectMapper) {
  26. this.baseUrl = (baseUrl == null || baseUrl.isBlank())
  27. ? "https://ads-drcn.platform.hihonorcloud.com"
  28. : baseUrl.replaceAll("/+$", "");
  29. this.objectMapper = objectMapper;
  30. this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
  31. }
  32. public HonorMediaCallbackRecord sendConversion(HonorBidRecord bid, PaymentInfo payment, int conversionId) {
  33. HonorMediaCallbackRecord record = new HonorMediaCallbackRecord();
  34. record.setQk(payment.getQk());
  35. record.setTagId(bid.getTagId());
  36. record.setEventType(payment.getAct());
  37. record.setPurchase(payment.getPayment());
  38. record.setAttempt(1);
  39. record.setCreatedAt(Instant.now());
  40. Map<String, String> params = buildParams(bid, payment, conversionId);
  41. String callbackUrl = baseUrl + "/api/ad-tracking/v1/conversion?" + toQuery(params);
  42. record.setCallbackUrl(callbackUrl);
  43. record.setRequestBody(toJson(params));
  44. record.setEventTimeMs(Long.parseLong(params.get("conversionTime")));
  45. try {
  46. HttpRequest request = HttpRequest.newBuilder()
  47. .uri(URI.create(callbackUrl))
  48. .GET()
  49. .timeout(Duration.ofSeconds(15))
  50. .build();
  51. HttpResponse<byte[]> response = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
  52. String body = new String(response.body(), StandardCharsets.UTF_8);
  53. record.setStatus(response.statusCode());
  54. record.setResponseBody(body);
  55. record.setOk(response.statusCode() >= 200 && response.statusCode() < 300);
  56. if (!record.isOk()) {
  57. record.setErrorMessage("HTTP status: " + response.statusCode());
  58. }
  59. log.info("[Honor] callback结果: qk={}, tagId={}, conversionId={}, status={}, ok={}, response={}",
  60. payment.getQk(), bid.getTagId(), conversionId, response.statusCode(), record.isOk(), body);
  61. } catch (Exception e) {
  62. record.setOk(false);
  63. record.setErrorMessage(e.getMessage());
  64. log.warn("[Honor] callback失败: qk={}, tagId={}, conversionId={}, error={}",
  65. payment.getQk(), bid.getTagId(), conversionId, e.getMessage());
  66. }
  67. return record;
  68. }
  69. public HonorMediaCallbackRecord retryCallback(HonorMediaCallbackRecord original) throws Exception {
  70. HonorMediaCallbackRecord retry = copy(original);
  71. retry.setAttempt(original.getAttempt() + 1);
  72. retry.setCreatedAt(Instant.now());
  73. HttpRequest request = HttpRequest.newBuilder()
  74. .uri(URI.create(original.getCallbackUrl()))
  75. .GET()
  76. .timeout(Duration.ofSeconds(15))
  77. .build();
  78. HttpResponse<byte[]> response = httpClient.send(request, HttpResponse.BodyHandlers.ofByteArray());
  79. retry.setStatus(response.statusCode());
  80. retry.setResponseBody(new String(response.body(), StandardCharsets.UTF_8));
  81. retry.setOk(response.statusCode() >= 200 && response.statusCode() < 300);
  82. if (!retry.isOk()) retry.setErrorMessage("HTTP status: " + response.statusCode());
  83. return retry;
  84. }
  85. private Map<String, String> buildParams(HonorBidRecord bid, PaymentInfo payment, int conversionId) {
  86. Map<String, String> mediaParams = bid.getMediaParams();
  87. long monitorTime = parseLong(mediaParams, "eventTime");
  88. long conversionTime = Math.max(Instant.now().toEpochMilli(), monitorTime + 1);
  89. Map<String, String> params = new LinkedHashMap<>();
  90. put(params, "trackId", value(mediaParams, "trackId"));
  91. params.put("conversionId", String.valueOf(conversionId));
  92. params.put("conversionTime", String.valueOf(conversionTime));
  93. put(params, "advertiserId", value(mediaParams, "advertiserId"));
  94. put(params, "oaid", value(mediaParams, "oaid"));
  95. params.put("id_type", "0");
  96. params.put("channelId", FIXED_CHANNEL_ID);
  97. put(params, "pkgName", firstNonBlank(value(mediaParams, "pkgName"), bid.getPackageName()));
  98. put(params, "extra", urlEncode("{\"tagId\":\"" + bid.getTagId() + "\"}"));
  99. if (conversionId == 10004) {
  100. params.put("payAmount", String.format(Locale.ROOT, "%.2f",
  101. payment.getGmv() > 0 ? payment.getGmv() : payment.getPayment()));
  102. put(params, "orderId", buildOrderId(payment));
  103. }
  104. return params;
  105. }
  106. private static HonorMediaCallbackRecord copy(HonorMediaCallbackRecord src) {
  107. HonorMediaCallbackRecord copy = new HonorMediaCallbackRecord();
  108. copy.setDedupeKey(src.getDedupeKey());
  109. copy.setQk(src.getQk());
  110. copy.setTagId(src.getTagId());
  111. copy.setCallbackUrl(src.getCallbackUrl());
  112. copy.setEventType(src.getEventType());
  113. copy.setEventTimeMs(src.getEventTimeMs());
  114. copy.setPurchase(src.getPurchase());
  115. copy.setStatus(src.getStatus());
  116. copy.setOk(src.isOk());
  117. copy.setAttempt(src.getAttempt());
  118. copy.setResponseBody(src.getResponseBody());
  119. copy.setErrorMessage(src.getErrorMessage());
  120. copy.setRequestBody(src.getRequestBody());
  121. copy.setCreatedAt(src.getCreatedAt());
  122. return copy;
  123. }
  124. private String toJson(Object value) {
  125. try {
  126. return objectMapper.writeValueAsString(value);
  127. } catch (Exception e) {
  128. return String.valueOf(value);
  129. }
  130. }
  131. private static String toQuery(Map<String, String> params) {
  132. StringBuilder sb = new StringBuilder();
  133. boolean first = true;
  134. for (Map.Entry<String, String> entry : params.entrySet()) {
  135. if (entry.getValue() == null || entry.getValue().isBlank()) continue;
  136. if (!first) sb.append('&');
  137. first = false;
  138. sb.append(urlEncode(entry.getKey())).append('=').append(urlEncode(entry.getValue()));
  139. }
  140. return sb.toString();
  141. }
  142. private static String urlEncode(String value) {
  143. return URLEncoder.encode(value, StandardCharsets.UTF_8);
  144. }
  145. private static void put(Map<String, String> params, String key, String value) {
  146. if (value != null && !value.isBlank()) params.put(key, value);
  147. }
  148. private static String value(Map<String, String> params, String key) {
  149. return params != null ? params.get(key) : null;
  150. }
  151. private static long parseLong(Map<String, String> params, String key) {
  152. try {
  153. return Long.parseLong(value(params, key));
  154. } catch (Exception e) {
  155. return 0L;
  156. }
  157. }
  158. private static String firstNonBlank(String... values) {
  159. for (String value : values) {
  160. if (value != null && !value.isBlank()) return value;
  161. }
  162. return null;
  163. }
  164. private static String buildOrderId(PaymentInfo payment) {
  165. String raw = (payment.getTu() != null ? payment.getTu() : "")
  166. + "_" + (payment.getQk() != null ? payment.getQk() : "")
  167. + "_" + payment.getAct();
  168. return raw.length() <= 64 ? raw : raw.substring(0, 64);
  169. }
  170. }