Disable buffering on SSE endpoints
All checks were successful
build-and-deploy / build-deploy (push) Successful in 34s

This commit is contained in:
androidlover5842
2026-02-01 13:57:20 +05:30
parent 42d91cc09a
commit ab2330b593
4 changed files with 31 additions and 3 deletions

View File

@@ -32,6 +32,7 @@ import com.android.trisolarisserver.repo.PropertyRepo
import com.android.trisolarisserver.repo.RoomRepo import com.android.trisolarisserver.repo.RoomRepo
import com.android.trisolarisserver.repo.RoomStayRepo import com.android.trisolarisserver.repo.RoomStayRepo
import com.android.trisolarisserver.security.MyPrincipal import com.android.trisolarisserver.security.MyPrincipal
import jakarta.servlet.http.HttpServletResponse
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.annotation.Transactional
@@ -248,7 +249,8 @@ class BookingFlow(
fun streamBooking( fun streamBooking(
@PathVariable propertyId: UUID, @PathVariable propertyId: UUID,
@PathVariable bookingId: UUID, @PathVariable bookingId: UUID,
@AuthenticationPrincipal principal: MyPrincipal? @AuthenticationPrincipal principal: MyPrincipal?,
response: HttpServletResponse
): org.springframework.web.servlet.mvc.method.annotation.SseEmitter { ): org.springframework.web.servlet.mvc.method.annotation.SseEmitter {
requireRole( requireRole(
propertyAccess, propertyAccess,
@@ -261,6 +263,7 @@ class BookingFlow(
Role.FINANCE Role.FINANCE
) )
requireBooking(propertyId, bookingId) requireBooking(propertyId, bookingId)
prepareSse(response)
return bookingEvents.subscribe(propertyId, bookingId) return bookingEvents.subscribe(propertyId, bookingId)
} }
@@ -725,4 +728,10 @@ class BookingFlow(
return true return true
} }
private fun prepareSse(response: HttpServletResponse) {
response.setHeader("Cache-Control", "no-cache")
response.setHeader("Connection", "keep-alive")
response.setHeader("X-Accel-Buffering", "no")
}
} }

View File

@@ -138,6 +138,7 @@ class GuestDocuments(
): org.springframework.web.servlet.mvc.method.annotation.SseEmitter { ): org.springframework.web.servlet.mvc.method.annotation.SseEmitter {
requireRole(propertyAccess, propertyId, principal, Role.ADMIN, Role.MANAGER) requireRole(propertyAccess, propertyId, principal, Role.ADMIN, Role.MANAGER)
response.setHeader("Cache-Control", "no-cache") response.setHeader("Cache-Control", "no-cache")
response.setHeader("Connection", "keep-alive")
response.setHeader("X-Accel-Buffering", "no") response.setHeader("X-Accel-Buffering", "no")
return guestDocumentEvents.subscribe(propertyId, guestId) return guestDocumentEvents.subscribe(propertyId, guestId)
} }

View File

@@ -15,6 +15,7 @@ import com.android.trisolarisserver.repo.RazorpaySettingsRepo
import com.android.trisolarisserver.repo.RazorpayWebhookLogRepo import com.android.trisolarisserver.repo.RazorpayWebhookLogRepo
import com.android.trisolarisserver.security.MyPrincipal import com.android.trisolarisserver.security.MyPrincipal
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import jakarta.servlet.http.HttpServletResponse
import org.springframework.http.HttpEntity import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod import org.springframework.http.HttpMethod
@@ -267,12 +268,20 @@ class RazorpayQrPayments(
@PathVariable propertyId: UUID, @PathVariable propertyId: UUID,
@PathVariable bookingId: UUID, @PathVariable bookingId: UUID,
@PathVariable qrId: String, @PathVariable qrId: String,
@AuthenticationPrincipal principal: MyPrincipal? @AuthenticationPrincipal principal: MyPrincipal?,
response: HttpServletResponse
): SseEmitter { ): SseEmitter {
requireRole(propertyAccess, propertyId, principal, Role.ADMIN, Role.MANAGER, Role.STAFF) requireRole(propertyAccess, propertyId, principal, Role.ADMIN, Role.MANAGER, Role.STAFF)
prepareSse(response)
return qrEvents.subscribe(propertyId, qrId) return qrEvents.subscribe(propertyId, qrId)
} }
private fun prepareSse(response: HttpServletResponse) {
response.setHeader("Cache-Control", "no-cache")
response.setHeader("Connection", "keep-alive")
response.setHeader("X-Accel-Buffering", "no")
}
@GetMapping("/qr") @GetMapping("/qr")
fun listQr( fun listQr(
@PathVariable propertyId: UUID, @PathVariable propertyId: UUID,

View File

@@ -22,6 +22,7 @@ import com.android.trisolarisserver.models.room.Room
import com.android.trisolarisserver.models.room.RatePlan import com.android.trisolarisserver.models.room.RatePlan
import com.android.trisolarisserver.models.property.Role import com.android.trisolarisserver.models.property.Role
import com.android.trisolarisserver.security.MyPrincipal import com.android.trisolarisserver.security.MyPrincipal
import jakarta.servlet.http.HttpServletResponse
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.GetMapping
@@ -109,10 +110,12 @@ class Rooms(
@GetMapping("/board/stream") @GetMapping("/board/stream")
fun roomBoardStream( fun roomBoardStream(
@PathVariable propertyId: UUID, @PathVariable propertyId: UUID,
@AuthenticationPrincipal principal: MyPrincipal? @AuthenticationPrincipal principal: MyPrincipal?,
response: HttpServletResponse
): SseEmitter { ): SseEmitter {
requirePrincipal(principal) requirePrincipal(principal)
propertyAccess.requireMember(propertyId, principal!!.userId) propertyAccess.requireMember(propertyId, principal!!.userId)
prepareSse(response)
return roomBoardEvents.subscribe(propertyId) return roomBoardEvents.subscribe(propertyId)
} }
@@ -442,6 +445,12 @@ class Rooms(
.groupBy { it.room.id ?: throw IllegalStateException("Room id is null") } .groupBy { it.room.id ?: throw IllegalStateException("Room id is null") }
.mapValues { (_, cards) -> cards.maxBy { it.expiresAt }.expiresAt } .mapValues { (_, cards) -> cards.maxBy { it.expiresAt }.expiresAt }
} }
private fun prepareSse(response: HttpServletResponse) {
response.setHeader("Cache-Control", "no-cache")
response.setHeader("Connection", "keep-alive")
response.setHeader("X-Accel-Buffering", "no")
}
} }
private fun Room.toRoomResponse(tempCardExpiresAt: OffsetDateTime? = null): RoomResponse { private fun Room.toRoomResponse(tempCardExpiresAt: OffsetDateTime? = null): RoomResponse {