This commit is contained in:
xds
2025-10-31 15:31:55 +03:00
parent 040da34ff7
commit 7972ea0fdf
117 changed files with 3691 additions and 2013 deletions

View File

@@ -1,113 +1,111 @@
package space.luminic.finance.services
import com.interaso.webpush.VapidKeys
import com.interaso.webpush.WebPushService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.reactive.awaitSingle
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.bson.types.ObjectId
import org.slf4j.LoggerFactory
import org.springframework.dao.DuplicateKeyException
import org.springframework.stereotype.Service
import space.luminic.finance.models.PushMessage
import space.luminic.finance.models.Subscription
import space.luminic.finance.models.SubscriptionDTO
import space.luminic.finance.models.User
import space.luminic.finance.repos.SubscriptionRepo
import space.luminic.finance.services.VapidConstants.VAPID_PRIVATE_KEY
import space.luminic.finance.services.VapidConstants.VAPID_PUBLIC_KEY
import space.luminic.finance.services.VapidConstants.VAPID_SUBJECT
import kotlin.collections.forEach
import kotlin.jvm.javaClass
import kotlin.text.orEmpty
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)
)
suspend fun sendToSpaceOwner(ownerId: String, message: PushMessage) = coroutineScope {
val ownerTokens = subscriptionRepo.findByUserIdAndIsActive(ObjectId(ownerId)).collectList().awaitSingle()
ownerTokens.forEach { token ->
launch(Dispatchers.IO) { // Теперь мы точно в корутин скоупе
try {
sendNotification(token.endpoint, token.p256dh, token.auth, message)
} catch (e: Exception) {
logger.error("Ошибка при отправке уведомления: ${e.message}", e)
}
}
}
}
suspend fun sendNotification(endpoint: String, p256dh: String, auth: String, payload: PushMessage) {
try {
pushService.send(
payload = Json.encodeToString(payload),
endpoint = endpoint,
p256dh = p256dh,
auth = auth
)
logger.info("Уведомление успешно отправлено на endpoint: $endpoint")
} catch (e: Exception) {
logger.error("Ошибка при отправке уведомления на endpoint $endpoint: ${e.message}")
throw e
}
}
suspend fun sendToAll(payload: PushMessage) {
subscriptionRepo.findAll().collectList().awaitSingle().forEach { sub ->
try {
sendNotification(sub.endpoint, sub.p256dh, sub.auth, payload)
} catch (e: Exception) {
sub.isActive = false
subscriptionRepo.save(sub).awaitSingle()
}
}
}
suspend fun subscribe(subscriptionDTO: SubscriptionDTO, user: User): String {
val subscription = Subscription(
id = null,
user = user,
endpoint = subscriptionDTO.endpoint,
auth = subscriptionDTO.keys["auth"].orEmpty(),
p256dh = subscriptionDTO.keys["p256dh"].orEmpty(),
isActive = true
)
return try {
val savedSubscription = subscriptionRepo.save(subscription).awaitSingle()
"Subscription created with ID: ${savedSubscription.id}"
} catch (e: DuplicateKeyException) {
logger.info("Subscription already exists. Skipping.")
"Subscription already exists. Skipping."
} catch (e: Exception) {
logger.error("Error while saving subscription: ${e.message}")
throw kotlin.RuntimeException("Error while saving subscription")
}
}
}
//package space.luminic.finance.services
//
//
//import com.interaso.webpush.VapidKeys
//import com.interaso.webpush.WebPushService
//import kotlinx.coroutines.Dispatchers
//import kotlinx.coroutines.coroutineScope
//import kotlinx.coroutines.launch
//import kotlinx.coroutines.reactive.awaitSingle
//import kotlinx.serialization.encodeToString
//import kotlinx.serialization.json.Json
//import org.slf4j.LoggerFactory
//import org.springframework.dao.DuplicateKeyException
//import org.springframework.stereotype.Service
//import space.luminic.finance.models.PushMessage
//import space.luminic.finance.models.Subscription
//import space.luminic.finance.models.User
//import space.luminic.finance.repos.SubscriptionRepo
//import space.luminic.finance.services.VapidConstants.VAPID_PRIVATE_KEY
//import space.luminic.finance.services.VapidConstants.VAPID_PUBLIC_KEY
//import space.luminic.finance.services.VapidConstants.VAPID_SUBJECT
//import kotlin.collections.forEach
//import kotlin.jvm.javaClass
//import kotlin.text.orEmpty
//
//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)
// )
//
//
// suspend fun sendToSpaceOwner(ownerId: String, message: PushMessage) = coroutineScope {
// val ownerTokens = subscriptionRepo.findByUserIdAndIsActive(ObjectId(ownerId)).collectList().awaitSingle()
//
// ownerTokens.forEach { token ->
// launch(Dispatchers.IO) { // Теперь мы точно в корутин скоупе
// try {
// sendNotification(token.endpoint, token.p256dh, token.auth, message)
// } catch (e: Exception) {
// logger.error("Ошибка при отправке уведомления: ${e.message}", e)
// }
// }
// }
// }
//
//
// suspend fun sendNotification(endpoint: String, p256dh: String, auth: String, payload: PushMessage) {
// try {
// pushService.send(
// payload = Json.encodeToString(payload),
// endpoint = endpoint,
// p256dh = p256dh,
// auth = auth
// )
// logger.info("Уведомление успешно отправлено на endpoint: $endpoint")
//
// } catch (e: Exception) {
// logger.error("Ошибка при отправке уведомления на endpoint $endpoint: ${e.message}")
// throw e
// }
// }
//
//
// suspend fun sendToAll(payload: PushMessage) {
//
// subscriptionRepo.findAll().collectList().awaitSingle().forEach { sub ->
//
// try {
// sendNotification(sub.endpoint, sub.p256dh, sub.auth, payload)
// } catch (e: Exception) {
// sub.isActive = false
// subscriptionRepo.save(sub).awaitSingle()
// }
// }
// }
//
//
// suspend fun subscribe(subscriptionDTO: SubscriptionDTO, user: User): String {
// val subscription = Subscription(
// id = null,
// user = user,
// endpoint = subscriptionDTO.endpoint,
// auth = subscriptionDTO.keys["auth"].orEmpty(),
// p256dh = subscriptionDTO.keys["p256dh"].orEmpty(),
// isActive = true
// )
//
// return try {
// val savedSubscription = subscriptionRepo.save(subscription).awaitSingle()
// "Subscription created with ID: ${savedSubscription.id}"
// } catch (e: DuplicateKeyException) {
// logger.info("Subscription already exists. Skipping.")
// "Subscription already exists. Skipping."
// } catch (e: Exception) {
// logger.error("Error while saving subscription: ${e.message}")
// throw kotlin.RuntimeException("Error while saving subscription")
// }
// }
//}