aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/notificators/NotificatorFirebase.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/notificators/NotificatorFirebase.java')
-rw-r--r--src/main/java/org/traccar/notificators/NotificatorFirebase.java87
1 files changed, 62 insertions, 25 deletions
diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java
index 5ce2cbc0b..7440068f8 100644
--- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java
+++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 - 2024 Anton Tananaev (anton@traccar.org)
* Copyright 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,34 +24,50 @@ import com.google.firebase.messaging.AndroidNotification;
import com.google.firebase.messaging.ApnsConfig;
import com.google.firebase.messaging.Aps;
import com.google.firebase.messaging.FirebaseMessaging;
-import com.google.firebase.messaging.FirebaseMessagingException;
+import com.google.firebase.messaging.MessagingErrorCode;
import com.google.firebase.messaging.MulticastMessage;
-import com.google.firebase.messaging.Notification;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Event;
+import org.traccar.model.ObjectOperation;
import org.traccar.model.Position;
import org.traccar.model.User;
import org.traccar.notification.MessageException;
import org.traccar.notification.NotificationFormatter;
+import org.traccar.notification.NotificationMessage;
+import org.traccar.session.cache.CacheManager;
+import org.traccar.storage.Storage;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Condition;
+import org.traccar.storage.query.Request;
-import javax.inject.Inject;
-import javax.inject.Singleton;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.List;
@Singleton
-public class NotificatorFirebase implements Notificator {
+public class NotificatorFirebase extends Notificator {
- private final NotificationFormatter notificationFormatter;
+ private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class);
+ private final Storage storage;
+ private final CacheManager cacheManager;
@Inject
- public NotificatorFirebase(Config config, NotificationFormatter notificationFormatter) throws IOException {
+ public NotificatorFirebase(
+ Config config, NotificationFormatter notificationFormatter,
+ Storage storage, CacheManager cacheManager) throws IOException {
- this.notificationFormatter = notificationFormatter;
+ super(notificationFormatter, "short");
+ this.storage = storage;
+ this.cacheManager = cacheManager;
InputStream serviceAccount = new ByteArrayInputStream(
config.getString(Keys.NOTIFICATOR_FIREBASE_SERVICE_ACCOUNT).getBytes());
@@ -64,17 +80,16 @@ public class NotificatorFirebase implements Notificator {
}
@Override
- public void send(User user, Event event, Position position) throws MessageException {
+ public void send(User user, NotificationMessage message, Event event, Position position) throws MessageException {
if (user.hasAttribute("notificationTokens")) {
- var shortMessage = notificationFormatter.formatMessage(user, event, position, "short");
+ List<String> registrationTokens = new ArrayList<>(
+ Arrays.asList(user.getString("notificationTokens").split("[, ]")));
- List<String> registrationTokens = Arrays.asList(user.getString("notificationTokens").split("[, ]"));
-
- MulticastMessage message = MulticastMessage.builder()
- .setNotification(Notification.builder()
- .setTitle(shortMessage.getSubject())
- .setBody(shortMessage.getBody())
+ var messageBuilder = MulticastMessage.builder()
+ .setNotification(com.google.firebase.messaging.Notification.builder()
+ .setTitle(message.getSubject())
+ .setBody(message.getBody())
.build())
.setAndroidConfig(AndroidConfig.builder()
.setNotification(AndroidNotification.builder()
@@ -86,19 +101,41 @@ public class NotificatorFirebase implements Notificator {
.setSound("default")
.build())
.build())
- .addAllTokens(registrationTokens)
- .putData("eventId", String.valueOf(event.getId()))
- .build();
+ .addAllTokens(registrationTokens);
+
+ if (event != null) {
+ messageBuilder.putData("eventId", String.valueOf(event.getId()));
+ }
try {
- var result = FirebaseMessaging.getInstance().sendMulticast(message);
- for (var response : result.getResponses()) {
+ var result = FirebaseMessaging.getInstance().sendEachForMulticast(messageBuilder.build());
+ List<String> failedTokens = new LinkedList<>();
+ var iterator = result.getResponses().listIterator();
+ while (iterator.hasNext()) {
+ int index = iterator.nextIndex();
+ var response = iterator.next();
if (!response.isSuccessful()) {
- throw new MessageException(response.getException());
+ MessagingErrorCode error = response.getException().getMessagingErrorCode();
+ if (error == MessagingErrorCode.INVALID_ARGUMENT || error == MessagingErrorCode.UNREGISTERED) {
+ failedTokens.add(registrationTokens.get(index));
+ }
+ LOGGER.warn("Firebase user {} error", user.getId(), response.getException());
+ }
+ }
+ if (!failedTokens.isEmpty()) {
+ registrationTokens.removeAll(failedTokens);
+ if (registrationTokens.isEmpty()) {
+ user.getAttributes().remove("notificationTokens");
+ } else {
+ user.set("notificationTokens", String.join(",", registrationTokens));
}
+ storage.updateObject(user, new Request(
+ new Columns.Include("attributes"),
+ new Condition.Equals("id", user.getId())));
+ cacheManager.invalidateObject(true, User.class, user.getId(), ObjectOperation.UPDATE);
}
- } catch (FirebaseMessagingException e) {
- throw new MessageException(e);
+ } catch (Exception e) {
+ LOGGER.warn("Firebase error", e);
}
}
}