package space.luminic.budgerapp.services import com.interaso.webpush.VapidKeys import com.interaso.webpush.WebPushService import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.slf4j.LoggerFactory import org.springframework.dao.DuplicateKeyException import org.springframework.stereotype.Service import reactor.core.publisher.Mono import space.luminic.budgerapp.models.PushMessage import space.luminic.budgerapp.models.Subscription import space.luminic.budgerapp.models.SubscriptionDTO import space.luminic.budgerapp.models.User import space.luminic.budgerapp.repos.SubscriptionRepo import space.luminic.budgerapp.services.VapidConstants.VAPID_PRIVATE_KEY import space.luminic.budgerapp.services.VapidConstants.VAPID_PUBLIC_KEY import space.luminic.budgerapp.services.VapidConstants.VAPID_SUBJECT object VapidConstants { const val VAPID_PUBLIC_KEY = "BKmMyBUhpkcmzYWcYsjH_spqcy0zf_8eVtZo60f7949TgLztCmv3YD0E_vtV2dTfECQ4sdLdPK3ICDcyOkCqr84" const val VAPID_PRIVATE_KEY = "YeJH_0LhnVYN6RdxMidgR6WMYlpGXTJS3HjT9V3NSGI" const val VAPID_SUBJECT = "mailto:voroninvyu@gmail.com" } @Service class SubscriptionService(private val subscriptionRepo: SubscriptionRepo) { private val logger = LoggerFactory.getLogger(javaClass) private val pushService = WebPushService( subject = VAPID_SUBJECT, vapidKeys = VapidKeys.fromUncompressedBytes(VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY) ) fun sendNotification(endpoint: String, p256dh: String, auth: String, payload: PushMessage): Mono { return Mono.fromRunnable { pushService.send( payload = Json.encodeToString(payload), endpoint = endpoint, p256dh = p256dh, auth = auth ) } .doOnSuccess { logger.info("Уведомление успешно отправлено на endpoint: $endpoint") } .doOnError { e -> logger.error("Ошибка при отправке уведомления на endpoint $endpoint: ${e.message}") } .onErrorResume { e -> Mono.error(e) // Пробрасываем ошибку дальше, если нужна обработка выше } } fun sendToAll(payload: PushMessage): Mono> { return subscriptionRepo.findAll() .flatMap { sub -> sendNotification(sub.endpoint, sub.p256dh, sub.auth, payload) .then(Mono.just("${sub.user?.username} at endpoint ${sub.endpoint}")) .onErrorResume { e -> sub.isActive = false subscriptionRepo.save(sub).then(Mono.empty()) } } .collectList() // Собираем результаты в список } fun subscribe(subscriptionDTO: SubscriptionDTO, user: User): Mono { val subscription = Subscription( id = null, user = user, endpoint = subscriptionDTO.endpoint, auth = subscriptionDTO.keys["auth"].orEmpty(), p256dh = subscriptionDTO.keys["p256dh"].orEmpty(), isActive = true ) return subscriptionRepo.save(subscription) .flatMap { savedSubscription -> Mono.just("Subscription created with ID: ${savedSubscription.id}") } .onErrorResume(DuplicateKeyException::class.java) { logger.info("Subscription already exists. Skipping.") Mono.just("Subscription already exists. Skipping.") } .onErrorResume { e -> logger.error("Error while saving subscription: ${e.message}") Mono.error(RuntimeException("Error while saving subscription")) } } }