From c8fdaa6d7c0dd70f445d93d3ad795eeefbb5368a Mon Sep 17 00:00:00 2001 From: RoyceDa Date: Wed, 25 Feb 2026 19:35:41 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC=D0=B0=20?= =?UTF-8?q?=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20FCM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/Dockerfile b/build/Dockerfile index cabc99c..104d3b0 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -4,6 +4,10 @@ WORKDIR /app # Копируем готовый JAR со всеми зависимостями COPY app.jar ./app.jar +# Копируем файл с переменными окружения +COPY .env ./.env +# Копируем файл с учётными данными для Firebase +COPY serviceAccount.json ./serviceAccount.json # Открываем порт (может быть переопределён через ENV) EXPOSE ${PORT:-3000} From b7535d76642afd2a235f0694e09c136e2f159995 Mon Sep 17 00:00:00 2001 From: RoyceDa Date: Wed, 25 Feb 2026 19:44:38 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=D0=9D=D0=BE=D0=B2=D0=B0=D1=8F=20=D1=81?= =?UTF-8?q?=D0=B8=D1=81=D1=82=D0=B5=D0=BC=D0=B0=20=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B8=20=D0=B8=D0=B7=D0=B1=D0=B5=D0=B6=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B1=D0=BB=D0=BE=D0=BA=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BE=D0=BA=20=D0=BF=D1=80=D0=B8=20=D0=BE=D1=82=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BA=D0=B5=20=D1=83=D0=B2=D0=B5=D0=B4=D0=BE?= =?UTF-8?q?=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/Dockerfile | 8 +- .../service/dispatch/FirebaseDispatcher.java | 87 ++++++++++++++----- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index 104d3b0..a4f79eb 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -2,12 +2,8 @@ FROM eclipse-temurin:21-jre-alpine WORKDIR /app -# Копируем готовый JAR со всеми зависимостями -COPY app.jar ./app.jar -# Копируем файл с переменными окружения -COPY .env ./.env -# Копируем файл с учётными данными для Firebase -COPY serviceAccount.json ./serviceAccount.json +# Копируем рабочую директорию +COPY . . # Открываем порт (может быть переопределён через ENV) EXPOSE ${PORT:-3000} diff --git a/src/main/java/im/rosetta/service/dispatch/FirebaseDispatcher.java b/src/main/java/im/rosetta/service/dispatch/FirebaseDispatcher.java index 2ffac92..f0fa523 100644 --- a/src/main/java/im/rosetta/service/dispatch/FirebaseDispatcher.java +++ b/src/main/java/im/rosetta/service/dispatch/FirebaseDispatcher.java @@ -3,6 +3,8 @@ package im.rosetta.service.dispatch; import java.io.FileInputStream; import java.io.IOException; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import com.google.auth.oauth2.GoogleCredentials; import com.google.firebase.FirebaseApp; @@ -21,6 +23,7 @@ public class FirebaseDispatcher { private UserRepository userRepository = new UserRepository(); private UserService userService = new UserService(userRepository); + private final ExecutorService executor = Executors.newFixedThreadPool(10); public FirebaseDispatcher() { initializeFirebase(); @@ -49,45 +52,85 @@ public class FirebaseDispatcher { } /** - * Отправляет push-уведомление пользователю с данным публичным ключом + * Отправляет push-уведомление пользователю с данным публичным ключом (асинхронно) * @param publicKey публичный ключ пользователя * @param title заголовок уведомления - * @param message текст уведомления + * @param messageText текст уведомления */ public void sendPushNotification(String publicKey, String title, String messageText) { - List tokens = userService.getNotificationsTokens(publicKey); - if (tokens == null || tokens.isEmpty()) { - return; - } - - for (String token : tokens) { + executor.submit(() -> { try { - Message message = Message.builder() - .setNotification(Notification.builder() - .setTitle(title) - .setBody(messageText) - .build()) - .setToken(token) - .build(); + List tokens = userService.getNotificationsTokens(publicKey); + if (tokens == null || tokens.isEmpty()) { + return; + } - String response = FirebaseMessaging.getInstance().send(message); - System.out.println("Successfully sent message: " + response); + for (String token : tokens) { + try { + Message message = Message.builder() + .setNotification(Notification.builder() + .setTitle(title) + .setBody(messageText) + .build()) + .setToken(token) + .build(); + + FirebaseMessaging.getInstance().send(message); + } catch (Exception e) { + // Логирование ошибки + } + } } catch (Exception e) { - System.err.println("Failed to send notification to token: " + token + ", error: " + e.getMessage()); + // Логирование ошибки } - } + }); } /** - * Отправляет push-уведомление нескольким пользователям + * Отправляет push-уведомление нескольким пользователям (асинхронно) * @param publicKeys список публичных ключей пользователей * @param title заголовок уведомления * @param messageText текст уведомления */ public void sendPushNotification(List publicKeys, String title, String messageText) { - for (String publicKey : publicKeys) { - sendPushNotification(publicKey, title, messageText); + executor.submit(() -> { + for (String publicKey : publicKeys) { + sendPushNotificationSync(publicKey, title, messageText); + } + }); + } + + private void sendPushNotificationSync(String publicKey, String title, String messageText) { + try { + List tokens = userService.getNotificationsTokens(publicKey); + if (tokens == null || tokens.isEmpty()) { + return; + } + + for (String token : tokens) { + try { + Message message = Message.builder() + .setNotification(Notification.builder() + .setTitle(title) + .setBody(messageText) + .build()) + .setToken(token) + .build(); + + FirebaseMessaging.getInstance().send(message); + } catch (Exception e) { + // Логирование ошибки + } + } + } catch (Exception e) { + // Логирование ошибки } } + /** + * Завершить работу executor при остановке приложения + */ + public void shutdown() { + executor.shutdown(); + } } \ No newline at end of file