diff options
author | Vitaly Takmazov | 2018-11-08 21:16:19 +0300 |
---|---|---|
committer | Vitaly Takmazov | 2018-11-08 21:16:19 +0300 |
commit | 3ea9770d0d43fbe45449ac4531ec4b0a374d98ea (patch) | |
tree | cf6ded98dd9c6b7bbe038711f1d8caacd99a8493 | |
parent | 31a4fc0bc7735a7ff670499deafd0364522df344 (diff) |
Drop legacy notification server
14 files changed, 1 insertions, 943 deletions
diff --git a/juick-notifications/build.gradle b/juick-notifications/build.gradle deleted file mode 100644 index 688f4eb9..00000000 --- a/juick-notifications/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'java' -apply plugin: 'org.springframework.boot' - -dependencies { - compile project(':juick-common') - compile("org.springframework.boot:spring-boot-starter-websocket") - implementation 'com.google.firebase:firebase-admin:6.5.0' - compile 'com.turo:pushy:0.13.5' -} - -compileJava.options.encoding = 'UTF-8' - -bootJar { - launchScript() -} - -configurations { - all*.exclude module: 'commons-logging' -} - diff --git a/juick-notifications/src/main/java/com/juick/components/APNSManager.java b/juick-notifications/src/main/java/com/juick/components/APNSManager.java deleted file mode 100644 index 4e5fc01a..00000000 --- a/juick-notifications/src/main/java/com/juick/components/APNSManager.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.juick.components; - -import com.juick.ExternalToken; -import com.juick.Message; -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; - @Value("${ios_sandbox_user_id:}") - private Integer sandboxUserId; - @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()); - apnsPayloadBuilder.addCustomProperty("avatarUrl", - String.format("https://i.juick.com/a/%d.png", jmsg.getUser().getUid())); - apnsPayloadBuilder.setMutableContent(true); - String post = PlainTextFormatter.formatPost(jmsg); - String[] parts = post.split("\n", 2); - apnsPayloadBuilder.setAlertTitle(parts[0]).setAlertBody(parts[1]); - users.stream().filter(u -> u.getUid() != sandboxUserId).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) { - User user = messageReadEvent.getUser(); - if (user.getUid() != sandboxUserId) { - ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder(); - 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 processTopEvent(TopEvent topEvent) { - Message message = topEvent.getMessage(); - if (message.getUser().getUid() != sandboxUserId) { - ApnsPayloadBuilder apnsPayloadBuilder = new ApnsPayloadBuilder(); - message.getUser().getTokens().stream().filter(t -> t.getType().equals("apns")) - .map(ExternalToken::getToken).forEach(token -> { - String payload = apnsPayloadBuilder.setAlertTitle("Top").setAlertBody("Your message became popular!") - .addCustomProperty("mid", message.getMid()) - .addCustomProperty("uname", message.getUser().getName()) - .buildWithDefaultMaximumLength(); - 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 deleted file mode 100644 index 1feee458..00000000 --- a/juick-notifications/src/main/java/com/juick/components/FirebaseManager.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.juick.components; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.api.core.ApiFuture; -import com.google.api.core.ApiFutureCallback; -import com.google.api.core.ApiFutures; -import com.google.auth.oauth2.GoogleCredentials; -import com.google.firebase.FirebaseApp; -import com.google.firebase.FirebaseOptions; -import com.google.firebase.messaging.FirebaseMessaging; -import com.google.firebase.messaging.FirebaseMessagingException; -import com.google.firebase.messaging.Message; -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 org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.task.TaskExecutor; - -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import java.io.IOException; -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("${fcm_database_url:}") - private String fcmDatabaseUrl; - @Inject - private NotificationsManager notificationsManager; - @Inject - private TaskExecutor taskExecutor; - - @PostConstruct - public void initialize() throws IOException { - Resource serviceAccount = - new ClassPathResource("serviceAccount.json"); - - FirebaseOptions options = new FirebaseOptions.Builder() - .setCredentials(GoogleCredentials.fromStream(serviceAccount.getInputStream())) - .setDatabaseUrl(fcmDatabaseUrl) - .build(); - - FirebaseApp.initializeApp(options); - } - - @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()) { - String json = null; - try { - json = jsonMapper.writeValueAsString(jmsg); - } catch (JsonProcessingException e) { - logger.warn("JSON exception", e); - } - logger.info(json); - Message.Builder messageBuilder = Message.builder() - .putData("message", json); - regids.forEach(token -> { - messageBuilder.setToken(token); - ApiFuture<String> response = FirebaseMessaging.getInstance().sendAsync(messageBuilder.build()); - ApiFutures.addCallback(response, new ApiFutureCallback<String>() { - @Override - public void onFailure(Throwable t) { - if (t instanceof FirebaseMessagingException) { - FirebaseMessagingException e = (FirebaseMessagingException) t; - logger.warn("FirebaseMessaging error: {}", e.getErrorCode()); - if (e.getErrorCode().equals("invalid-argument") - || e.getErrorCode().equals("registration-token-not-registered") - || e.getErrorCode().equals("invalid-registration-token")) { - // invalid token - logger.info("{} is scheduled to remove", token); - notificationsManager.addInvalidGCMToken(token); - } else { - logger.warn("Unhandled FirebaseMessaging exception", t); - } - } else { - logger.warn("Unhandled FCM exception", t); - } - } - - @Override - public void onSuccess(String result) { - logger.info("Successfully sent message: " + result); - } - }, taskExecutor); - }); - } 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) { - - } - - @Override - public void processTopEvent(TopEvent topEvent) { - - } -} diff --git a/juick-notifications/src/main/java/com/juick/components/MPNSManager.java b/juick-notifications/src/main/java/com/juick/components/MPNSManager.java deleted file mode 100644 index d6c99b0b..00000000 --- a/juick-notifications/src/main/java/com/juick/components/MPNSManager.java +++ /dev/null @@ -1,168 +0,0 @@ -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) { - - } - - @Override - public void processTopEvent(TopEvent topEvent) { - - } -} diff --git a/juick-notifications/src/main/java/com/juick/components/NotificationsManager.java b/juick-notifications/src/main/java/com/juick/components/NotificationsManager.java deleted file mode 100644 index fce0bed7..00000000 --- a/juick-notifications/src/main/java/com/juick/components/NotificationsManager.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Juick - * Copyright (C) 2013, Ugnich Anton - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -package com.juick.components; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.juick.ExternalToken; -import com.juick.User; -import com.juick.service.component.DisconnectedEvent; -import com.juick.service.component.MessageEvent; -import com.juick.service.component.MessageReadEvent; -import com.juick.util.MessageUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.socket.CloseStatus; -import org.springframework.web.socket.PingMessage; -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator; -import org.springframework.web.socket.handler.TextWebSocketHandler; - -import javax.annotation.Nonnull; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.inject.Inject; -import java.io.IOException; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; - -/** - * @author Ugnich Anton - */ -@Component -public class NotificationsManager extends TextWebSocketHandler { - private static Logger logger = LoggerFactory.getLogger(NotificationsManager.class); - - @Inject - private RestTemplate rest; - - @Inject - private ObjectMapper jsonMapper; - - 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<>()); - - @PostConstruct - public void init() { - closeFlag.set(false); - } - public void messageReceived(@Nonnull com.juick.Message jmsg) { - if (jmsg.isService()) { - serviceMessageReceived(jmsg); - return; - } - User pmTo = jmsg.getTo(); - final List<User> users = new ArrayList<>(); - if (MessageUtils.isPM(jmsg)) { - users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%d", - pmTo.getUid()), - HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() { - }).getBody()); - } else if (MessageUtils.isReply(jmsg)) { - users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%d&mid=%d&rid=%d", - jmsg.getUser().getUid(), jmsg.getMid(), jmsg.getRid()), - HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() { - }).getBody()); - } else { - users.addAll(rest.exchange(String.format("http://api.juick.com/notifications?uid=%s&mid=%s", - jmsg.getUser().getUid(), jmsg.getMid()), - HttpMethod.GET, null, new ParameterizedTypeReference<List<User>>() { - }).getBody()); - } - 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()); - 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(); - users.forEach(user -> { - applicationEventPublisher.publishEvent(new MessageReadEvent(this, user, jmsg)); - }); - } - - public void addInvalidGCMToken(String token) { - synchronized (invalidGCMTokens) { - invalidGCMTokens.add(token); - } - } - public Set<String> getInvalidGCMTokens() { - return invalidGCMTokens; - } - public void cleanupGCMTokens() { - logger.info("removed {} GCM tokens", invalidGCMTokens.size()); - synchronized (invalidGCMTokens) { - invalidGCMTokens.clear(); - } - } - public void addInvalidMPNSToken(String token) { - synchronized (invalidMPNSTokens) { - invalidMPNSTokens.add(token); - } - } - public Set<String> getInvalidMPNSTokens() { - return invalidMPNSTokens; - } - public void cleanupMPNSTokens() { - logger.info("removed {} MPNS tokens", invalidMPNSTokens.size()); - synchronized (invalidMPNSTokens) { - invalidMPNSTokens.clear(); - } - } - - public Set<String> getInvalidAPNSTokens() { - return invalidAPNSTokens; - } - @Inject - private ApplicationEventPublisher applicationEventPublisher; - - private ConcurrentWebSocketSessionDecorator session; - private final AtomicBoolean closeFlag = new AtomicBoolean(false); - - @Override - public void afterConnectionEstablished(WebSocketSession session) { - if (!closeFlag.get()) { - logger.info("WebSocket connected"); - this.session = new ConcurrentWebSocketSessionDecorator(session, 60000, 65535); - } - } - - @Override - public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { - if (!closeFlag.get()) { - logger.info("WebSocket disconnected with code {}: {}", status.getCode(), status.getReason()); - applicationEventPublisher.publishEvent(new DisconnectedEvent(this)); - } - } - - @Override - protected void handleTextMessage(WebSocketSession session, TextMessage text) throws Exception { - if (!closeFlag.get() && this.session.getDelegate().equals(session)) { - com.juick.Message jmsg = jsonMapper.readValue(text.asBytes(), com.juick.Message.class); - - if (logger.isInfoEnabled()) // prevent writeValueAsString execution if logger disabled - logger.info("got jmsg: {}", jsonMapper.writeValueAsString(jmsg)); - messageReceived(jmsg); - } - } - - @Scheduled(fixedRate = 30000, initialDelay = 30000) - public void ping() throws IOException { - if (!closeFlag.get()) { - if (session != null && session.isOpen()) { - logger.debug("Sending WebSocket ping"); - session.sendMessage(new PingMessage()); - } else { - applicationEventPublisher.publishEvent(new DisconnectedEvent(this)); - } - } - } - @PreDestroy - public void close() { - closeFlag.set(true); - } - @Scheduled(fixedRate = 600000) - public void cleanupTokens() { - if (!closeFlag.get()) { - logger.debug("initializing GCM tokens cleanup: {} tokens", getInvalidGCMTokens().size()); - deleteTokens("gcm", new ArrayList<>(getInvalidGCMTokens())); - cleanupGCMTokens(); - logger.debug("initializing MPNS tokens cleanup: {} tokens", getInvalidMPNSTokens().size()); - deleteTokens("mpns", new ArrayList<>(getInvalidMPNSTokens())); - cleanupMPNSTokens(); - logger.debug("initializing APNS tokens cleanup: {} tokens", getInvalidAPNSTokens().size()); - deleteTokens("apns", new ArrayList<>(getInvalidAPNSTokens())); - cleanupMPNSTokens(); - } - } - private void deleteTokens(String type, List<String> devices) { - if (devices.size() > 0) { - List<ExternalToken> list = devices.stream() - .map(d -> new ExternalToken(null, type, d, null)).collect(Collectors.toList()); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON_UTF8); - rest.exchange("http://api.juick.com/notifications", - HttpMethod.DELETE, new HttpEntity<>(list, headers), new ParameterizedTypeReference<Void>() { - }); - } - } -} diff --git a/juick-notifications/src/main/java/com/juick/components/PushServer.java b/juick-notifications/src/main/java/com/juick/components/PushServer.java deleted file mode 100644 index a590c2d1..00000000 --- a/juick-notifications/src/main/java/com/juick/components/PushServer.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.juick.components; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.WebApplicationType; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class PushServer { - - public static void main(String[] args) { - SpringApplication app = new SpringApplication(PushServer.class); - app.setWebApplicationType(WebApplicationType.NONE); - app.run(args); - } -} 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 deleted file mode 100644 index fbc17bc9..00000000 --- a/juick-notifications/src/main/java/com/juick/components/configuration/APNSConfiguration.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.juick.components.configuration; - -import com.juick.components.APNSManager; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Created by vital on 28.03.2017. - */ -@Configuration -@ConditionalOnProperty(name = "ios_p8_key") -public class APNSConfiguration { - @Bean - 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 deleted file mode 100644 index 68d9f017..00000000 --- a/juick-notifications/src/main/java/com/juick/components/configuration/GCMConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.juick.components.configuration; - -import com.juick.components.FirebaseManager; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Created by vital on 29.03.2017. - */ -@Configuration -@ConditionalOnProperty(name = "gcm_key") -public class GCMConfiguration { - - @Bean - 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 deleted file mode 100644 index deb0cb5b..00000000 --- a/juick-notifications/src/main/java/com/juick/components/configuration/JuickServerWebsocketConfiguration.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.juick.components.configuration; - -import com.fasterxml.jackson.databind.ObjectMapper; -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.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.InterceptingClientHttpRequestFactory; -import org.springframework.http.client.support.BasicAuthorizationInterceptor; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.socket.client.WebSocketConnectionManager; -import org.springframework.web.socket.client.standard.StandardWebSocketClient; -import org.springframework.web.util.UriComponentsBuilder; - -import javax.inject.Inject; -import java.util.Collections; -import java.util.List; - -@Configuration -@EnableScheduling -public class JuickServerWebsocketConfiguration { - private static final Logger logger = LoggerFactory.getLogger(JuickServerWebsocketConfiguration.class); - @Value("${websocket_url:ws://localhost:8080/ws/}") - private String baseUri; - @Value("${api_user:juick}") - private String serviceUser; - @Value("${api_password:secret}") - private String servicePassword; - @Inject - ObjectMapper jsonMapper; - @Inject - private NotificationsManager notificationsManager; - @Bean - public RestTemplate rest() { - RestTemplate rest = new RestTemplate(); - List<ClientHttpRequestInterceptor> interceptors = Collections.singletonList( - new BasicAuthorizationInterceptor(serviceUser, servicePassword)); - - rest.setRequestFactory(new InterceptingClientHttpRequestFactory(rest.getRequestFactory(), interceptors)); - return rest; - } - @Bean - public WebSocketConnectionManager connectionManager() { - String hash = StringUtils.EMPTY; - try { - ResponseEntity<String> response = rest().exchange("https://api.juick.com/auth", - HttpMethod.GET, null, String.class); - hash = response.getBody(); - } catch (HttpClientErrorException e) { - logger.warn("service component is not authenticated", e); - } - String websocketURI = UriComponentsBuilder.fromUriString(baseUri) - .queryParam("hash", hash).build().toUriString(); - WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), notificationsManager, websocketURI); - return manager; - } - @Bean - public StandardWebSocketClient client() { - return new StandardWebSocketClient(); - } - @Bean - public TaskScheduler taskScheduler() { - return new ConcurrentTaskScheduler(); - } -} 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 deleted file mode 100644 index 4235486c..00000000 --- a/juick-notifications/src/main/java/com/juick/components/configuration/MPNSConfiguration.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.juick.components.configuration; - -import com.juick.components.MPNSManager; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Created by vital on 29.03.2017. - */ -@Configuration -@ConditionalOnProperty(name = "wns_application_sip") -public class MPNSConfiguration { - @Bean - public MPNSManager mpnsClient() { - return new MPNSManager(); - } -} diff --git a/juick-notifications/src/main/java/com/juick/components/mpns/MPNSError.java b/juick-notifications/src/main/java/com/juick/components/mpns/MPNSError.java deleted file mode 100644 index de27641e..00000000 --- a/juick-notifications/src/main/java/com/juick/components/mpns/MPNSError.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.juick.components.mpns; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Created by vitalyster on 28.11.2016. - */ -public class MPNSError { - private String error; - private String errorDescription; - - @JsonProperty("error") - public String getError() { - return error; - } - - public void setError(String error) { - this.error = error; - } - - @JsonProperty("error_description") - public String getErrorDescription() { - return errorDescription; - } - - public void setErrorDescription(String errorDescription) { - this.errorDescription = errorDescription; - } -} diff --git a/juick-notifications/src/main/java/com/juick/components/mpns/MPNSToken.java b/juick-notifications/src/main/java/com/juick/components/mpns/MPNSToken.java deleted file mode 100644 index cd36831e..00000000 --- a/juick-notifications/src/main/java/com/juick/components/mpns/MPNSToken.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.juick.components.mpns; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Created by vitalyster on 28.11.2016. - */ -public class MPNSToken { - private String tokenType; - private String accessToken; - private String expiresIn; - - @JsonProperty("token_type") - public String getTokenType() { - return tokenType; - } - - public void setTokenType(String tokenType) { - this.tokenType = tokenType; - } - - @JsonProperty("access_token") - public String getAccessToken() { - return accessToken; - } - - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - - @JsonProperty("expires_in") - public String getExpiresIn() { - return expiresIn; - } - - public void setExpiresIn(String expiresIn) { - this.expiresIn = expiresIn; - } -} diff --git a/juick-notifications/src/main/java/com/juick/components/service/JuickServerReconnectManager.java b/juick-notifications/src/main/java/com/juick/components/service/JuickServerReconnectManager.java deleted file mode 100644 index b490c154..00000000 --- a/juick-notifications/src/main/java/com/juick/components/service/JuickServerReconnectManager.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.juick.components.service; - -import com.juick.service.component.DisconnectedEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationListener; -import org.springframework.stereotype.Component; -import org.springframework.web.socket.client.WebSocketConnectionManager; - -import javax.annotation.Nonnull; -import javax.inject.Inject; - -@Component -public class JuickServerReconnectManager implements ApplicationListener<DisconnectedEvent> { - private static Logger logger = LoggerFactory.getLogger(JuickServerReconnectManager.class); - @Inject - private WebSocketConnectionManager webSocketConnectionManager; - @Override - public void onApplicationEvent(@Nonnull DisconnectedEvent event) { - logger.info("retrying..."); - webSocketConnectionManager.stop(); - webSocketConnectionManager.start(); - } -} diff --git a/settings.gradle b/settings.gradle index 86d92c90..214e89fe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,4 @@ rootProject.name = "Juick" -include ':juick-common', ':juick-server', ':juick-notifications' +include ':juick-common', ':juick-server' |