Add SSE for Razorpay QR events
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s
This commit is contained in:
@@ -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
|
||||||
|
)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.android.trisolarisserver.controller
|
package com.android.trisolarisserver.controller
|
||||||
|
|
||||||
import com.android.trisolarisserver.component.PropertyAccess
|
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.RazorpayQrGenerateRequest
|
||||||
import com.android.trisolarisserver.controller.dto.RazorpayQrEventResponse
|
import com.android.trisolarisserver.controller.dto.RazorpayQrEventResponse
|
||||||
import com.android.trisolarisserver.controller.dto.RazorpayQrGenerateResponse
|
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.web.server.ResponseStatusException
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
import java.util.Base64
|
import java.util.Base64
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -42,6 +44,7 @@ class RazorpayQrPayments(
|
|||||||
private val settingsRepo: RazorpaySettingsRepo,
|
private val settingsRepo: RazorpaySettingsRepo,
|
||||||
private val qrRequestRepo: RazorpayQrRequestRepo,
|
private val qrRequestRepo: RazorpayQrRequestRepo,
|
||||||
private val webhookLogRepo: RazorpayWebhookLogRepo,
|
private val webhookLogRepo: RazorpayWebhookLogRepo,
|
||||||
|
private val qrEvents: RazorpayQrEvents,
|
||||||
private val restTemplate: RestTemplate,
|
private val restTemplate: RestTemplate,
|
||||||
private val objectMapper: ObjectMapper
|
private val objectMapper: ObjectMapper
|
||||||
) {
|
) {
|
||||||
@@ -259,6 +262,17 @@ class RazorpayQrPayments(
|
|||||||
return out
|
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")
|
@GetMapping("/qr")
|
||||||
fun listQr(
|
fun listQr(
|
||||||
@PathVariable propertyId: UUID,
|
@PathVariable propertyId: UUID,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import com.android.trisolarisserver.models.booking.Payment
|
|||||||
import com.android.trisolarisserver.models.booking.PaymentMethod
|
import com.android.trisolarisserver.models.booking.PaymentMethod
|
||||||
import com.android.trisolarisserver.models.payment.RazorpayPaymentAttempt
|
import com.android.trisolarisserver.models.payment.RazorpayPaymentAttempt
|
||||||
import com.android.trisolarisserver.models.payment.RazorpayWebhookLog
|
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.PaymentRepo
|
||||||
import com.android.trisolarisserver.repo.PropertyRepo
|
import com.android.trisolarisserver.repo.PropertyRepo
|
||||||
import com.android.trisolarisserver.repo.RazorpayPaymentAttemptRepo
|
import com.android.trisolarisserver.repo.RazorpayPaymentAttemptRepo
|
||||||
@@ -37,6 +39,7 @@ class RazorpayWebhookCapture(
|
|||||||
private val razorpayPaymentAttemptRepo: RazorpayPaymentAttemptRepo,
|
private val razorpayPaymentAttemptRepo: RazorpayPaymentAttemptRepo,
|
||||||
private val razorpayQrRequestRepo: RazorpayQrRequestRepo,
|
private val razorpayQrRequestRepo: RazorpayQrRequestRepo,
|
||||||
private val razorpayWebhookLogRepo: RazorpayWebhookLogRepo,
|
private val razorpayWebhookLogRepo: RazorpayWebhookLogRepo,
|
||||||
|
private val razorpayQrEvents: RazorpayQrEvents,
|
||||||
private val objectMapper: ObjectMapper
|
private val objectMapper: ObjectMapper
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -102,6 +105,16 @@ class RazorpayWebhookCapture(
|
|||||||
razorpayQrRequestRepo.save(existingQr)
|
razorpayQrRequestRepo.save(existingQr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
razorpayQrEvents.emit(
|
||||||
|
propertyId,
|
||||||
|
qrId,
|
||||||
|
RazorpayQrEventResponse(
|
||||||
|
event = event,
|
||||||
|
qrId = qrId,
|
||||||
|
status = qrStatus,
|
||||||
|
receivedAt = OffsetDateTime.now().toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
razorpayPaymentAttemptRepo.save(
|
razorpayPaymentAttemptRepo.save(
|
||||||
|
|||||||
Reference in New Issue
Block a user