diff --git a/pom.xml b/pom.xml index b570cce..9f54508 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.uci adapter - 2.2.8 + 2.2.9 adapter jar @@ -19,9 +19,9 @@ 11 - 2.2.8 - 2.2.8 - 2.2.8 + 2.2.9 + 2.2.9 + 2.2.9 diff --git a/src/main/java/com/uci/adapter/firebase/web/FirebaseNotificationAdapter.java b/src/main/java/com/uci/adapter/firebase/web/FirebaseNotificationAdapter.java index 7e88f3e..cf1fca7 100644 --- a/src/main/java/com/uci/adapter/firebase/web/FirebaseNotificationAdapter.java +++ b/src/main/java/com/uci/adapter/firebase/web/FirebaseNotificationAdapter.java @@ -5,7 +5,6 @@ import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutureCallback; import com.google.api.core.ApiFutures; -import com.google.api.gax.rpc.ApiException; import com.google.auth.oauth2.GoogleCredentials; import com.google.common.util.concurrent.MoreExecutors; import com.google.firebase.FirebaseApp; @@ -22,7 +21,6 @@ import lombok.extern.slf4j.Slf4j; import messagerosa.core.model.*; import org.jetbrains.annotations.NotNull; -import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -34,8 +32,6 @@ import java.sql.Timestamp; import java.time.LocalDateTime; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -50,6 +46,7 @@ public class FirebaseNotificationAdapter extends AbstractProvider implements IPr public BotService botService; private String notificationKeyEnable; + private long fcmAndroidConfigTTl; /** * Convert Firebase Message Object to XMessage Object @@ -146,27 +143,48 @@ public Mono processOutBoundMessageF(XMessage nextMsg) { @Override public Mono apply(JsonNode credentials) { String channelMessageId = UUID.randomUUID().toString(); - log.info("credentials: " + credentials); - if (credentials != null && credentials.path("serviceKey") != null - && !credentials.path("serviceKey").asText().isEmpty()) { + + if (credentials != null && credentials.path("serviceKey") != null) { String click_action = null; if (data.get("fcmClickActionUrl") != null && !data.get("fcmClickActionUrl").isEmpty()) { click_action = data.get("fcmClickActionUrl"); } - - - return (new FirebaseNotificationService()).sendNotificationMessage(credentials.path("serviceKey").asText(), data.get("fcmToken"), nextMsg.getPayload().getTitle(), nextMsg.getPayload().getText(), click_action, nextMsg.getTo().getUserID(), channelMessageId, notificationKeyEnable, data) - .map(new Function() { + String serviceKey = credentials.path("serviceKey").toString(); + log.info("FCM serviceKey: " + credentials); + FirebaseMessaging firebaseMessaging = null; + try { + firebaseMessaging = configureFirebaseMessaging(serviceKey, nextMsg.getAdapterId()); + } catch (Exception e) { + e.printStackTrace(); + } + + return (new FirebaseNotificationService()).sendNotificationMessage(data.get("fcmToken"), nextMsg.getPayload().getTitle(), nextMsg.getPayload().getText(), click_action, nextMsg.getTo().getUserID(), channelMessageId, notificationKeyEnable, + data, firebaseMessaging) + .map(new Function() { @Override - public XMessage apply(Boolean result) { - if (result) { + public XMessage apply(String messageId) { + if (messageId != null && !messageId.isEmpty()) { nextMsg.setTo(to); nextMsg.setMessageId(MessageId.builder().channelMessageId(channelMessageId).build()); nextMsg.setMessageState(XMessage.MessageState.SENT); + nextMsg.setRespMsgId(messageId); } return nextMsg; } }); + +// return (new FirebaseNotificationService()).sendNotificationMessage(credentials.path("serviceKey").asText(), data.get("fcmToken"), nextMsg.getPayload().getTitle(), nextMsg.getPayload().getText(), click_action, nextMsg.getTo().getUserID(), channelMessageId, notificationKeyEnable, data) +// .map(new Function() { +// @Override +// public XMessage apply(Boolean result) { +// if (result) { +// nextMsg.setTo(to); +// nextMsg.setMessageId(MessageId.builder().channelMessageId(channelMessageId).build()); +// nextMsg.setMessageState(XMessage.MessageState.SENT); +// } +// return nextMsg; +// } +// }); } return null; } @@ -234,7 +252,8 @@ public Mono> apply(List msgList) { .setBody(nextMsg.getPayload().getText()) .build(); } - + String botName = nextMsg.getApp().replaceAll(" ", "_"); + log.info("FirebaseNotificationAdapter:processOutBoundMessageF:: BotName : " + botName + " : fcmAndroidConfigTTl : " + fcmAndroidConfigTTl); Message message = Message.builder() .setNotification(notification) .setToken(data.get("fcmToken")) @@ -244,6 +263,8 @@ public Mono> apply(List msgList) { .putData("destAdd", nextMsg.getTo().getUserID()) .putData("fcmDestAdd", data.get("fcmToken")) .putData("click_action", click_action) + .setFcmOptions(FcmOptions.withAnalyticsLabel(botName)) + .setAndroidConfig(AndroidConfig.builder().setTtl(1000 * fcmAndroidConfigTTl).build()) .putAllData(dataMap) .build(); // uniqueUserSet.add(nextMsg.getTo().getUserID()); diff --git a/src/main/java/com/uci/adapter/firebase/web/FirebaseNotificationService.java b/src/main/java/com/uci/adapter/firebase/web/FirebaseNotificationService.java index dffd647..972f7ad 100644 --- a/src/main/java/com/uci/adapter/firebase/web/FirebaseNotificationService.java +++ b/src/main/java/com/uci/adapter/firebase/web/FirebaseNotificationService.java @@ -3,13 +3,21 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.Notification; +import com.google.firebase.messaging.SendResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Slf4j @Service @@ -19,75 +27,118 @@ public class FirebaseNotificationService { /** * Send FCM Notification to token with title & body + * * @param token * @param title * @param body * @return */ - public Mono sendNotificationMessage(String serviceKey, String token, String title, String body, String click_action, String phone, String channelMessageId, String notificationKeyEnable, Map data) { - try { - WebClient client = WebClient.builder() - .baseUrl(url) - .defaultHeaders(httpHeaders -> { - httpHeaders.set("Authorization", "key=" + serviceKey); - httpHeaders.set("Content-Type", "application/json"); - }) - .build(); - ObjectMapper mapper = new ObjectMapper(); - ObjectNode node = mapper.createObjectNode(); - node.put("to", token); - node.put("collapse_key", "type_a"); - // Notification Key Enable and Disable from Payload - if (notificationKeyEnable != null && notificationKeyEnable.equalsIgnoreCase("true")) { - ObjectNode notificationNode = mapper.createObjectNode(); - notificationNode.put("body", body); - notificationNode.put("title", title); - if (click_action != null && !click_action.isEmpty()) { - notificationNode.put("click_action", click_action); - } - node.put("notification", notificationNode); - } - - ObjectNode dataNode = mapper.createObjectNode(); - dataNode.put("body", body); - dataNode.put("title", title); - dataNode.put("externalId", channelMessageId); - dataNode.put("destAdd", phone); - dataNode.put("fcmDestAdd", token); - dataNode.put("click_action", click_action); - - if (data != null) { - for (String dataKey : data.keySet()) { - if (!dataKey.equalsIgnoreCase("fcmToken") && !dataKey.equalsIgnoreCase("fcmClickActionUrl")) { - dataNode.put(dataKey, data.get(dataKey)); - } - } - } - - node.put("data", dataNode); - - return client.post().bodyValue(node.toString()).retrieve().bodyToMono(String.class).map(response -> { - if (response != null) { - try { - ObjectNode resultNode = (ObjectNode) mapper.readTree(response); - if (resultNode.get("success") != null && Integer.parseInt(resultNode.get("success").toString()) >= 1) { - log.info("FirebaseNotificationService:Notification triggered success : " + phone + " fcm token : " + token + " FCM Response : " + resultNode.toString()); - return true; - } else { - log.error("FirebaseNotificationService:Notification not sent : " + phone + " fcm Token : " + token + " error :" + resultNode.toString()); + public Mono sendNotificationMessage(String token, String title, String body, String click_action, String phone, String channelMessageId, String notificationKeyEnable, Map data, FirebaseMessaging firebaseMessaging) { + return Mono.fromCallable(() -> { + try { + Map dataMap = new HashMap<>(); + if (data != null) { + for (String dataKey : data.keySet()) { + if (!dataKey.equalsIgnoreCase("fcmToken") && !dataKey.equalsIgnoreCase("fcmClickActionUrl")) { + dataMap.put(dataKey, data.get(dataKey)); } - } catch (Exception ex) { - log.error("FirebaseNotificationService:sendNotificationMessage::Exception: " + ex.getMessage()); } } - return false; - }); - } catch (Exception ex){ - log.error("FirebaseNotificationService:sendNotificationMessage::Exception: "+ex.getMessage()); - } - return Mono.just(false); + Notification notification = null; + if (notificationKeyEnable != null && notificationKeyEnable.equalsIgnoreCase("true")) { + notification = Notification.builder() + .setTitle(title) + .setBody(body) + .build(); + } + Message message = Message.builder() + .setNotification(notification) + .setToken(data.get("fcmToken")) + .putData("body", body) + .putData("title", title) + .putData("externalId", channelMessageId) + .putData("destAdd", phone) + .putData("fcmDestAdd", token) + .putData("click_action", click_action) + .putAllData(dataMap) + .build(); + String messageId = firebaseMessaging.send(message); + log.info("FCM Returned MessageID : " + messageId); + return messageId; + } catch (Exception ex) { + log.error("FirebaseNotificationService:sendNotificationMessage::Exception: " + ex.getMessage()); + return null; + } + }); } + /** + * FCM Old Implementation + */ +// public Mono sendNotificationMessage(String serviceKey, String token, String title, String body, String click_action, String phone, String channelMessageId, String notificationKeyEnable, Map data) { +// try { +// WebClient client = WebClient.builder() +// .baseUrl(url) +// .defaultHeaders(httpHeaders -> { +// httpHeaders.set("Authorization", "key=" + serviceKey); +// httpHeaders.set("Content-Type", "application/json"); +// }) +// .build(); +// ObjectMapper mapper = new ObjectMapper(); +// ObjectNode node = mapper.createObjectNode(); +// node.put("to", token); +// node.put("collapse_key", "type_a"); +// // Notification Key Enable and Disable from Payload +// if (notificationKeyEnable != null && notificationKeyEnable.equalsIgnoreCase("true")) { +// ObjectNode notificationNode = mapper.createObjectNode(); +// notificationNode.put("body", body); +// notificationNode.put("title", title); +// if (click_action != null && !click_action.isEmpty()) { +// notificationNode.put("click_action", click_action); +// } +// node.put("notification", notificationNode); +// } +// +// ObjectNode dataNode = mapper.createObjectNode(); +// dataNode.put("body", body); +// dataNode.put("title", title); +// dataNode.put("externalId", channelMessageId); +// dataNode.put("destAdd", phone); +// dataNode.put("fcmDestAdd", token); +// dataNode.put("click_action", click_action); +// +// if (data != null) { +// for (String dataKey : data.keySet()) { +// if (!dataKey.equalsIgnoreCase("fcmToken") && !dataKey.equalsIgnoreCase("fcmClickActionUrl")) { +// dataNode.put(dataKey, data.get(dataKey)); +// } +// } +// } +// +// node.put("data", dataNode); +// +// return client.post().bodyValue(node.toString()).retrieve().bodyToMono(String.class).map(response -> { +// if (response != null) { +// try { +// ObjectNode resultNode = (ObjectNode) mapper.readTree(response); +// if (resultNode.get("success") != null && Integer.parseInt(resultNode.get("success").toString()) >= 1) { +// log.info("FirebaseNotificationService:Notification triggered success : " + phone + " fcm token : " + token + " FCM Response : " + resultNode.toString()); +// return true; +// } else { +// log.error("FirebaseNotificationService:Notification not sent : " + phone + " fcm Token : " + token + " error :" + resultNode.toString()); +// } +// } catch (Exception ex) { +// log.error("FirebaseNotificationService:sendNotificationMessage::Exception: " + ex.getMessage()); +// } +// } +// return false; +// }); +// } catch (Exception ex){ +// log.error("FirebaseNotificationService:sendNotificationMessage::Exception: "+ex.getMessage()); +// } +// return Mono.just(false); +// } + // public Mono sendNotificationMessage2(String token, String title, String body) { // OkHttpClient client = new OkHttpClient().newBuilder().build(); // ObjectMapper mapper = new ObjectMapper(); diff --git a/src/main/java/com/uci/adapter/provider/factory/ProviderFactory.java b/src/main/java/com/uci/adapter/provider/factory/ProviderFactory.java index cc9261e..4361282 100644 --- a/src/main/java/com/uci/adapter/provider/factory/ProviderFactory.java +++ b/src/main/java/com/uci/adapter/provider/factory/ProviderFactory.java @@ -44,6 +44,8 @@ public class ProviderFactory { @Value("${fcm.notificationKeyEnable:#{'true'}}") private String notificationKeyEnable; + @Value("${fcm.androidconfig.ttl:#{36000}}") + private long fcmAndgoidConfigTTl; public IProvider getProvider(String provider, String channel) { if (provider.toLowerCase().equals("gupshup") && channel.toLowerCase().equals("whatsapp")) { @@ -72,7 +74,9 @@ public IProvider getProvider(String provider, String channel) { netcoreWhatsappAdapter.setFileCdnProvider(fileCdnFactory.getFileCdnProvider()); return netcoreWhatsappAdapter; } else if (provider.toLowerCase().equals("firebase") && channel.toLowerCase().equals("web")) { - return FirebaseNotificationAdapter.builder().botService(botService).notificationKeyEnable(notificationKeyEnable).build(); + return FirebaseNotificationAdapter.builder().botService(botService).notificationKeyEnable(notificationKeyEnable).fcmAndroidConfigTTl(fcmAndgoidConfigTTl) + .build(); + } return null; }