aboutsummaryrefslogtreecommitdiff
path: root/juick-notifications/src/main/java/com/juick/components/MPNSManager.java
diff options
context:
space:
mode:
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.java163
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) {
+
+ }
+}