aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2018-09-25 12:49:57 +0300
committerGravatar Vitaly Takmazov2018-09-25 12:49:57 +0300
commit15753b2ebdac2ab49cf5682c417851a0653e136e (patch)
tree81efc43348a820a1c647779f78264bce10103b59
parentae76024011a8442ae7eab953e0b97e9fe2c7c201 (diff)
notifications server refactoring
-rw-r--r--juick-common/src/main/java/com/juick/service/component/MessageReadEvent.java12
-rw-r--r--juick-common/src/main/java/com/juick/service/component/NotificationListener.java (renamed from juick-server/src/main/java/com/juick/server/NotificationListener.java)3
-rw-r--r--juick-notifications/build.gradle5
-rw-r--r--juick-notifications/src/main/java/com/juick/components/APNSManager.java140
-rw-r--r--juick-notifications/src/main/java/com/juick/components/FirebaseManager.java90
-rw-r--r--juick-notifications/src/main/java/com/juick/components/MPNSManager.java (renamed from juick-notifications/src/main/java/com/juick/components/MPNSClient.java)79
-rw-r--r--juick-notifications/src/main/java/com/juick/components/NotificationClientListener.java8
-rw-r--r--juick-notifications/src/main/java/com/juick/components/NotificationsManager.java (renamed from juick-notifications/src/main/java/com/juick/components/Notifications.java)172
-rw-r--r--juick-notifications/src/main/java/com/juick/components/configuration/APNSConfiguration.java26
-rw-r--r--juick-notifications/src/main/java/com/juick/components/configuration/GCMConfiguration.java12
-rw-r--r--juick-notifications/src/main/java/com/juick/components/configuration/JuickServerWebsocketConfiguration.java7
-rw-r--r--juick-notifications/src/main/java/com/juick/components/configuration/MPNSConfiguration.java8
12 files changed, 334 insertions, 228 deletions
diff --git a/juick-common/src/main/java/com/juick/service/component/MessageReadEvent.java b/juick-common/src/main/java/com/juick/service/component/MessageReadEvent.java
index 82cfadd5..b314b89b 100644
--- a/juick-common/src/main/java/com/juick/service/component/MessageReadEvent.java
+++ b/juick-common/src/main/java/com/juick/service/component/MessageReadEvent.java
@@ -4,22 +4,24 @@ import com.juick.Message;
import com.juick.User;
import org.springframework.context.ApplicationEvent;
+import java.util.List;
+
public class MessageReadEvent extends ApplicationEvent {
- private User user;
+ private List<User> users;
private Message message;
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
- public MessageReadEvent(Object source, User user, Message message) {
+ public MessageReadEvent(Object source, List<User> users, Message message) {
super(source);
- this.user = user;
+ this.users = users;
this.message = message;
}
- public User getUser() {
- return user;
+ public List<User> getUsers() {
+ return users;
}
public Message getMessage() {
diff --git a/juick-server/src/main/java/com/juick/server/NotificationListener.java b/juick-common/src/main/java/com/juick/service/component/NotificationListener.java
index 750c8b18..e4ccb13b 100644
--- a/juick-server/src/main/java/com/juick/server/NotificationListener.java
+++ b/juick-common/src/main/java/com/juick/service/component/NotificationListener.java
@@ -1,6 +1,5 @@
-package com.juick.server;
+package com.juick.service.component;
-import com.juick.service.component.*;
import org.springframework.context.event.EventListener;
public interface NotificationListener {
diff --git a/juick-notifications/build.gradle b/juick-notifications/build.gradle
index b5b7bd89..203931ee 100644
--- a/juick-notifications/build.gradle
+++ b/juick-notifications/build.gradle
@@ -3,10 +3,7 @@ apply plugin: 'org.springframework.boot'
dependencies {
compile project(':juick-common')
- compile("org.springframework.boot:spring-boot-starter-websocket") {
- exclude module: "spring-boot-starter-tomcat"
- exclude module: "spring-boot-starter-web"
- }
+ compile("org.springframework.boot:spring-boot-starter-websocket")
compile 'com.ganyo:gcm-server:1.1.0'
compile 'com.turo:pushy:0.13.4'
}
diff --git a/juick-notifications/src/main/java/com/juick/components/APNSManager.java b/juick-notifications/src/main/java/com/juick/components/APNSManager.java
new file mode 100644
index 00000000..c0380847
--- /dev/null
+++ b/juick-notifications/src/main/java/com/juick/components/APNSManager.java
@@ -0,0 +1,140 @@
+package com.juick.components;
+
+import com.juick.ExternalToken;
+import com.juick.User;
+import com.juick.formatters.PlainTextFormatter;
+import com.juick.service.component.*;
+import com.turo.pushy.apns.ApnsClient;
+import com.turo.pushy.apns.ApnsClientBuilder;
+import com.turo.pushy.apns.PushNotificationResponse;
+import com.turo.pushy.apns.auth.ApnsSigningKey;
+import com.turo.pushy.apns.util.ApnsPayloadBuilder;
+import com.turo.pushy.apns.util.SimpleApnsPushNotification;
+import com.turo.pushy.apns.util.concurrent.PushNotificationResponseListener;
+import io.netty.util.concurrent.Future;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+public class APNSManager implements NotificationListener {
+ private static Logger logger = LoggerFactory.getLogger(APNSManager.class);
+
+ private ApnsClient apns;
+ @Value("${ios_p8_key:}")
+ private String p8key;
+ @Value("${ios_app_id:}")
+ private String topic;
+ @Value("${ios_team_id:}")
+ private String teamId;
+ @Value("${ios_key_id:}")
+ private String keyId;
+ @Inject
+ private NotificationsManager notificationsManager;
+ @PostConstruct
+ public void initialize() throws NoSuchAlgorithmException, InvalidKeyException, IOException {
+ apns = new ApnsClientBuilder()
+ .setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST)
+ .setSigningKey(ApnsSigningKey.loadFromPkcs8File(new File(p8key),
+ teamId, keyId))
+ .build();
+ }
+ @Override
+ public void processMessageEvent(MessageEvent messageEvent) {
+ com.juick.Message jmsg = messageEvent.getMessage();
+ List<User> users = messageEvent.getUsers();
+ ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder();
+ apnsPayloadBuilder.addCustomProperty("mid", jmsg.getMid());
+ apnsPayloadBuilder.addCustomProperty("uname", jmsg.getUser().getName());
+ String post = PlainTextFormatter.formatPost(jmsg);
+ String[] parts = post.split("\n", 2);
+ apnsPayloadBuilder.setAlertTitle(parts[0]).setAlertBody(parts[1]);
+ users.forEach( user -> {
+ apnsPayloadBuilder.setBadgeNumber(user.getUnreadCount());
+ String payload = apnsPayloadBuilder.buildWithDefaultMaximumLength();
+ user.getTokens().stream().filter(t -> t.getType().equals("apns"))
+ .map(ExternalToken::getToken).forEach(token -> {
+ Future<PushNotificationResponse<SimpleApnsPushNotification>> notification = apns.sendNotification(
+ new SimpleApnsPushNotification(token, topic, payload));
+ notification.addListener((PushNotificationResponseListener<SimpleApnsPushNotification>) future -> {
+ if (future.isSuccess()) {
+ processAPNSResponse(token, future.getNow());
+ } else {
+ logger.warn("APNS error ", future.cause());
+ }
+ });
+ });
+ });
+ }
+
+ @Override
+ public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
+
+ }
+
+ @Override
+ public void processLikeEvent(LikeEvent likeEvent) {
+
+ }
+
+ @Override
+ public void processPingEvent(PingEvent pingEvent) {
+
+ }
+
+ @Override
+ public void processMessageReadEvent(MessageReadEvent messageReadEvent) {
+ List<User> users = messageReadEvent.getUsers();
+ ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder();
+ users.forEach(user -> {
+ apnsPayloadBuilder.setBadgeNumber(user.getUnreadCount());
+ String payload = apnsPayloadBuilder.buildWithDefaultMaximumLength();
+ user.getTokens().stream().filter(t -> t.getType().equals("apns"))
+ .map(ExternalToken::getToken).forEach(token -> {
+ Future<PushNotificationResponse<SimpleApnsPushNotification>> notification = apns.sendNotification(
+ new SimpleApnsPushNotification(token, topic, payload));
+ notification.addListener((PushNotificationResponseListener<SimpleApnsPushNotification>) future -> {
+ if (future.isSuccess()) {
+ processAPNSResponse(token, future.getNow());
+ } else {
+ logger.warn("APNS error ", future.cause());
+ }
+ });
+ });
+ });
+ }
+ @PreDestroy
+ public void close() {
+ apns.close();
+ }
+
+ private void processAPNSResponse(String token, PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse) {
+ if (pushNotificationResponse.isAccepted()) {
+ logger.info("APNS accepted: {}", token);
+ } else {
+ String reason = pushNotificationResponse.getRejectionReason();
+ logger.info("APNS rejected: {}", reason);
+ if (reason.equals("BadDeviceToken")) {
+ notificationsManager.getInvalidAPNSTokens().add(token);
+ }
+ }
+ Optional<Date> invalidationDate = Optional.ofNullable(
+ pushNotificationResponse.getTokenInvalidationTimestamp());
+ invalidationDate.ifPresent(date -> {
+ if (date.before(new Date())) {
+ logger.info("Token invalidated: {}", token);
+ notificationsManager.getInvalidAPNSTokens().add(token);
+ }
+ });
+ }
+}
diff --git a/juick-notifications/src/main/java/com/juick/components/FirebaseManager.java b/juick-notifications/src/main/java/com/juick/components/FirebaseManager.java
new file mode 100644
index 00000000..54e7c97a
--- /dev/null
+++ b/juick-notifications/src/main/java/com/juick/components/FirebaseManager.java
@@ -0,0 +1,90 @@
+package com.juick.components;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.android.gcm.server.*;
+import com.juick.ExternalToken;
+import com.juick.User;
+import com.juick.service.component.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class FirebaseManager implements NotificationListener {
+ private static Logger logger = LoggerFactory.getLogger(FirebaseManager.class);
+ @Inject
+ ObjectMapper jsonMapper;
+ @Value("${gcm_key:}")
+ private String gcmKey;
+ @Inject
+ private NotificationsManager notificationsManager;
+
+ private Sender GCMSender;
+
+ @PostConstruct
+ public void initialize() {
+ GCMSender = new Sender(gcmKey, Endpoint.GCM);
+ }
+
+ @Override
+ public void processMessageEvent(MessageEvent messageEvent) {
+ com.juick.Message jmsg = messageEvent.getMessage();
+ List<User> users = messageEvent.getUsers();
+ // GCM
+ List<String> regids = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("gcm"))
+ .map(ExternalToken::getToken).collect(Collectors.toList());
+ if (!regids.isEmpty()) {
+ try {
+ String json = jsonMapper.writeValueAsString(jmsg);
+ logger.info(json);
+ Message message = new Message.Builder().addData("message", json).build();
+ MulticastResult result = GCMSender.send(message, regids, 3);
+ List<Result> results = result.getResults();
+ for (int i = 0; i < results.size(); i++) {
+ Result currentResult = results.get(i);
+ logger.info("RES {}: {}", i, currentResult);
+ List<String> errorCodes = Arrays.asList(Constants.ERROR_MISMATCH_SENDER_ID, Constants.ERROR_NOT_REGISTERED);
+ if (errorCodes.contains(currentResult.getErrorCodeName())) {
+ // assuming results are in order of regids
+ // http://stackoverflow.com/a/11594531/1097384
+ String currentId = regids.get(i);
+ logger.info("{} is scheduled to remove", currentId);
+ notificationsManager.addInvalidGCMToken(currentId);
+ }
+ }
+ } catch (IOException ex) {
+ logger.error(ex.getMessage(), ex);
+ } catch (IllegalArgumentException err) {
+ logger.warn("Android: Invalid API Key", err);
+ }
+ } else {
+ logger.info("GMS: no recipients");
+ }
+ }
+
+ @Override
+ public void processSubscribeEvent(SubscribeEvent subscribeEvent) {
+
+ }
+
+ @Override
+ public void processLikeEvent(LikeEvent likeEvent) {
+
+ }
+
+ @Override
+ public void processPingEvent(PingEvent pingEvent) {
+
+ }
+
+ @Override
+ public void processMessageReadEvent(MessageReadEvent messageReadEvent) {
+
+ }
+}
diff --git a/juick-notifications/src/main/java/com/juick/components/MPNSClient.java b/juick-notifications/src/main/java/com/juick/components/MPNSManager.java
index efa47bb1..56c2df8d 100644
--- a/juick-notifications/src/main/java/com/juick/components/MPNSClient.java
+++ b/juick-notifications/src/main/java/com/juick/components/MPNSManager.java
@@ -1,9 +1,14 @@
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 org.apache.commons.collections4.MapUtils;
+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;
@@ -19,19 +24,18 @@ 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 MPNSClient {
+public class MPNSManager implements NotificationListener {
- private static Logger logger = LoggerFactory.getLogger(MPNSClient.class);
+ private static Logger logger = LoggerFactory.getLogger(MPNSManager.class);
private String accessToken;
- private NotificationClientListener listener;
-
@Inject
private ObjectMapper jsonMapper;
@Value("${wns_application_sip:}")
@@ -40,6 +44,9 @@ public class MPNSClient {
private String applicationSecret;
private RestTemplate wnsService;
+ @Inject
+ private NotificationsManager notificationsManager;
+
@PostConstruct
public void authenticate() throws IOException {
String url = "https://login.live.com/accesstoken.srf";
@@ -82,7 +89,7 @@ public class MPNSClient {
if (statusCode == HttpStatus.GONE) {
// expired
logger.info("{} is scheduled to remove", url);
- listener.invalidToken("mpns", url);
+ notificationsManager.addInvalidMPNSToken(url);
} else {
String headersContent = ex.getResponseHeaders().entrySet().stream()
.filter(x -> x.getKey().startsWith("X-WNS-") || x.getKey().startsWith("WWW-"))
@@ -93,8 +100,64 @@ public class MPNSClient {
}
}
+ @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) {
- public void setListener(NotificationClientListener listener) {
- this.listener = listener;
}
}
diff --git a/juick-notifications/src/main/java/com/juick/components/NotificationClientListener.java b/juick-notifications/src/main/java/com/juick/components/NotificationClientListener.java
deleted file mode 100644
index 46bd683f..00000000
--- a/juick-notifications/src/main/java/com/juick/components/NotificationClientListener.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.juick.components;
-
-/**
- * Created by vital on 29.03.2017.
- */
-public interface NotificationClientListener {
- void invalidToken(String type, String token);
-}
diff --git a/juick-notifications/src/main/java/com/juick/components/Notifications.java b/juick-notifications/src/main/java/com/juick/components/NotificationsManager.java
index 1842593a..be97ea40 100644
--- a/juick-notifications/src/main/java/com/juick/components/Notifications.java
+++ b/juick-notifications/src/main/java/com/juick/components/NotificationsManager.java
@@ -18,23 +18,14 @@
package com.juick.components;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.android.gcm.server.*;
import com.juick.ExternalToken;
import com.juick.User;
-import com.juick.formatters.PlainTextFormatter;
import com.juick.service.component.DisconnectedEvent;
+import com.juick.service.component.MessageEvent;
+import com.juick.service.component.MessageReadEvent;
import com.juick.util.MessageUtils;
-import com.turo.pushy.apns.ApnsClient;
-import com.turo.pushy.apns.PushNotificationResponse;
-import com.turo.pushy.apns.util.ApnsPayloadBuilder;
-import com.turo.pushy.apns.util.SimpleApnsPushNotification;
-import com.turo.pushy.apns.util.concurrent.PushNotificationResponseListener;
-import io.netty.util.concurrent.Future;
-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.context.ApplicationEventPublisher;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
@@ -64,13 +55,11 @@ import java.util.stream.Collectors;
* @author Ugnich Anton
*/
@Component
-public class Notifications extends TextWebSocketHandler implements NotificationClientListener {
- private static Logger logger = LoggerFactory.getLogger(Notifications.class);
+public class NotificationsManager extends TextWebSocketHandler {
+ private static Logger logger = LoggerFactory.getLogger(NotificationsManager.class);
@Inject
private RestTemplate rest;
- @Inject
- private Sender GCMSender;
@Inject
private ObjectMapper jsonMapper;
@@ -79,16 +68,8 @@ public class Notifications extends TextWebSocketHandler implements NotificationC
private final Set<String> invalidMPNSTokens = Collections.synchronizedSet(new HashSet<>());
private final Set<String> invalidAPNSTokens = Collections.synchronizedSet(new HashSet<>());
- @Inject
- private MPNSClient mpnsClient;
- @Inject
- private ApnsClient apns;
- @Value("${ios_app_id:}")
- private String topic;
-
@PostConstruct
public void init() {
- mpnsClient.setListener(this);
closeFlag.set(false);
}
public void messageReceived(@Nonnull com.juick.Message jmsg) {
@@ -114,144 +95,15 @@ public class Notifications extends TextWebSocketHandler implements NotificationC
HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() {
}).getBody());
}
-
- // GCM
- List<String> regids = users.stream().flatMap(u -> u.getTokens().stream()).filter(d -> d.getType().equals("gcm"))
- .map(ExternalToken::getToken).collect(Collectors.toList());
- if (!regids.isEmpty()) {
- try {
- String json = jsonMapper.writeValueAsString(jmsg);
- logger.info(json);
- Message message = new Message.Builder().addData("message", json).build();
- MulticastResult result = GCMSender.send(message, regids, 3);
- List<Result> results = result.getResults();
- for (int i = 0; i < results.size(); i++) {
- Result currentResult = results.get(i);
- logger.info("RES {}: {}", i, currentResult);
- List<String> errorCodes = Arrays.asList(Constants.ERROR_MISMATCH_SENDER_ID, Constants.ERROR_NOT_REGISTERED);
- if (errorCodes.contains(currentResult.getErrorCodeName())) {
- // assuming results are in order of regids
- // http://stackoverflow.com/a/11594531/1097384
- String currentId = regids.get(i);
- logger.info("{} is scheduled to remove", currentId);
- addInvalidGCMToken(currentId);
- }
- }
- } catch (IOException ex) {
- logger.error(ex.getMessage(), ex);
- } catch (IllegalArgumentException err) {
- logger.warn("Android: Invalid API Key", err);
- }
- } else {
- logger.info("GMS: no recipients");
- }
-
- /*** WinPhone ***/
- 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);
- mpnsClient.sendNotification(url, xml);
- }
- } catch (IOException | IllegalStateException ex) {
- logger.error("WNS: ", ex);
- }
- }
-
- /*** iOS ***/
- ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder();
- apnsPayloadBuilder.addCustomProperty("mid", jmsg.getMid());
- apnsPayloadBuilder.addCustomProperty("uname", jmsg.getUser().getName());
- String post = PlainTextFormatter.formatPost(jmsg);
- String[] parts = post.split("\n", 2);
- apnsPayloadBuilder.setAlertTitle(parts[0]).setAlertBody(parts[1]);
- users.forEach( user -> {
- apnsPayloadBuilder.setBadgeNumber(user.getUnreadCount());
- String payload = apnsPayloadBuilder.buildWithDefaultMaximumLength();
- user.getTokens().stream().filter(t -> t.getType().equals("apns"))
- .map(ExternalToken::getToken).forEach(token -> {
- Future<PushNotificationResponse<SimpleApnsPushNotification>> notification = apns.sendNotification(
- new SimpleApnsPushNotification(token, topic, payload));
- notification.addListener((PushNotificationResponseListener<SimpleApnsPushNotification>) future -> {
- if (future.isSuccess()) {
- processAPNSResponse(token, future.getNow());
- } else {
- logger.warn("APNS error ", future.cause());
- }
- });
- });
- });
+ applicationEventPublisher.publishEvent(new MessageEvent(this, jmsg, users));
}
private void serviceMessageReceived(@Nonnull com.juick.Message jmsg) {
logger.info("Message read event from {} for {}", jmsg.getUser().getName(), jmsg.getMid());
- // iOS
List<User> users = rest.exchange(String.format("http://api.juick.com/notifications?uid=%d",
jmsg.getUser().getUid()),
HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() {
}).getBody();
- ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder();
- users.forEach(user -> {
- apnsPayloadBuilder.setBadgeNumber(user.getUnreadCount());
- String payload = apnsPayloadBuilder.buildWithDefaultMaximumLength();
- user.getTokens().stream().filter(t -> t.getType().equals("apns"))
- .map(ExternalToken::getToken).forEach(token -> {
- Future<PushNotificationResponse<SimpleApnsPushNotification>> notification = apns.sendNotification(
- new SimpleApnsPushNotification(token, topic, payload));
- notification.addListener((PushNotificationResponseListener<SimpleApnsPushNotification>) future -> {
- if (future.isSuccess()) {
- processAPNSResponse(token, future.getNow());
- } else {
- logger.warn("APNS error ", future.cause());
- }
- });
- });
- });
- }
-
- private void processAPNSResponse(String token, PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse) {
- if (!closeFlag.get()) {
- if (pushNotificationResponse.isAccepted()) {
- logger.info("APNS accepted: {}", token);
- } else {
- String reason = pushNotificationResponse.getRejectionReason();
- logger.info("APNS rejected: {}", reason);
- if (reason.equals("BadDeviceToken")) {
- invalidAPNSTokens.add(token);
- }
- }
- Optional<Date> invalidationDate = Optional.ofNullable(
- pushNotificationResponse.getTokenInvalidationTimestamp());
- invalidationDate.ifPresent(date -> {
- if (date.before(new Date())) {
- logger.info("Token invalidated: {}", token);
- invalidAPNSTokens.add(token);
- }
- });
- }
+ applicationEventPublisher.publishEvent(new MessageReadEvent(this, users, jmsg));
}
public void addInvalidGCMToken(String token) {
@@ -283,17 +135,6 @@ public class Notifications extends TextWebSocketHandler implements NotificationC
}
}
- @Override
- public void invalidToken(String type, String token) {
- switch (type) {
- case "mpns":
- addInvalidMPNSToken(token);
- break;
- default:
- break;
- }
- }
-
public Set<String> getInvalidAPNSTokens() {
return invalidAPNSTokens;
}
@@ -343,7 +184,6 @@ public class Notifications extends TextWebSocketHandler implements NotificationC
}
@PreDestroy
public void close() {
- apns.close();
closeFlag.set(true);
}
@Scheduled(fixedRate = 600000)
diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/APNSConfiguration.java b/juick-notifications/src/main/java/com/juick/components/configuration/APNSConfiguration.java
index 43ea3943..fbc17bc9 100644
--- a/juick-notifications/src/main/java/com/juick/components/configuration/APNSConfiguration.java
+++ b/juick-notifications/src/main/java/com/juick/components/configuration/APNSConfiguration.java
@@ -1,34 +1,18 @@
package com.juick.components.configuration;
-import com.turo.pushy.apns.ApnsClient;
-import com.turo.pushy.apns.ApnsClientBuilder;
-import com.turo.pushy.apns.auth.ApnsSigningKey;
-import org.springframework.beans.factory.annotation.Value;
+import com.juick.components.APNSManager;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import java.io.File;
-import java.io.IOException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
/**
* Created by vital on 28.03.2017.
*/
@Configuration
+@ConditionalOnProperty(name = "ios_p8_key")
public class APNSConfiguration {
- @Value("${ios_p8_key:}")
- private String p8key;
- @Value("${ios_team_id:}")
- private String teamId;
- @Value("${ios_key_id:}")
- private String keyId;
@Bean
- public ApnsClient apns() throws NoSuchAlgorithmException, InvalidKeyException, IOException {
- return new ApnsClientBuilder()
- .setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST)
- .setSigningKey(ApnsSigningKey.loadFromPkcs8File(new File(p8key),
- teamId, keyId))
- .build();
+ public APNSManager apnsManager() {
+ return new APNSManager();
}
}
diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/GCMConfiguration.java b/juick-notifications/src/main/java/com/juick/components/configuration/GCMConfiguration.java
index 27e1af0f..68d9f017 100644
--- a/juick-notifications/src/main/java/com/juick/components/configuration/GCMConfiguration.java
+++ b/juick-notifications/src/main/java/com/juick/components/configuration/GCMConfiguration.java
@@ -1,8 +1,7 @@
package com.juick.components.configuration;
-import com.google.android.gcm.server.Endpoint;
-import com.google.android.gcm.server.Sender;
-import org.springframework.beans.factory.annotation.Value;
+import com.juick.components.FirebaseManager;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -10,12 +9,11 @@ import org.springframework.context.annotation.Configuration;
* Created by vital on 29.03.2017.
*/
@Configuration
+@ConditionalOnProperty(name = "gcm_key")
public class GCMConfiguration {
- @Value("${gcm_key:}")
- private String gcmKey;
@Bean
- public Sender GCMSender() {
- return new Sender(gcmKey, Endpoint.GCM);
+ public FirebaseManager firebaseManager() {
+ return new FirebaseManager();
}
}
diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/JuickServerWebsocketConfiguration.java b/juick-notifications/src/main/java/com/juick/components/configuration/JuickServerWebsocketConfiguration.java
index c35dfc7d..deb0cb5b 100644
--- a/juick-notifications/src/main/java/com/juick/components/configuration/JuickServerWebsocketConfiguration.java
+++ b/juick-notifications/src/main/java/com/juick/components/configuration/JuickServerWebsocketConfiguration.java
@@ -1,14 +1,13 @@
package com.juick.components.configuration;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.juick.components.Notifications;
+import com.juick.components.NotificationsManager;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestInterceptor;
@@ -40,7 +39,7 @@ public class JuickServerWebsocketConfiguration {
@Inject
ObjectMapper jsonMapper;
@Inject
- private Notifications notifications;
+ private NotificationsManager notificationsManager;
@Bean
public RestTemplate rest() {
RestTemplate rest = new RestTemplate();
@@ -62,7 +61,7 @@ public class JuickServerWebsocketConfiguration {
}
String websocketURI = UriComponentsBuilder.fromUriString(baseUri)
.queryParam("hash", hash).build().toUriString();
- WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), notifications, websocketURI);
+ WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), notificationsManager, websocketURI);
return manager;
}
@Bean
diff --git a/juick-notifications/src/main/java/com/juick/components/configuration/MPNSConfiguration.java b/juick-notifications/src/main/java/com/juick/components/configuration/MPNSConfiguration.java
index f849b159..4235486c 100644
--- a/juick-notifications/src/main/java/com/juick/components/configuration/MPNSConfiguration.java
+++ b/juick-notifications/src/main/java/com/juick/components/configuration/MPNSConfiguration.java
@@ -1,6 +1,7 @@
package com.juick.components.configuration;
-import com.juick.components.MPNSClient;
+import com.juick.components.MPNSManager;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -8,9 +9,10 @@ import org.springframework.context.annotation.Configuration;
* Created by vital on 29.03.2017.
*/
@Configuration
+@ConditionalOnProperty(name = "wns_application_sip")
public class MPNSConfiguration {
@Bean
- public MPNSClient mpnsClient() {
- return new MPNSClient();
+ public MPNSManager mpnsClient() {
+ return new MPNSManager();
}
}