aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Vitaly Takmazov2017-10-17 13:50:26 +0300
committerGravatar Vitaly Takmazov2017-10-17 14:27:08 +0300
commitd41e94c835396f5f8b33f8be05dcb76366e06d22 (patch)
treeec82ffa96068e338a4dd7cfa823e43408c43b868
parent9b5db8da41d5c4c5f50012c0055b4008191cdb8f (diff)
notifications: APNS HTTP API
-rw-r--r--juick-notifications/build.gradle2
-rw-r--r--juick-notifications/src/main/java/com/juick/components/CleanUp.java22
-rw-r--r--juick-notifications/src/main/java/com/juick/components/Notifications.java42
-rw-r--r--juick-notifications/src/main/java/com/juick/components/configuration/APNSConfiguration.java29
4 files changed, 63 insertions, 32 deletions
diff --git a/juick-notifications/build.gradle b/juick-notifications/build.gradle
index 3e641c93..74fb9081 100644
--- a/juick-notifications/build.gradle
+++ b/juick-notifications/build.gradle
@@ -5,7 +5,7 @@ apply plugin: 'org.akhikhl.gretty'
dependencies {
compile project(':juick-server-web')
compile 'com.ganyo:gcm-server:1.1.0'
- compile 'com.notnoop.apns:apns:1.0.0.Beta6'
+ compile 'com.turo:pushy:0.11.3'
compile "rocks.xmpp:xmpp-core-client:0.7.4"
compile "rocks.xmpp:xmpp-extensions-client:0.7.4"
diff --git a/juick-notifications/src/main/java/com/juick/components/CleanUp.java b/juick-notifications/src/main/java/com/juick/components/CleanUp.java
index 9714e597..d0f3e44a 100644
--- a/juick-notifications/src/main/java/com/juick/components/CleanUp.java
+++ b/juick-notifications/src/main/java/com/juick/components/CleanUp.java
@@ -1,15 +1,13 @@
package com.juick.components;
import com.juick.components.service.TokenService;
-import com.notnoop.apns.ApnsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
-import java.util.Collection;
-import java.util.stream.Collectors;
+import java.util.ArrayList;
/**
* Created by vitalyster on 22.11.2016.
@@ -20,8 +18,6 @@ public class CleanUp {
private static Logger logger = LoggerFactory.getLogger(CleanUp.class);
@Inject
- ApnsService apns;
- @Inject
TokenService tokenService;
@Inject
@@ -29,20 +25,14 @@ public class CleanUp {
@Scheduled(fixedRate = 600000)
public void cleanupTokens() {
- logger.info("initializing apns tokens cleanup");
- Collection<String> devices = apns.getInactiveDevices().keySet();
- int count = devices.size();
- if (count > 0) {
- logger.info("{} tokens to delete", count);
- tokenService.deleteTokens("apns", devices.stream().collect(Collectors.toList()));
- } else {
- logger.debug("No APNS tokens to delete");
- }
logger.debug("initializing GCM tokens cleanup: {} tokens", push.getInvalidGCMTokens().size());
- tokenService.deleteTokens("gcm", push.getInvalidGCMTokens().stream().collect(Collectors.toList()));
+ tokenService.deleteTokens("gcm", new ArrayList<>(push.getInvalidGCMTokens()));
push.cleanupGCMTokens();
logger.debug("initializing MPNS tokens cleanup: {} tokens", push.getInvalidMPNSTokens().size());
- tokenService.deleteTokens("mpns", push.getInvalidMPNSTokens().stream().collect(Collectors.toList()));
+ tokenService.deleteTokens("mpns", new ArrayList<>(push.getInvalidMPNSTokens()));
+ push.cleanupMPNSTokens();
+ logger.debug("initializing APNS tokens cleanup: {} tokens", push.getInvalidAPNSTokens().size());
+ tokenService.deleteTokens("apns", new ArrayList<>(push.getInvalidAPNSTokens()));
push.cleanupMPNSTokens();
}
}
diff --git a/juick-notifications/src/main/java/com/juick/components/Notifications.java b/juick-notifications/src/main/java/com/juick/components/Notifications.java
index f0ab3b81..575f7460 100644
--- a/juick-notifications/src/main/java/com/juick/components/Notifications.java
+++ b/juick-notifications/src/main/java/com/juick/components/Notifications.java
@@ -21,12 +21,15 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.android.gcm.server.*;
import com.juick.DeviceRegistration;
import com.juick.User;
-import com.notnoop.apns.APNS;
-import com.notnoop.apns.ApnsService;
+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 org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
@@ -37,6 +40,8 @@ import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.io.IOException;
import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.stream.Collectors;
/**
@@ -57,11 +62,14 @@ public class Notifications implements NotificationClientListener, AutoCloseable
private final Set<String> invalidGCMTokens = Collections.synchronizedSet(new HashSet<>());
private final Set<String> invalidMPNSTokens = Collections.synchronizedSet(new HashSet<>());
+ private final Set<String> invalidAPNSTokens = Collections.synchronizedSet(new HashSet<>());
@Inject
private MPNSClient mpnsClient;
@Inject
- private ApnsService apns;
+ private ApnsClient apns;
+ @Value("${ios_app_id:}")
+ private String topic;
@PostConstruct
public void init() throws IOException {
@@ -164,10 +172,27 @@ public class Notifications implements NotificationClientListener, AutoCloseable
List<String> tokens = users.stream().flatMap(u -> u.getDevices().stream()).filter(d -> d.getType().equals("apns"))
.map(DeviceRegistration::getToken).collect(Collectors.toList());
if (!tokens.isEmpty()) {
+ ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder();
+ String payload = apnsPayloadBuilder.setAlertTitle("@" + jmsg.getUser().getName())
+ .setAlertBody(jmsg.getText()).buildWithDefaultMaximumLength();
for (String token : tokens) {
- String payload = APNS.newPayload().alertTitle("@" + jmsg.getUser().getName()).alertBody(jmsg.getText()).build();
- logger.info("APNS: {}", token);
- apns.push(token, payload);
+ final Future<PushNotificationResponse<SimpleApnsPushNotification>> notification
+ = apns.sendNotification(new SimpleApnsPushNotification(token, topic, payload));
+ try {
+ final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse
+ = notification.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);
+ }
+ }
+ } catch (final ExecutionException | InterruptedException ex) {
+ logger.info("APNS exception", ex);
+ }
}
} else {
logger.info("APNS: no recipients");
@@ -182,6 +207,7 @@ public class Notifications implements NotificationClientListener, AutoCloseable
@Override
public void close() throws Exception {
+ apns.close();
if (xmpp != null)
xmpp.close();
@@ -227,4 +253,8 @@ public class Notifications implements NotificationClientListener, AutoCloseable
break;
}
}
+
+ public Set<String> getInvalidAPNSTokens() {
+ return invalidAPNSTokens;
+ }
}
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 6ac155a1..43ea3943 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,23 +1,34 @@
package com.juick.components.configuration;
-import com.notnoop.apns.APNS;
-import com.notnoop.apns.ApnsService;
+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 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
public class APNSConfiguration {
- @Value("${ios_pkcs12_file:}")
- private String pkcs12File;
- @Value("${ios_pkcs12_password:}")
- private String pkcs12secret;
+ @Value("${ios_p8_key:}")
+ private String p8key;
+ @Value("${ios_team_id:}")
+ private String teamId;
+ @Value("${ios_key_id:}")
+ private String keyId;
@Bean
- public ApnsService apns() {
- return APNS.newService().withCert(pkcs12File, pkcs12secret)
- .withProductionDestination().build();
+ public ApnsClient apns() throws NoSuchAlgorithmException, InvalidKeyException, IOException {
+ return new ApnsClientBuilder()
+ .setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST)
+ .setSigningKey(ApnsSigningKey.loadFromPkcs8File(new File(p8key),
+ teamId, keyId))
+ .build();
}
}