Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
aad1081
:recycle: exit 응답 추가
sehee123 Jul 20, 2025
c512117
chore: Java 스타일 수정
Jul 20, 2025
4e7b82d
Merge remote-tracking branch 'origin/dev' into refactor/96
sehee123 Jul 21, 2025
ffed8f0
:recycle: convertAndSendToUser 작업 중간 커밋
sehee123 Jul 21, 2025
b934073
Merge remote-tracking branch 'origin/dev' into refactor/96
sehee123 Jul 23, 2025
059ca0d
:sparkles: 1:1 메세징 구현
sehee123 Jul 23, 2025
5277c7c
:bug: 삭제 시 인원 카운트 조건 변경
sehee123 Jul 23, 2025
924286d
Merge remote-tracking branch 'origin/refactor/96' into refactor/96
sehee123 Jul 23, 2025
f06fa7c
chore: Java 스타일 수정
Jul 23, 2025
a6928e5
:mute: yml 로깅 설정 삭제
sehee123 Jul 23, 2025
d22020d
Merge remote-tracking branch 'origin/refactor/96' into refactor/96
sehee123 Jul 23, 2025
67631e6
:mute: securityConfig 테스트용 경로 삭제
sehee123 Jul 23, 2025
ddcc137
:coffin: /me api 응답 수정
sehee123 Jul 23, 2025
5110aed
:adhesive_bandage: isSuccess -> success 필드명 변경
sehee123 Jul 23, 2025
5865945
:adhesive_bandage: reconnect_private 메세지 추가, 재연결시 응답 request_start 제거
sehee123 Jul 25, 2025
4b21714
chore: Java 스타일 수정
Jul 25, 2025
92c73b8
Merge remote-tracking branch 'origin/dev' into refactor/96
sehee123 Jul 25, 2025
a9cfba4
:twisted_rightwards_arrows: dev merge
sehee123 Jul 25, 2025
20dc276
Merge remote-tracking branch 'origin/refactor/96' into refactor/96
sehee123 Jul 25, 2025
2f689e3
:twisted_rightwards_arrows: dev merge
sehee123 Jul 25, 2025
dc4fd0b
:twisted_rightwards_arrows: dev merge
sehee123 Jul 25, 2025
6ec049f
:adhesive_bandage: systemNotice 메세지 수정
sehee123 Jul 25, 2025
d6061d0
Merge remote-tracking branch 'origin/dev' into refactor/96
sehee123 Jul 25, 2025
ae77da3
Merge remote-tracking branch 'origin/dev' into refactor/96
sehee123 Jul 25, 2025
9239461
:twisted_rightwards_arrows: dev merge
sehee123 Jul 25, 2025
6c4ce37
chore: Java 스타일 수정
Jul 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -157,7 +167,7 @@ public void gameEnd(Room room) {
Map<String, Player> playerSessionMap = room.getPlayerSessionMap();

// TODO : 랭킹 정보 업데이트
messageSender.send(
messageSender.sendBroadcast(
destination,
MessageType.GAME_RESULT,
toGameResultListResponse(playerSessionMap, room.getGameSetting().getRound()));
Expand All @@ -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) {
Expand All @@ -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(
Expand Down Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -160,15 +163,22 @@ 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 =
ofPlayerEvent(removePlayer.nickname, RoomEventType.EXIT);

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);
}
}

Expand All @@ -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);

Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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());
Expand All @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ public enum MessageType {
QUESTION_RESULT,
RANK_UPDATE,
QUESTION_START,
GAME_RESULT
GAME_RESULT,
EXIT_SUCCESS
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ public enum SystemNoticeMessage {
EXIT(" 님이 퇴장하셨습니다"),
CORRECT_ANSWER(" 님 정답입니다 !"),
TIMEOUT("땡 ~ ⏰ 제한 시간 초과!"),
RECONNECT(" 님이 재연결 되었습니다.");
RECONNECT(" 님이 재연결 되었습니다. "),
RECONNECT_PRIVATE_NOTICE("⚠️다음 라운드부터 참여하실 수 있습니다");

private final String message;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package io.f1.backend.domain.game.dto.response;

public record ExitSuccessResponse(boolean success) {}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -14,8 +15,14 @@ public class MessageSender {

private final SimpMessagingTemplate messagingTemplate;

public <T> void send(String destination, MessageType type, T message) {
public <T> void sendBroadcast(String destination, MessageType type, T message) {
messagingTemplate.convertAndSend(
destination, new DefaultWebSocketResponse<>(type, message));
}

public <T> void sendPersonal(
String destination, MessageType type, T message, UserPrincipal principal) {
messagingTemplate.convertAndSendToUser(
principal.getName(), destination, new DefaultWebSocketResponse<>(type, message));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
Expand Down