Add SSE for Razorpay QR events
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s

This commit is contained in:
androidlover5842
2026-02-01 12:22:16 +05:30
parent c74944711e
commit 35b15f37ec
3 changed files with 75 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
package com.android.trisolarisserver.component
import com.android.trisolarisserver.controller.dto.RazorpayQrEventResponse
import com.android.trisolarisserver.repo.RazorpayQrRequestRepo
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter
import java.time.OffsetDateTime
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
@Component
class RazorpayQrEvents(
private val qrRequestRepo: RazorpayQrRequestRepo
) {
private val latestEvents: MutableMap<QrKey, RazorpayQrEventResponse> = ConcurrentHashMap()
private val hub = SseHub<QrKey>("qr") { key ->
latestEvents[key] ?: run {
val latest = qrRequestRepo.findTopByQrIdOrderByCreatedAtDesc(key.qrId)
RazorpayQrEventResponse(
event = "snapshot",
qrId = key.qrId,
status = latest?.status,
receivedAt = (latest?.createdAt ?: OffsetDateTime.now()).toString()
)
}
}
fun subscribe(propertyId: UUID, qrId: String): SseEmitter {
return hub.subscribe(QrKey(propertyId, qrId))
}
fun emit(propertyId: UUID, qrId: String, event: RazorpayQrEventResponse) {
val key = QrKey(propertyId, qrId)
latestEvents[key] = event
hub.emit(key)
}
@Scheduled(fixedDelayString = "25000")
fun heartbeat() {
hub.heartbeat()
}
}
private data class QrKey(
val propertyId: UUID,
val qrId: String
)

View File

@@ -1,6 +1,7 @@
package com.android.trisolarisserver.controller
import com.android.trisolarisserver.component.PropertyAccess
import com.android.trisolarisserver.component.RazorpayQrEvents
import com.android.trisolarisserver.controller.dto.RazorpayQrGenerateRequest
import com.android.trisolarisserver.controller.dto.RazorpayQrEventResponse
import com.android.trisolarisserver.controller.dto.RazorpayQrGenerateResponse
@@ -30,6 +31,7 @@ import org.springframework.web.client.RestTemplate
import org.springframework.web.server.ResponseStatusException
import org.springframework.http.HttpStatus
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter
import java.time.OffsetDateTime
import java.util.Base64
import java.util.UUID
@@ -42,6 +44,7 @@ class RazorpayQrPayments(
private val settingsRepo: RazorpaySettingsRepo,
private val qrRequestRepo: RazorpayQrRequestRepo,
private val webhookLogRepo: RazorpayWebhookLogRepo,
private val qrEvents: RazorpayQrEvents,
private val restTemplate: RestTemplate,
private val objectMapper: ObjectMapper
) {
@@ -259,6 +262,17 @@ class RazorpayQrPayments(
return out
}
@GetMapping("/qr/{qrId}/events/stream", produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
fun streamQrEvents(
@PathVariable propertyId: UUID,
@PathVariable bookingId: UUID,
@PathVariable qrId: String,
@AuthenticationPrincipal principal: MyPrincipal?
): SseEmitter {
requireRole(propertyAccess, propertyId, principal, Role.ADMIN, Role.MANAGER, Role.STAFF)
return qrEvents.subscribe(propertyId, qrId)
}
@GetMapping("/qr")
fun listQr(
@PathVariable propertyId: UUID,

View File

@@ -5,6 +5,8 @@ import com.android.trisolarisserver.models.booking.Payment
import com.android.trisolarisserver.models.booking.PaymentMethod
import com.android.trisolarisserver.models.payment.RazorpayPaymentAttempt
import com.android.trisolarisserver.models.payment.RazorpayWebhookLog
import com.android.trisolarisserver.component.RazorpayQrEvents
import com.android.trisolarisserver.controller.dto.RazorpayQrEventResponse
import com.android.trisolarisserver.repo.PaymentRepo
import com.android.trisolarisserver.repo.PropertyRepo
import com.android.trisolarisserver.repo.RazorpayPaymentAttemptRepo
@@ -37,6 +39,7 @@ class RazorpayWebhookCapture(
private val razorpayPaymentAttemptRepo: RazorpayPaymentAttemptRepo,
private val razorpayQrRequestRepo: RazorpayQrRequestRepo,
private val razorpayWebhookLogRepo: RazorpayWebhookLogRepo,
private val razorpayQrEvents: RazorpayQrEvents,
private val objectMapper: ObjectMapper
) {
@@ -102,6 +105,16 @@ class RazorpayWebhookCapture(
razorpayQrRequestRepo.save(existingQr)
}
}
razorpayQrEvents.emit(
propertyId,
qrId,
RazorpayQrEventResponse(
event = event,
qrId = qrId,
status = qrStatus,
receivedAt = OffsetDateTime.now().toString()
)
)
}
razorpayPaymentAttemptRepo.save(