diff --git a/backend/src/main/java/io/f1/backend/domain/auth/dto/CurrentUserAndAdminResponse.java b/backend/src/main/java/io/f1/backend/domain/auth/dto/CurrentUserAndAdminResponse.java index 1df1ccaa..d8579951 100644 --- a/backend/src/main/java/io/f1/backend/domain/auth/dto/CurrentUserAndAdminResponse.java +++ b/backend/src/main/java/io/f1/backend/domain/auth/dto/CurrentUserAndAdminResponse.java @@ -3,21 +3,19 @@ import io.f1.backend.domain.admin.dto.AdminPrincipal; import io.f1.backend.domain.user.dto.UserPrincipal; -public record CurrentUserAndAdminResponse(Long id, String name, String role, String providerId) { +public record CurrentUserAndAdminResponse(Long id, String name, String role) { public static CurrentUserAndAdminResponse from(UserPrincipal userPrincipal) { return new CurrentUserAndAdminResponse( userPrincipal.getUserId(), userPrincipal.getUserNickname(), - UserPrincipal.ROLE_USER, - userPrincipal.getName()); + UserPrincipal.ROLE_USER); } public static CurrentUserAndAdminResponse from(AdminPrincipal adminPrincipal) { return new CurrentUserAndAdminResponse( adminPrincipal.getAuthenticationAdmin().adminId(), adminPrincipal.getUsername(), - AdminPrincipal.ROLE_ADMIN, - null); + AdminPrincipal.ROLE_ADMIN); } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/ChatService.java b/backend/src/main/java/io/f1/backend/domain/game/app/ChatService.java index 00df3de1..ae6df69f 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/ChatService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/ChatService.java @@ -30,7 +30,7 @@ public void chat(Long roomId, String sessionId, ChatMessage chatMessage) { String destination = getDestination(roomId); - messageSender.send(destination, MessageType.CHAT, chatMessage); + messageSender.sendBroadcast(destination, MessageType.CHAT, chatMessage); if (!room.isPlaying()) { return; diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java index f378b24b..72fd186e 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/GameService.java @@ -1,6 +1,13 @@ package io.f1.backend.domain.game.app; -import static io.f1.backend.domain.game.mapper.RoomMapper.*; +import static io.f1.backend.domain.game.mapper.RoomMapper.ofPlayerEvent; +import static io.f1.backend.domain.game.mapper.RoomMapper.toGameResultListResponse; +import static io.f1.backend.domain.game.mapper.RoomMapper.toGameSettingResponse; +import static io.f1.backend.domain.game.mapper.RoomMapper.toPlayerListResponse; +import static io.f1.backend.domain.game.mapper.RoomMapper.toQuestionResultResponse; +import static io.f1.backend.domain.game.mapper.RoomMapper.toQuestionStartResponse; +import static io.f1.backend.domain.game.mapper.RoomMapper.toRankUpdateResponse; +import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomSettingResponse; import static io.f1.backend.domain.game.websocket.WebSocketUtils.getDestination; import static io.f1.backend.domain.quiz.mapper.QuizMapper.toGameStartResponse; @@ -75,9 +82,11 @@ public void gameStart(Long roomId, UserPrincipal principal) { timerService.startTimer(room, START_DELAY); - messageSender.send(destination, MessageType.GAME_START, toGameStartResponse(questions)); - messageSender.send(destination, MessageType.RANK_UPDATE, toRankUpdateResponse(room)); - messageSender.send( + messageSender.sendBroadcast( + destination, MessageType.GAME_START, toGameStartResponse(questions)); + messageSender.sendBroadcast( + destination, MessageType.RANK_UPDATE, toRankUpdateResponse(room)); + messageSender.sendBroadcast( destination, MessageType.QUESTION_START, toQuestionStartResponse(room, START_DELAY)); @@ -95,12 +104,13 @@ public void onCorrectAnswer(GameCorrectAnswerEvent event) { room.increasePlayerCorrectCount(sessionId); - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.QUESTION_RESULT, toQuestionResultResponse(chatMessage.nickname(), answer)); - messageSender.send(destination, MessageType.RANK_UPDATE, toRankUpdateResponse(room)); - messageSender.send( + messageSender.sendBroadcast( + destination, MessageType.RANK_UPDATE, toRankUpdateResponse(room)); + messageSender.sendBroadcast( destination, MessageType.SYSTEM_NOTICE, ofPlayerEvent(chatMessage.nickname(), RoomEventType.CORRECT_ANSWER)); @@ -116,7 +126,7 @@ public void onCorrectAnswer(GameCorrectAnswerEvent event) { // 타이머 추가하기 timerService.startTimer(room, CONTINUE_DELAY); - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.QUESTION_START, toQuestionStartResponse(room, CONTINUE_DELAY)); @@ -127,11 +137,11 @@ public void onTimeout(GameTimeoutEvent event) { Room room = event.room(); String destination = getDestination(room.getId()); - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.QUESTION_RESULT, toQuestionResultResponse(NONE_CORRECT_USER, room.getCurrentQuestion().getAnswer())); - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.SYSTEM_NOTICE, ofPlayerEvent(NONE_CORRECT_USER, RoomEventType.TIMEOUT)); @@ -144,7 +154,7 @@ public void onTimeout(GameTimeoutEvent event) { room.increaseCurrentRound(); timerService.startTimer(room, CONTINUE_DELAY); - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.QUESTION_START, toQuestionStartResponse(room, CONTINUE_DELAY)); @@ -157,7 +167,7 @@ public void gameEnd(Room room) { Map playerSessionMap = room.getPlayerSessionMap(); // TODO : 랭킹 정보 업데이트 - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.GAME_RESULT, toGameResultListResponse(playerSessionMap, room.getGameSetting().getRound())); @@ -170,13 +180,14 @@ public void gameEnd(Room room) { room.updateRoomState(RoomState.WAITING); - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.GAME_SETTING, toGameSettingResponse( room.getGameSetting(), quizService.getQuizWithQuestionsById(room.getGameSetting().getQuizId()))); - messageSender.send(destination, MessageType.ROOM_SETTING, toRoomSettingResponse(room)); + messageSender.sendBroadcast( + destination, MessageType.ROOM_SETTING, toRoomSettingResponse(room)); } public void handlePlayerReady(Long roomId, String sessionId) { @@ -191,7 +202,7 @@ public void handlePlayerReady(Long roomId, String sessionId) { PlayerListResponse playerListResponse = toPlayerListResponse(room); log.info(playerListResponse.toString()); - messageSender.send(destination, MessageType.PLAYER_LIST, playerListResponse); + messageSender.sendBroadcast(destination, MessageType.PLAYER_LIST, playerListResponse); } public void changeGameSetting( @@ -262,7 +273,7 @@ private void toggleReadyIfPossible(Room room, Player player) { private void broadcastGameSetting(Room room) { String destination = getDestination(room.getId()); Quiz quiz = quizService.getQuizWithQuestionsById(room.getGameSetting().getQuizId()); - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.GAME_SETTING, toGameSettingResponse(room.getGameSetting(), quiz)); diff --git a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java index 481989f8..db2a8f96 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/app/RoomService.java @@ -4,7 +4,7 @@ import static io.f1.backend.domain.game.mapper.RoomMapper.toGameSetting; import static io.f1.backend.domain.game.mapper.RoomMapper.toGameSettingResponse; import static io.f1.backend.domain.game.mapper.RoomMapper.toPlayerListResponse; -import static io.f1.backend.domain.game.mapper.RoomMapper.toQuestionStartResponse; +import static io.f1.backend.domain.game.mapper.RoomMapper.toRankUpdateResponse; import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomResponse; import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomSetting; import static io.f1.backend.domain.game.mapper.RoomMapper.toRoomSettingResponse; @@ -17,6 +17,7 @@ import io.f1.backend.domain.game.dto.RoomEventType; import io.f1.backend.domain.game.dto.request.RoomCreateRequest; import io.f1.backend.domain.game.dto.request.RoomValidationRequest; +import io.f1.backend.domain.game.dto.response.ExitSuccessResponse; import io.f1.backend.domain.game.dto.response.GameSettingResponse; import io.f1.backend.domain.game.dto.response.PlayerListResponse; import io.f1.backend.domain.game.dto.response.RoomCreateResponse; @@ -143,10 +144,12 @@ public void initializeRoomSocket(Long roomId, String sessionId, UserPrincipal pr String destination = getDestination(roomId); - messageSender.send(destination, MessageType.ROOM_SETTING, roomSettingResponse); - messageSender.send(destination, MessageType.GAME_SETTING, gameSettingResponse); - messageSender.send(destination, MessageType.PLAYER_LIST, playerListResponse); - messageSender.send(destination, MessageType.SYSTEM_NOTICE, systemNoticeResponse); + messageSender.sendPersonal( + getUserDestination(), MessageType.GAME_SETTING, gameSettingResponse, principal); + + messageSender.sendBroadcast(destination, MessageType.ROOM_SETTING, roomSettingResponse); + messageSender.sendBroadcast(destination, MessageType.PLAYER_LIST, playerListResponse); + messageSender.sendBroadcast(destination, MessageType.SYSTEM_NOTICE, systemNoticeResponse); } public void exitRoom(Long roomId, String sessionId, UserPrincipal principal) { @@ -160,6 +163,12 @@ public void exitRoom(Long roomId, String sessionId, UserPrincipal principal) { String destination = getDestination(roomId); + messageSender.sendPersonal( + getUserDestination(), + MessageType.EXIT_SUCCESS, + new ExitSuccessResponse(true), + principal); + cleanRoom(room, sessionId, removePlayer); SystemNoticeResponse systemNoticeResponse = @@ -167,8 +176,9 @@ public void exitRoom(Long roomId, String sessionId, UserPrincipal principal) { PlayerListResponse playerListResponse = toPlayerListResponse(room); - messageSender.send(destination, MessageType.PLAYER_LIST, playerListResponse); - messageSender.send(destination, MessageType.SYSTEM_NOTICE, systemNoticeResponse); + messageSender.sendBroadcast(destination, MessageType.PLAYER_LIST, playerListResponse); + messageSender.sendBroadcast( + destination, MessageType.SYSTEM_NOTICE, systemNoticeResponse); } } @@ -193,20 +203,30 @@ public void reconnectSession( room.reconnectSession(oldSessionId, newSessionId); String destination = getDestination(roomId); + String userDestination = getUserDestination(); - messageSender.send( + messageSender.sendBroadcast( destination, MessageType.SYSTEM_NOTICE, ofPlayerEvent(principal.getUserNickname(), RoomEventType.RECONNECT)); if (room.isPlaying()) { - // todo 랭킹 리스트 추가 - messageSender.send( - destination, MessageType.GAME_START, toGameStartResponse(room.getQuestions())); - messageSender.send( - destination, - MessageType.QUESTION_START, - toQuestionStartResponse(room, CONTINUE_DELAY)); + messageSender.sendPersonal( + userDestination, + MessageType.SYSTEM_NOTICE, + ofPlayerEvent( + principal.getUserNickname(), RoomEventType.RECONNECT_PRIVATE_NOTICE), + principal); + messageSender.sendPersonal( + userDestination, + MessageType.RANK_UPDATE, + toRankUpdateResponse(room), + principal); + messageSender.sendPersonal( + userDestination, + MessageType.GAME_START, + toGameStartResponse(room.getQuestions()), + principal); } else { RoomSettingResponse roomSettingResponse = toRoomSettingResponse(room); @@ -219,9 +239,12 @@ public void reconnectSession( PlayerListResponse playerListResponse = toPlayerListResponse(room); - messageSender.send(destination, MessageType.ROOM_SETTING, roomSettingResponse); - messageSender.send(destination, MessageType.GAME_SETTING, gameSettingResponse); - messageSender.send(destination, MessageType.PLAYER_LIST, playerListResponse); + messageSender.sendPersonal( + userDestination, MessageType.ROOM_SETTING, roomSettingResponse, principal); + messageSender.sendPersonal( + userDestination, MessageType.PLAYER_LIST, playerListResponse, principal); + messageSender.sendPersonal( + userDestination, MessageType.GAME_SETTING, gameSettingResponse, principal); } } @@ -296,6 +319,10 @@ private void removePlayer(Room room, String sessionId, Player removePlayer) { room.removeValidatedUserId(removePlayer.getId()); } + private String getUserDestination() { + return "/queue"; + } + public void exitRoomForDisconnectedPlayer(Long roomId, Player player, String sessionId) { Object lock = roomLocks.computeIfAbsent(roomId, k -> new Object()); @@ -311,8 +338,10 @@ public void exitRoomForDisconnectedPlayer(Long roomId, Player player, String ses SystemNoticeResponse systemNoticeResponse = ofPlayerEvent(player.nickname, RoomEventType.EXIT); - messageSender.send(destination, MessageType.PLAYER_LIST, toPlayerListResponse(room)); - messageSender.send(destination, MessageType.SYSTEM_NOTICE, systemNoticeResponse); + messageSender.sendBroadcast( + destination, MessageType.PLAYER_LIST, toPlayerListResponse(room)); + messageSender.sendBroadcast( + destination, MessageType.SYSTEM_NOTICE, systemNoticeResponse); } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java b/backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java index 103bd214..0e0f39a6 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/MessageType.java @@ -10,5 +10,6 @@ public enum MessageType { QUESTION_RESULT, RANK_UPDATE, QUESTION_START, - GAME_RESULT + GAME_RESULT, + EXIT_SUCCESS } diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/RoomEventType.java b/backend/src/main/java/io/f1/backend/domain/game/dto/RoomEventType.java index f9cdce92..924af183 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/dto/RoomEventType.java +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/RoomEventType.java @@ -7,7 +7,8 @@ public enum RoomEventType { END(null), CORRECT_ANSWER(SystemNoticeMessage.CORRECT_ANSWER), TIMEOUT(SystemNoticeMessage.TIMEOUT), - RECONNECT(SystemNoticeMessage.RECONNECT); + RECONNECT(SystemNoticeMessage.RECONNECT), + RECONNECT_PRIVATE_NOTICE(SystemNoticeMessage.RECONNECT_PRIVATE_NOTICE); private final SystemNoticeMessage systemMessage; @@ -17,7 +18,7 @@ public enum RoomEventType { public String getMessage(String nickname) { - if (this == TIMEOUT) { + if (this == TIMEOUT || this == RECONNECT_PRIVATE_NOTICE) { return systemMessage.getMessage(); } diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/SystemNoticeMessage.java b/backend/src/main/java/io/f1/backend/domain/game/dto/SystemNoticeMessage.java index 636e5bf1..31f2e345 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/dto/SystemNoticeMessage.java +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/SystemNoticeMessage.java @@ -5,7 +5,8 @@ public enum SystemNoticeMessage { EXIT(" 님이 퇴장하셨습니다"), CORRECT_ANSWER(" 님 정답입니다 !"), TIMEOUT("땡 ~ ⏰ 제한 시간 초과!"), - RECONNECT(" 님이 재연결 되었습니다."); + RECONNECT(" 님이 재연결 되었습니다. "), + RECONNECT_PRIVATE_NOTICE("⚠️다음 라운드부터 참여하실 수 있습니다"); private final String message; diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/request/QuizChangeRequest.java b/backend/src/main/java/io/f1/backend/domain/game/dto/request/QuizChangeRequest.java index ecafe393..1237a44c 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/dto/request/QuizChangeRequest.java +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/request/QuizChangeRequest.java @@ -32,6 +32,6 @@ public void afterChange(Room room, MessageSender messageSender) { PlayerListResponse response = toPlayerListResponse(room); log.info(response.toString()); - messageSender.send(destination, MessageType.PLAYER_LIST, response); + messageSender.sendBroadcast(destination, MessageType.PLAYER_LIST, response); } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/dto/response/ExitSuccessResponse.java b/backend/src/main/java/io/f1/backend/domain/game/dto/response/ExitSuccessResponse.java new file mode 100644 index 00000000..aa9d9ed9 --- /dev/null +++ b/backend/src/main/java/io/f1/backend/domain/game/dto/response/ExitSuccessResponse.java @@ -0,0 +1,3 @@ +package io.f1.backend.domain.game.dto.response; + +public record ExitSuccessResponse(boolean success) {} diff --git a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java index 3f761725..cd3ef88f 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/model/Room.java +++ b/backend/src/main/java/io/f1/backend/domain/game/model/Room.java @@ -93,8 +93,8 @@ public void updateTimer(ScheduledFuture timer) { this.timer = timer; } - public void removeSessionId(String sessionId) { - this.playerSessionMap.remove(sessionId); + public boolean removeSessionId(String sessionId) { + return this.playerSessionMap.remove(sessionId) != null; } public void removeValidatedUserId(Long userId) { @@ -167,10 +167,7 @@ public boolean isExit(String sessionId) { } public boolean isLastPlayer(String sessionId) { - long connectedCount = - playerSessionMap.values().stream() - .filter(player -> player.getState() == ConnectionState.CONNECTED) - .count(); + long connectedCount = playerSessionMap.size(); return connectedCount == 1 && playerSessionMap.containsKey(sessionId); } diff --git a/backend/src/main/java/io/f1/backend/domain/game/websocket/MessageSender.java b/backend/src/main/java/io/f1/backend/domain/game/websocket/MessageSender.java index 0a85ddc1..46f53b7e 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/websocket/MessageSender.java +++ b/backend/src/main/java/io/f1/backend/domain/game/websocket/MessageSender.java @@ -2,6 +2,7 @@ import io.f1.backend.domain.game.dto.MessageType; import io.f1.backend.domain.game.dto.response.DefaultWebSocketResponse; +import io.f1.backend.domain.user.dto.UserPrincipal; import lombok.RequiredArgsConstructor; @@ -14,8 +15,14 @@ public class MessageSender { private final SimpMessagingTemplate messagingTemplate; - public void send(String destination, MessageType type, T message) { + public void sendBroadcast(String destination, MessageType type, T message) { messagingTemplate.convertAndSend( destination, new DefaultWebSocketResponse<>(type, message)); } + + public void sendPersonal( + String destination, MessageType type, T message, UserPrincipal principal) { + messagingTemplate.convertAndSendToUser( + principal.getName(), destination, new DefaultWebSocketResponse<>(type, message)); + } } diff --git a/backend/src/main/java/io/f1/backend/domain/game/websocket/service/SessionService.java b/backend/src/main/java/io/f1/backend/domain/game/websocket/service/SessionService.java index ec40f46f..d568b0de 100644 --- a/backend/src/main/java/io/f1/backend/domain/game/websocket/service/SessionService.java +++ b/backend/src/main/java/io/f1/backend/domain/game/websocket/service/SessionService.java @@ -65,7 +65,6 @@ public void handleUserDisconnect(String sessionId, UserPrincipal principal) { /* 재연결 실패 */ if (sessionId.equals(userIdSession.get(userId))) { roomService.exitIfNotPlaying(roomId, sessionId, principal); - // 메세지 응답 추가 } removeSession(sessionId, userId); },