diff options
Diffstat (limited to 'src/main/java/org/traccar/notificators/NotificatorFirebase.java')
-rw-r--r-- | src/main/java/org/traccar/notificators/NotificatorFirebase.java | 87 |
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); } } } |