From 1d1fc57b3dd44013bd467a825b970ac06749e125 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Mar 2023 17:53:19 -0700 Subject: Handle Firebase failures --- .../traccar/notificators/NotificatorFirebase.java | 52 +++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) (limited to 'src/main/java/org/traccar/notificators') diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index 9fa2ebaf3..d80354d7d 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -25,7 +25,10 @@ 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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; @@ -34,24 +37,40 @@ import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; +import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +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 { + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class); + private final NotificationFormatter notificationFormatter; + 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; + this.storage = storage; + this.cacheManager = cacheManager; InputStream serviceAccount = new ByteArrayInputStream( config.getString(Keys.NOTIFICATOR_FIREBASE_SERVICE_ACCOUNT).getBytes()); @@ -69,7 +88,8 @@ public class NotificatorFirebase implements Notificator { var shortMessage = notificationFormatter.formatMessage(user, event, position, "short"); - List registrationTokens = Arrays.asList(user.getString("notificationTokens").split("[, ]")); + List registrationTokens = new ArrayList<>( + Arrays.asList(user.getString("notificationTokens").split("[, ]"))); MulticastMessage message = MulticastMessage.builder() .setNotification(com.google.firebase.messaging.Notification.builder() @@ -92,13 +112,33 @@ public class NotificatorFirebase implements Notificator { try { var result = FirebaseMessaging.getInstance().sendMulticast(message); - for (var response : result.getResponses()) { + List 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.updateOrInvalidate(true, user); } - } catch (FirebaseMessagingException e) { - throw new MessageException(e); + } catch (FirebaseMessagingException | StorageException e) { + LOGGER.warn("Firebase error", e); } } } -- cgit v1.2.3