This commit is contained in:
Vladimir Voronin
2025-01-07 12:35:17 +03:00
commit afd8e9f6d7
72 changed files with 4606 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
package space.luminic.budgerapp.services
import com.interaso.webpush.VapidKeys
import com.interaso.webpush.WebPushService
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString
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
import java.security.GeneralSecurityException
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<Void> {
return Mono.fromRunnable<Void> {
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<List<String>> {
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<String> {
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"))
}
}
}