| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- package com.adx.tencent.vivo.service;
- import com.adx.tencent.vivo.model.VivoAdvertiserAccountRecord;
- import com.adx.tencent.vivo.model.VivoTokenRecord;
- import com.adx.tencent.vivo.store.VivoColdStore;
- import com.fasterxml.jackson.databind.JsonNode;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.net.URI;
- import java.net.URLEncoder;
- import java.net.http.HttpClient;
- import java.net.http.HttpRequest;
- import java.net.http.HttpResponse;
- import java.nio.charset.StandardCharsets;
- import java.time.Duration;
- import java.time.Instant;
- import java.util.ArrayList;
- import java.util.LinkedHashMap;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.UUID;
- import java.util.stream.Collectors;
- public class VivoAdvertiserSyncService {
- private static final Logger log = LoggerFactory.getLogger(VivoAdvertiserSyncService.class);
- private static final String ADVERTISER_QUERY_PATH = "/openapi/v1/account/advertiser/query";
- private static final int PAGE_SIZE = 100;
- private final String baseUrl;
- private final VivoAuthService authService;
- private final VivoColdStore coldStore;
- private final ObjectMapper objectMapper;
- private final HttpClient httpClient;
- public VivoAdvertiserSyncService(String baseUrl,
- VivoAuthService authService,
- VivoColdStore coldStore,
- ObjectMapper objectMapper) {
- this.baseUrl = trimTrailingSlash(baseUrl);
- this.authService = authService;
- this.coldStore = coldStore;
- this.objectMapper = objectMapper;
- this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
- }
- public void syncAllAuthorizedAccounts() {
- List<VivoTokenRecord> tokens = authService.listAuthorizedSecondaryAccounts();
- if (tokens == null || tokens.isEmpty()) {
- return;
- }
- for (VivoTokenRecord token : tokens) {
- if (token == null || token.getAccountId() == null || token.getAccountId().isBlank()) {
- continue;
- }
- syncSecondaryAccount(token.getAccountId().trim());
- }
- }
- public void syncSecondaryAccount(String secondaryAccountId) {
- if (secondaryAccountId == null || secondaryAccountId.isBlank()) {
- return;
- }
- String accessToken = authService.getAccessTokenBySecondaryAccountId(secondaryAccountId);
- List<VivoAdvertiserAccountRecord> fetched = queryAllAdvertisers(secondaryAccountId, accessToken);
- List<String> staleAdvertiserIds = new ArrayList<>(coldStore.listAdvertiserIdsBySecondaryAccountId(secondaryAccountId));
- Set<String> freshIds = fetched.stream()
- .map(VivoAdvertiserAccountRecord::getAdvertiserId)
- .filter(id -> id != null && !id.isBlank())
- .collect(Collectors.toCollection(LinkedHashSet::new));
- staleAdvertiserIds.removeIf(freshIds::contains);
- coldStore.replaceAdvertiserAccounts(secondaryAccountId, fetched);
- authService.cacheAdvertiserMappings(fetched);
- authService.evictAdvertiserMappings(staleAdvertiserIds);
- log.info("[Vivo][广告主同步] secondaryAccountId={} count={} staleCount={}",
- secondaryAccountId, fetched.size(), staleAdvertiserIds.size());
- }
- private List<VivoAdvertiserAccountRecord> queryAllAdvertisers(String secondaryAccountId, String accessToken) {
- List<VivoAdvertiserAccountRecord> result = new ArrayList<>();
- int pageIndex = 1;
- int pageCount = 1;
- while (pageIndex <= pageCount) {
- PageResult page = queryAdvertiserPage(accessToken, pageIndex);
- pageCount = Math.max(page.pageCount, 1);
- if (page.records != null) {
- result.addAll(page.records);
- }
- if (page.records == null || page.records.isEmpty()) {
- break;
- }
- pageIndex++;
- }
- Instant now = Instant.now();
- for (VivoAdvertiserAccountRecord record : result) {
- record.setSecondaryAccountId(secondaryAccountId);
- if (record.getLastSyncAt() == null) {
- record.setLastSyncAt(now);
- }
- if (record.getUpdatedAt() == null) {
- record.setUpdatedAt(now);
- }
- }
- return result;
- }
- private PageResult queryAdvertiserPage(String accessToken, int pageIndex) {
- try {
- long timestamp = System.currentTimeMillis();
- String nonce = UUID.randomUUID().toString().replace("-", "");
- String url = baseUrl + ADVERTISER_QUERY_PATH + "?" + toQuery(Map.of(
- "access_token", accessToken,
- "timestamp", String.valueOf(timestamp),
- "nonce", nonce
- ));
- String body = objectMapper.writeValueAsString(Map.of("pageIndex", pageIndex, "pageSize", PAGE_SIZE));
- HttpRequest request = HttpRequest.newBuilder()
- .uri(URI.create(url))
- .header("Content-Type", "application/json")
- .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
- .timeout(Duration.ofSeconds(15))
- .build();
- HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
- if (response.statusCode() < 200 || response.statusCode() >= 300) {
- throw new IllegalStateException("HTTP status: " + response.statusCode() + ", body=" + response.body());
- }
- JsonNode root = objectMapper.readTree(response.body());
- int code = root.path("code").asInt(Integer.MIN_VALUE);
- if (code != 0) {
- throw new IllegalStateException("code=" + code + ", message=" + root.path("message").asText() + ", body=" + response.body());
- }
- JsonNode data = root.path("data");
- JsonNode pageInfo = data.path("pageInfo");
- int pageCount = pageInfo.path("pageCount").asInt(1);
- List<VivoAdvertiserAccountRecord> records = new ArrayList<>();
- JsonNode list = data.path("list");
- if (list.isArray()) {
- Instant now = Instant.now();
- for (JsonNode item : list) {
- String advertiserId = text(item, "uuid");
- if (advertiserId == null || advertiserId.isBlank()) {
- continue;
- }
- VivoAdvertiserAccountRecord record = new VivoAdvertiserAccountRecord();
- record.setAdvertiserId(advertiserId);
- record.setAdvertiserName(text(item, "name"));
- record.setAdvertiserStatus(asInt(item.get("status")));
- record.setLastSyncAt(now);
- record.setUpdatedAt(now);
- records.add(record);
- }
- }
- PageResult pageResult = new PageResult();
- pageResult.pageCount = pageCount;
- pageResult.records = records;
- return pageResult;
- } catch (Exception e) {
- throw new RuntimeException("sync vivo advertiser page failed: " + e.getMessage(), e);
- }
- }
- private static String toQuery(Map<String, String> params) {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (Map.Entry<String, String> entry : params.entrySet()) {
- if (entry.getValue() == null || entry.getValue().isBlank()) continue;
- if (!first) sb.append('&');
- first = false;
- sb.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
- .append('=')
- .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
- }
- return sb.toString();
- }
- private static String text(JsonNode node, String field) {
- JsonNode child = node == null ? null : node.get(field);
- if (child == null || child.isNull()) {
- return null;
- }
- String value = child.asText();
- return value == null || value.isBlank() ? null : value.trim();
- }
- private static Integer asInt(JsonNode node) {
- if (node == null || node.isNull()) {
- return null;
- }
- if (node.isInt() || node.isLong()) {
- return node.intValue();
- }
- try {
- return Integer.parseInt(node.asText().trim());
- } catch (Exception e) {
- return null;
- }
- }
- private static String trimTrailingSlash(String value) {
- if (value == null || value.isBlank()) {
- return "https://marketing-api.vivo.com.cn";
- }
- String result = value.trim();
- while (result.endsWith("/")) {
- result = result.substring(0, result.length() - 1);
- }
- return result;
- }
- private static class PageResult {
- private int pageCount;
- private List<VivoAdvertiserAccountRecord> records;
- }
- }
|