feat(user-creator-chat): WebSocket 세션 레지스트리를 추가한다

This commit is contained in:
2026-06-18 17:06:32 +09:00
parent fefd62c63a
commit af1e9b565a
2 changed files with 184 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
package kr.co.vividnext.sodalive.v2.usercreatorchat.websocket
import org.springframework.stereotype.Component
import org.springframework.web.socket.WebSocketSession
import java.util.concurrent.ConcurrentHashMap
@Component
class UserCreatorChatWebSocketSessionRegistry {
private val sessionsByRoomMember = ConcurrentHashMap<RoomMemberKey, ConcurrentHashMap<String, WebSocketSession>>()
private val sessionIndexes = ConcurrentHashMap<String, RoomMemberKey>()
private val lockStripes = Array(LOCK_STRIPE_COUNT) { Any() }
fun register(roomId: Long, memberId: Long, session: WebSocketSession) {
val sessionId = session.id
synchronized(lockFor(sessionId)) {
removeLocked(sessionId)
val key = RoomMemberKey(roomId, memberId)
sessionsByRoomMember.computeIfAbsent(key) { ConcurrentHashMap() }[sessionId] = session
sessionIndexes[sessionId] = key
}
}
fun findSessions(roomId: Long, memberId: Long): List<WebSocketSession> {
return sessionsByRoomMember[RoomMemberKey(roomId, memberId)]?.values?.toList() ?: emptyList()
}
fun remove(sessionId: String) {
synchronized(lockFor(sessionId)) {
removeLocked(sessionId)
}
}
private fun removeLocked(sessionId: String) {
val key = sessionIndexes.remove(sessionId) ?: return
val sessions = sessionsByRoomMember[key] ?: return
sessions.remove(sessionId)
if (sessions.isEmpty()) {
sessionsByRoomMember.remove(key, sessions)
}
}
private fun lockFor(sessionId: String): Any {
return lockStripes[Math.floorMod(sessionId.hashCode(), lockStripes.size)]
}
private data class RoomMemberKey(
val roomId: Long,
val memberId: Long
)
companion object {
private const val LOCK_STRIPE_COUNT = 64
}
}