Skip to content

Commit 83554bb

Browse files
authored
♻️ refactor: 게임 시작 요청 리팩토링 (#83)
* ♻️ refactor: gameStart 리팩토링 - 방장만 게임 시작 가능 - 이미 플레이 중인 방의 중복 게임시작 방지 * chore: Java 스타일 수정 * ⚰️ remove: GameStartRequestDTO 삭제 * ♻️ refactor: 리뷰 반영 수정 --------- Co-authored-by: github-actions <>
1 parent 0597d47 commit 83554bb

File tree

6 files changed

+60
-51
lines changed

6 files changed

+60
-51
lines changed

backend/src/main/java/io/f1/backend/domain/game/app/GameService.java

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22

33
import static io.f1.backend.domain.quiz.mapper.QuizMapper.toGameStartResponse;
44

5-
import io.f1.backend.domain.game.dto.request.GameStartRequest;
65
import io.f1.backend.domain.game.dto.response.GameStartResponse;
76
import io.f1.backend.domain.game.event.RoomUpdatedEvent;
8-
import io.f1.backend.domain.game.model.GameSetting;
97
import io.f1.backend.domain.game.model.Player;
108
import io.f1.backend.domain.game.model.Room;
119
import io.f1.backend.domain.game.model.RoomState;
1210
import io.f1.backend.domain.game.store.RoomRepository;
1311
import io.f1.backend.domain.question.entity.Question;
1412
import io.f1.backend.domain.quiz.app.QuizService;
1513
import io.f1.backend.domain.quiz.entity.Quiz;
14+
import io.f1.backend.domain.user.dto.UserPrincipal;
1615
import io.f1.backend.global.exception.CustomException;
1716
import io.f1.backend.global.exception.errorcode.GameErrorCode;
1817
import io.f1.backend.global.exception.errorcode.RoomErrorCode;
@@ -24,6 +23,7 @@
2423

2524
import java.util.List;
2625
import java.util.Map;
26+
import java.util.Objects;
2727

2828
@Service
2929
@RequiredArgsConstructor
@@ -33,53 +33,54 @@ public class GameService {
3333
private final RoomRepository roomRepository;
3434
private final ApplicationEventPublisher eventPublisher;
3535

36-
public GameStartResponse gameStart(Long roomId, GameStartRequest gameStartRequest) {
37-
38-
Long quizId = gameStartRequest.quizId();
36+
public GameStartResponse gameStart(Long roomId, UserPrincipal principal) {
3937

4038
Room room =
4139
roomRepository
4240
.findRoom(roomId)
4341
.orElseThrow(() -> new CustomException(RoomErrorCode.ROOM_NOT_FOUND));
4442

45-
if (!validateReadyStatus(room)) {
46-
throw new CustomException(RoomErrorCode.PLAYER_NOT_READY);
47-
}
48-
49-
// 방의 gameSetting에 설정된 퀴즈랑 요청 퀴즈랑 같은지 체크 후 GameSetting에서 라운드 가져오기
50-
Integer round = checkGameSetting(room, quizId);
43+
validateRoomStart(room, principal);
5144

45+
Long quizId = room.getGameSetting().getQuizId();
5246
Quiz quiz = quizService.getQuizWithQuestionsById(quizId);
47+
List<Question> questions = prepareQuestions(room, quiz);
5348

54-
// 라운드 수만큼 랜덤 Question 추출
55-
List<Question> questions = quizService.getRandomQuestionsWithoutAnswer(quizId, round);
5649
room.updateQuestions(questions);
5750

58-
GameStartResponse gameStartResponse = toGameStartResponse(questions);
59-
6051
// 방 정보 게임 중으로 변경
6152
room.updateRoomState(RoomState.PLAYING);
6253

6354
eventPublisher.publishEvent(new RoomUpdatedEvent(room, quiz));
6455

65-
return gameStartResponse;
56+
return toGameStartResponse(questions);
6657
}
6758

68-
private Integer checkGameSetting(Room room, Long quizId) {
69-
70-
GameSetting gameSetting = room.getGameSetting();
59+
private boolean validateReadyStatus(Room room) {
7160

72-
if (!gameSetting.validateQuizId(quizId)) {
73-
throw new CustomException(GameErrorCode.GAME_SETTING_CONFLICT);
74-
}
61+
Map<String, Player> playerSessionMap = room.getPlayerSessionMap();
7562

76-
return gameSetting.getRound();
63+
return playerSessionMap.values().stream().allMatch(Player::isReady);
7764
}
7865

79-
private boolean validateReadyStatus(Room room) {
66+
private void validateRoomStart(Room room, UserPrincipal principal) {
67+
if (!Objects.equals(principal.getUserId(), room.getHost().getId())) {
68+
throw new CustomException(RoomErrorCode.NOT_ROOM_OWNER);
69+
}
8070

81-
Map<String, Player> playerSessionMap = room.getPlayerSessionMap();
71+
if (!validateReadyStatus(room)) {
72+
throw new CustomException(GameErrorCode.PLAYER_NOT_READY);
73+
}
8274

83-
return playerSessionMap.values().stream().allMatch(Player::isReady);
75+
if (room.getState() == RoomState.PLAYING) {
76+
throw new CustomException(RoomErrorCode.GAME_ALREADY_PLAYING);
77+
}
78+
}
79+
80+
// 라운드 수만큼 랜덤 Question 추출
81+
private List<Question> prepareQuestions(Room room, Quiz quiz) {
82+
Long quizId = quiz.getId();
83+
Integer round = room.getGameSetting().getRound();
84+
return quizService.getRandomQuestionsWithoutAnswer(quizId, round);
8485
}
8586
}

backend/src/main/java/io/f1/backend/domain/game/dto/request/GameStartRequest.java

Lines changed: 0 additions & 3 deletions
This file was deleted.

backend/src/main/java/io/f1/backend/domain/game/websocket/GameSocketController.java

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package io.f1.backend.domain.game.websocket;
22

3+
import static io.f1.backend.domain.game.websocket.WebSocketUtils.getSessionId;
4+
import static io.f1.backend.domain.game.websocket.WebSocketUtils.getSessionUser;
5+
36
import io.f1.backend.domain.game.app.GameService;
47
import io.f1.backend.domain.game.app.RoomService;
58
import io.f1.backend.domain.game.dto.ChatMessage;
@@ -8,7 +11,6 @@
811
import io.f1.backend.domain.game.dto.RoomInitialData;
912
import io.f1.backend.domain.game.dto.RoundResult;
1013
import io.f1.backend.domain.game.dto.request.DefaultWebSocketRequest;
11-
import io.f1.backend.domain.game.dto.request.GameStartRequest;
1214
import io.f1.backend.domain.game.dto.response.GameStartResponse;
1315
import io.f1.backend.domain.game.dto.response.PlayerListResponse;
1416
import io.f1.backend.domain.user.dto.UserPrincipal;
@@ -18,8 +20,6 @@
1820
import org.springframework.messaging.Message;
1921
import org.springframework.messaging.handler.annotation.DestinationVariable;
2022
import org.springframework.messaging.handler.annotation.MessageMapping;
21-
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
22-
import org.springframework.security.core.Authentication;
2323
import org.springframework.stereotype.Controller;
2424

2525
@Controller
@@ -71,12 +71,11 @@ public void exitRoom(@DestinationVariable Long roomId, Message<?> message) {
7171
}
7272

7373
@MessageMapping("/room/start/{roomId}")
74-
public void gameStart(
75-
@DestinationVariable Long roomId,
76-
Message<DefaultWebSocketRequest<GameStartRequest>> message) {
74+
public void gameStart(@DestinationVariable Long roomId, Message<?> message) {
75+
76+
UserPrincipal principal = getSessionUser(message);
7777

78-
GameStartResponse gameStartResponse =
79-
gameService.gameStart(roomId, message.getPayload().getMessage());
78+
GameStartResponse gameStartResponse = gameService.gameStart(roomId, principal);
8079

8180
String destination = getDestination(roomId);
8281

@@ -112,17 +111,6 @@ public void playerReady(@DestinationVariable Long roomId, Message<?> message) {
112111
messageSender.send(getDestination(roomId), MessageType.PLAYER_LIST, playerListResponse);
113112
}
114113

115-
private static String getSessionId(Message<?> message) {
116-
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
117-
return accessor.getSessionId();
118-
}
119-
120-
private static UserPrincipal getSessionUser(Message<?> message) {
121-
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
122-
Authentication auth = (Authentication) accessor.getUser();
123-
return (UserPrincipal) auth.getPrincipal();
124-
}
125-
126114
private String getDestination(Long roomId) {
127115
return "/sub/room/" + roomId;
128116
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.f1.backend.domain.game.websocket;
2+
3+
import io.f1.backend.domain.user.dto.UserPrincipal;
4+
5+
import org.springframework.messaging.Message;
6+
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
7+
import org.springframework.security.core.Authentication;
8+
9+
public class WebSocketUtils {
10+
11+
public static String getSessionId(Message<?> message) {
12+
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
13+
return accessor.getSessionId();
14+
}
15+
16+
public static UserPrincipal getSessionUser(Message<?> message) {
17+
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
18+
Authentication auth = (Authentication) accessor.getUser();
19+
return (UserPrincipal) auth.getPrincipal();
20+
}
21+
}

backend/src/main/java/io/f1/backend/global/exception/errorcode/GameErrorCode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
@Getter
99
@RequiredArgsConstructor
1010
public enum GameErrorCode implements ErrorCode {
11-
GAME_SETTING_CONFLICT("E409002", HttpStatus.CONFLICT, "게임 설정이 맞지 않습니다.");
11+
GAME_SETTING_CONFLICT("E409002", HttpStatus.CONFLICT, "게임 설정이 맞지 않습니다."),
12+
PLAYER_NOT_READY("E403004", HttpStatus.FORBIDDEN, "게임 시작을 위한 준비 상태가 아닙니다.");
1213

1314
private final String code;
1415

backend/src/main/java/io/f1/backend/global/exception/errorcode/RoomErrorCode.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
public enum RoomErrorCode implements ErrorCode {
1111
ROOM_USER_LIMIT_REACHED("E403002", HttpStatus.FORBIDDEN, "정원이 모두 찼습니다."),
1212
ROOM_GAME_IN_PROGRESS("E403003", HttpStatus.FORBIDDEN, "게임이 진행 중 입니다."),
13-
PLAYER_NOT_READY("E403004", HttpStatus.FORBIDDEN, "게임 시작을 위한 준비 상태가 아닙니다."),
1413
ROOM_NOT_FOUND("E404005", HttpStatus.NOT_FOUND, "존재하지 않는 방입니다."),
1514
WRONG_PASSWORD("E401006", HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지않습니다."),
1615
PLAYER_NOT_FOUND("E404007", HttpStatus.NOT_FOUND, "존재하지 않는 플레이어입니다."),
17-
SOCKET_SESSION_NOT_FOUND("E404006", HttpStatus.NOT_FOUND, "존재하지 않는 소켓 세션입니다.");
16+
SOCKET_SESSION_NOT_FOUND("E404006", HttpStatus.NOT_FOUND, "존재하지 않는 소켓 세션입니다."),
17+
GAME_ALREADY_PLAYING("E400015", HttpStatus.BAD_REQUEST, "이미 게임이 진행 중 입니다."),
18+
NOT_ROOM_OWNER("E403005", HttpStatus.FORBIDDEN, "방장만 게임 시작이 가능합니다.");
1819

1920
private final String code;
2021

0 commit comments

Comments
 (0)