package com.xuqm.push.service; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import java.util.Map; import java.util.Optional; @Component public class ImPresenceClient { private final RestTemplate restTemplate = new RestTemplate(); private final ObjectMapper objectMapper; @Value("${push.im-service-base-url:http://im-service:8082}") private String imServiceBaseUrl; @Value("${push.internal-token:xuqm-internal-token}") private String internalToken; public ImPresenceClient(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } public Optional resolveToken(String token) { try { HttpHeaders headers = internalHeaders(); HttpEntity request = new HttpEntity<>( objectMapper.writeValueAsString(Map.of("token", token)), headers); String body = restTemplate.postForObject( imServiceBaseUrl + "/api/im/internal/presence/resolve-token", request, String.class); return parse(body); } catch (Exception ignored) { return Optional.empty(); } } public Optional userStatus(String appId, String userId) { try { HttpHeaders headers = internalHeaders(); HttpEntity request = new HttpEntity<>(headers); String uri = UriComponentsBuilder.fromHttpUrl(imServiceBaseUrl + "/api/im/internal/presence/users/{userId}") .queryParam("appId", appId) .build(userId) .toString(); String body = restTemplate.exchange( uri, org.springframework.http.HttpMethod.GET, request, String.class).getBody(); return parse(body); } catch (Exception ignored) { return Optional.empty(); } } private HttpHeaders internalHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("X-Internal-Token", internalToken); return headers; } private Optional parse(String body) throws Exception { if (body == null || body.isBlank()) { return Optional.empty(); } JsonNode data = objectMapper.readTree(body).path("data"); if (data.isMissingNode() || data.isNull()) { return Optional.empty(); } return Optional.of(new PresenceStatus( data.path("appId").asText(null), data.path("userId").asText(null), data.path("online").asBoolean(false), data.path("lastSeenAt").asLong(0L))); } public record PresenceStatus(String appId, String userId, boolean online, long lastSeenAt) {} }