feat(chat): 채팅방 세션 조회 API 구현

This commit is contained in:
Klaus 2025-08-08 15:15:29 +09:00
parent 4d1f84cc5c
commit 830e41dfa3
3 changed files with 100 additions and 7 deletions

View File

@ -7,6 +7,7 @@ import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.member.Member
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
@ -60,4 +61,21 @@ class ChatRoomController(
ApiResponse.ok(response)
}
}
/**
* 세션 상태 조회 API
* - 채팅방 참여 여부 검증
* - 외부 API로 세션 상태 조회 active면 true, 아니면 false 반환
*/
@GetMapping("/{chatRoomId}/session")
fun getChatSessionStatus(
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
@PathVariable chatRoomId: Long
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
if (member.auth == null) throw SodaException("본인인증을 하셔야 합니다.")
val isActive = chatRoomService.isMyRoomSessionActive(member, chatRoomId)
ApiResponse.ok(isActive)
}
}

View File

@ -34,18 +34,20 @@ data class ChatRoomListQueryDto(
)
/**
* 외부 API 채팅 세션 응답 DTO
* 외부 API 채팅 세션 생성 응답 DTO
*/
data class ExternalChatSessionResponse(
data class ExternalChatSessionCreateResponse(
val success: Boolean,
val message: String?,
val data: ExternalChatSessionData?
val data: ExternalChatSessionCreateData?
)
/**
* 외부 API 채팅 세션 데이터 DTO
* 외부 API 채팅 세션 생성 데이터 DTO
* 공통: sessionId, status
* 생성 전용: userId, characterId, character, createdAt
*/
data class ExternalChatSessionData(
data class ExternalChatSessionCreateData(
val sessionId: String,
val userId: String,
val characterId: String,
@ -54,6 +56,24 @@ data class ExternalChatSessionData(
val createdAt: String
)
/**
* 외부 API 채팅 세션 조회 응답 DTO
*/
data class ExternalChatSessionGetResponse(
val success: Boolean,
val message: String?,
val data: ExternalChatSessionGetData?
)
/**
* 외부 API 채팅 세션 조회 데이터 DTO
* 세션 조회에서 사용하는 공통 필드만 포함
*/
data class ExternalChatSessionGetData(
val sessionId: String,
val status: String
)
/**
* 외부 API 캐릭터 데이터 DTO
*/

View File

@ -8,7 +8,8 @@ import kr.co.vividnext.sodalive.chat.room.ParticipantType
import kr.co.vividnext.sodalive.chat.room.dto.ChatRoomListItemDto
import kr.co.vividnext.sodalive.chat.room.dto.ChatRoomListQueryDto
import kr.co.vividnext.sodalive.chat.room.dto.CreateChatRoomResponse
import kr.co.vividnext.sodalive.chat.room.dto.ExternalChatSessionResponse
import kr.co.vividnext.sodalive.chat.room.dto.ExternalChatSessionCreateResponse
import kr.co.vividnext.sodalive.chat.room.dto.ExternalChatSessionGetResponse
import kr.co.vividnext.sodalive.chat.room.repository.CharacterChatMessageRepository
import kr.co.vividnext.sodalive.chat.room.repository.CharacterChatParticipantRepository
import kr.co.vividnext.sodalive.chat.room.repository.CharacterChatRoomRepository
@ -150,7 +151,10 @@ class ChatRoomService(
// 응답 파싱
val objectMapper = ObjectMapper()
val apiResponse = objectMapper.readValue(response.body, ExternalChatSessionResponse::class.java)
val apiResponse = objectMapper.readValue(
response.body,
ExternalChatSessionCreateResponse::class.java
)
// success가 false이면 throw
if (!apiResponse.success) {
@ -195,4 +199,55 @@ class ChatRoomService(
)
}
}
@Transactional(readOnly = true)
fun isMyRoomSessionActive(member: Member, chatRoomId: Long): Boolean {
val room = chatRoomRepository.findById(chatRoomId).orElseThrow {
SodaException("채팅방을 찾을 수 없습니다.")
}
val participant = participantRepository.findByChatRoomAndMemberAndIsActiveTrue(room, member)
if (participant == null) {
throw SodaException("잘못된 접근입니다")
}
return fetchSessionActive(room.sessionId)
}
private fun fetchSessionActive(sessionId: String): Boolean {
try {
val factory = SimpleClientHttpRequestFactory()
factory.setConnectTimeout(20000) // 20초
factory.setReadTimeout(20000) // 20초
val restTemplate = RestTemplate(factory)
val headers = HttpHeaders()
headers.set("x-api-key", apiKey)
val httpEntity = HttpEntity(null, headers)
val response = restTemplate.exchange(
"$apiUrl/api/session/$sessionId",
HttpMethod.GET,
httpEntity,
String::class.java
)
val objectMapper = ObjectMapper()
val apiResponse = objectMapper.readValue(
response.body,
ExternalChatSessionGetResponse::class.java
)
// success가 false이면 throw
if (!apiResponse.success) {
throw SodaException("오류가 발생했습니다. 다시 시도해 주세요.")
}
val status = apiResponse.data?.status
return status == "active"
} catch (e: Exception) {
e.printStackTrace()
throw SodaException("오류가 발생했습니다. 다시 시도해 주세요.")
}
}
}