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; import com.google.firebase.FirebaseOptions; import com.google.firebase.messaging.FirebaseMessaging; import com.google.firebase.messaging.Message; import com.google.firebase.messaging.Notification; import im.rosetta.database.repository.UserRepository; import im.rosetta.service.services.UserService; /** * Класс для отправки push-уведомлений пользователям через Firebase Cloud Messaging (FCM). */ public class FirebaseDispatcher { private UserRepository userRepository = new UserRepository(); private UserService userService = new UserService(userRepository); private final ExecutorService executor = Executors.newFixedThreadPool(10); public FirebaseDispatcher() { initializeFirebase(); } /** * Инициализация Firebase Admin SDK */ private void initializeFirebase() { if (FirebaseApp.getApps().isEmpty()) { try { String firebaseCredentialsPath = System.getenv("FIREBASE_CREDENTIALS_PATH"); if (firebaseCredentialsPath == null || firebaseCredentialsPath.isEmpty()) { throw new IllegalStateException("FIREBASE_CREDENTIALS_PATH environment variable is not set"); } FileInputStream serviceAccount = new FileInputStream(firebaseCredentialsPath); FirebaseOptions options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.fromStream(serviceAccount)) .build(); FirebaseApp.initializeApp(options); } catch (IOException e) { throw new RuntimeException("Failed to initialize Firebase", e); } } } /** * Отправляет push-уведомление пользователю с данным публичным ключом (асинхронно) * @param publicKey публичный ключ пользователя * @param title заголовок уведомления * @param messageText текст уведомления */ public void sendPushNotification(String publicKey, String title, String messageText) { executor.submit(() -> { 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) { // Логирование ошибки } }); } /** * Отправляет push-уведомление нескольким пользователям (асинхронно) * @param publicKeys список публичных ключей пользователей * @param title заголовок уведомления * @param messageText текст уведомления */ public void sendPushNotification(List publicKeys, String title, String 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(); } }