diff options
author | Vitaly Takmazov | 2018-09-25 12:49:57 +0300 |
---|---|---|
committer | Vitaly Takmazov | 2018-09-25 12:49:57 +0300 |
commit | 15753b2ebdac2ab49cf5682c417851a0653e136e (patch) | |
tree | 81efc43348a820a1c647779f78264bce10103b59 /juick-notifications/src/main/java/com/juick/components/MPNSManager.java | |
parent | ae76024011a8442ae7eab953e0b97e9fe2c7c201 (diff) |
notifications server refactoring
Diffstat (limited to 'juick-notifications/src/main/java/com/juick/components/MPNSManager.java')
-rw-r--r-- | juick-notifications/src/main/java/com/juick/components/MPNSManager.java | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/juick-notifications/src/main/java/com/juick/components/MPNSManager.java b/juick-notifications/src/main/java/com/juick/components/MPNSManager.java new file mode 100644 index 00000000..56c2df8d --- /dev/null +++ b/juick-notifications/src/main/java/com/juick/components/MPNSManager.java @@ -0,0 +1,163 @@ +package com.juick.components; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.juick.ExternalToken; +import com.juick.User; +import com.juick.components.mpns.MPNSError; +import com.juick.components.mpns.MPNSToken; +import com.juick.service.component.*; +import com.juick.util.MessageUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.*; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Created by vital on 29.03.2017. + */ +public class MPNSManager implements NotificationListener { + + private static Logger logger = LoggerFactory.getLogger(MPNSManager.class); + + private String accessToken; + + @Inject + private ObjectMapper jsonMapper; + @Value("${wns_application_sip:}") + private String applicationSip; + @Value("${wns_client_secret:}") + private String applicationSecret; + private RestTemplate wnsService; + + @Inject + private NotificationsManager notificationsManager; + + @PostConstruct + public void authenticate() throws IOException { + String url = "https://login.live.com/accesstoken.srf"; + MultiValueMap<String, String> form = new LinkedMultiValueMap<>(); + form.add("grant_type", "client_credentials"); + form.add("client_id", applicationSip); + form.add("client_secret", applicationSecret); + form.add("scope", "notify.windows.com"); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + wnsService = new RestTemplate(); + wnsService.getMessageConverters().add(new StringHttpMessageConverter(StandardCharsets.UTF_8)); + HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(form, httpHeaders); + ResponseEntity<String> response = wnsService.exchange(url, HttpMethod.POST, entity, String.class); + String responseBody = response.getBody(); + HttpStatus statusCode = response.getStatusCode(); + if (statusCode != HttpStatus.OK) { + MPNSError error = jsonMapper.readValue(responseBody, MPNSError.class); + throw new IOException(error.getError() + ": " + error.getErrorDescription()); + } + MPNSToken token = jsonMapper.readValue(responseBody, MPNSToken.class); + if (token.getTokenType().length() >= 1) { + token.setTokenType(Character.toUpperCase(token.getTokenType().charAt(0)) + token.getTokenType().substring(1)); + } + accessToken = token.getTokenType() + " " + token.getAccessToken(); + logger.info("MPNS authenticated"); + } + + void sendNotification(final String url, final String xml) throws IOException { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(new MediaType("text", "xml", StandardCharsets.UTF_8)); + httpHeaders.set("Authorization", accessToken); + httpHeaders.set("X-WNS-Type", "wns/toast"); + HttpEntity<String> requestEntity = new HttpEntity<>(xml, httpHeaders); + try { + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url); + wnsService.exchange(builder.build(true).toUri(), HttpMethod.POST, requestEntity, Void.class); + } catch (HttpClientErrorException ex) { + HttpStatus statusCode = ex.getStatusCode(); + if (statusCode == HttpStatus.GONE) { + // expired + logger.info("{} is scheduled to remove", url); + notificationsManager.addInvalidMPNSToken(url); + } else { + String headersContent = ex.getResponseHeaders().entrySet().stream() + .filter(x -> x.getKey().startsWith("X-WNS-") || x.getKey().startsWith("WWW-")) + .map(x -> x.getKey() + ": " + String.join(",", x.getValue())) + .collect(Collectors.joining("\n")); + throw new IOException(headersContent); + } + } + } + + @Override + public void processMessageEvent(MessageEvent messageEvent) { + com.juick.Message jmsg = messageEvent.getMessage(); + List<User> users = messageEvent.getUsers(); + + List<String> urls = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("mpns")) + .map(ExternalToken::getToken).collect(Collectors.toList()); + + if (urls.isEmpty()) { + logger.info("WNS: no recipients"); + } else { + try { + String text1 = "@" + jmsg.getUser().getName(); + if (!jmsg.getTags().isEmpty()) { + text1 += ":" + StringEscapeUtils.escapeXml11(MessageUtils.getTagsString(jmsg)); + } + String text2 = StringEscapeUtils.escapeXml11(StringUtils.defaultString(jmsg.getText())); + String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + + "<toast>" + + "<visual>" + + "<binding template=\"ToastImageAndText02\">" + + "<image id=\"1\" src=\"http://i.juick.com/as/" + jmsg.getUser().getUid() + ".png\" />" + + "<text id=\"1\">" + text1 + "</text>" + + "<text id=\"2\">" + text2 + "</text>" + + "</binding>" + + "</visual>" + + "<commands>" + + "<command arguments=\"/ThreadView.xaml?mid=" + jmsg.getMid() + "\" />" + + "</commands>" + + "</toast>"; + logger.trace(xml); + for (String url : urls) { + logger.info("WNS: {}", url); + sendNotification(url, xml); + } + } catch (IOException | IllegalStateException ex) { + logger.error("WNS: ", ex); + } + } + } + + @Override + public void processSubscribeEvent(SubscribeEvent subscribeEvent) { + + } + + @Override + public void processLikeEvent(LikeEvent likeEvent) { + + } + + @Override + public void processPingEvent(PingEvent pingEvent) { + + } + + @Override + public void processMessageReadEvent(MessageReadEvent messageReadEvent) { + + } +} |