Skip to content

Commit

Permalink
feat: 게임방 멤버정보 업데이트 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
kimday0326 committed Feb 13, 2024
1 parent acbaa0f commit 9b6c0ee
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.pgms.api.domain.game.dto.response;

import com.pgms.coredomain.domain.game.GameRoomMember;

public record GameRoomMemberGetResponse(
Long id,
Long memberId,
String nickname,
boolean readyStatus
) {
public static GameRoomMemberGetResponse from(GameRoomMember gameRoomMember) {
return new GameRoomMemberGetResponse(
gameRoomMember.getId(),
gameRoomMember.getMemberId(),
gameRoomMember.getNickname(),
gameRoomMember.isReadyStatus()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.pgms.api.domain.game.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.pgms.api.domain.game.dto.request.GameRoomCreateRequest;
import com.pgms.api.domain.game.dto.response.GameRoomMemberGetResponse;
import com.pgms.api.domain.game.exception.GameException;
import com.pgms.api.sse.SseEmitters;
import com.pgms.api.sse.service.SseService;
Expand Down Expand Up @@ -31,6 +34,7 @@ public class GameRoomService {
private final GameRoomMemberRepository gameRoomMemberRepository;
private final SseEmitters sseEmitters;
private final SseService sseService;
// private final SimpMessageSendingOperations sendingOperations;

// ============================== 게임방 생성 ==============================
public Long createRoom(Long memberId, GameRoomCreateRequest request) {
Expand Down Expand Up @@ -85,20 +89,69 @@ public Long enterGameRoom(Long memberId, Long roomId) {
.memberId(memberId)
.nickname(member.getNickname())
.webSessionId(null)
.readyStatus(true)
.readyStatus(false)
.build();

gameRoom.enterRoom();
gameRoomMemberRepository.save(gameRoomMember);

// 대기실 리스트 업데이트
sseEmitters.updateGameRoom(sseService.getRooms());

// 현재 게임방 유저에 대한 정보 보냄
final List<GameRoomMemberGetResponse> gameRoomMembers = getAllGameRoomMembers(roomId).stream()
.map(GameRoomMemberGetResponse::from).toList();
// sendingOperations.convertAndSend("/from/game-room/" + roomId, gameRoomMembers);
return roomId;
}

public void exitGameRoom(String sessionId) {
// 세션 ID로 게임방 멤버 찾아서 제거
final GameRoomMember gameRoomMember = gameRoomMemberRepository.findByWebSessionId(sessionId)
.orElseThrow(() -> new IllegalArgumentException("게임 룸 멤버를 찾을 수 없습니다."));
final GameRoom gameRoom = gameRoomMember.getGameRoom();

gameRoomMemberRepository.delete(gameRoomMember);
gameRoom.exitRoom();

// 현재 인원 0 명이면 방까지 제거
if (gameRoom.getCurrentPlayer() == 0) {
gameRoomRepository.delete(gameRoom);
return;
}

// 방장이 나갔으면 다음 방장 지정
final List<GameRoomMember> leftGameRoomMembers = gameRoomMemberRepository.findAllByGameRoomId(gameRoom.getId());
if (gameRoom.getHostId().equals(gameRoomMember.getMemberId())) {
final GameRoomMember nextHost = leftGameRoomMembers.get(0);
gameRoom.updateHostId(nextHost.getMemberId());
}

// 구독된 사람들에게 메세지
// sendingOperations.convertAndSend("/from/game-room/" + gameRoom.getId(), leftGameRoomMembers);
// sendingOperations.convertAndSend(
// "/from/game-room/" + gameRoom.getId() + "/exit",
// gameRoomMember.getNickname() + "님이 퇴장하셨습니다."
// );
sseEmitters.updateGameRoom(sseService.getRooms());
}

public void enterSessionId(Long roomId, Long memberId, String sessionId) {
// 게임 룸에는 이미 입장한 상태
final GameRoomMember gameRoomMember = gameRoomMemberRepository.findByMemberId(memberId)
.orElseThrow(() -> new IllegalArgumentException("게임 룸 멤버를 찾을 수 없습니다."));
gameRoomMember.setSessionId(sessionId);
}

private GameRoom getGameRoom(Long roomId) {
return gameRoomRepository.findById(roomId)
.orElseThrow(() -> new GameException(GameRoomErrorCode.GAME_ROOM_NOT_FOUND));
}

private List<GameRoomMember> getAllGameRoomMembers(Long roomId) {
return gameRoomMemberRepository.findAllByGameRoomId(roomId);
}

private Member getMember(Long memberId) {
return memberRepository.findById(memberId)
.orElseThrow(() -> new GameException(MemberErrorCode.MEMBER_NOT_FOUND));
Expand All @@ -117,8 +170,9 @@ private void validateGameRoomEnableEnter(GameRoom gameRoom) {
}

private void validateMemberAlreadyEntered(Long memberId) {
if (gameRoomMemberRepository.existsByMemberId(memberId)) {
gameRoomMemberRepository.deleteByMemberId(memberId);
}
gameRoomMemberRepository.findByMemberId(memberId).ifPresent(gameRoomMember -> {
gameRoomMember.getGameRoom().exitRoom();
gameRoomMemberRepository.delete(gameRoomMember);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;

import com.pgms.api.domain.game.service.GameRoomService;
import com.pgms.api.socket.handler.CustomWebSocketHandlerDecorator;
import com.pgms.api.socket.handler.FilterChannelInterceptor;

Expand All @@ -21,6 +22,7 @@
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

private final FilterChannelInterceptor filterChannelInterceptor;
private final GameRoomService gameRoomService;

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
Expand All @@ -43,7 +45,7 @@ public void configureWebSocketTransport(WebSocketTransportRegistration registry)

@Bean
public CustomWebSocketHandlerDecorator customWebSocketHandlerDecorator(WebSocketHandler webSocketHandler) {
return new CustomWebSocketHandlerDecorator(webSocketHandler);
return new CustomWebSocketHandlerDecorator(webSocketHandler, gameRoomService);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com.pgms.api.socket.controller;

import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.web.bind.annotation.RestController;

import com.pgms.api.socket.service.GameRoomSocketService;
import com.pgms.api.domain.game.service.GameRoomService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -12,17 +17,19 @@
@RequiredArgsConstructor
public class GameRoomSocketController {

private final GameRoomSocketService gameRoomSocketService;
private final GameRoomService gameRoomService;

// // 게임방 입장
// @MessageMapping("/game-room/{roomId}/enter")
// @SendTo("/from/game-room/{roomId}/enter")
// public GameRoomEnterResponse enterGameRoom(
// @Header("MemberId") Long memberId,
// @DestinationVariable Long roomId) {
// log.info(">>>>>> enterGameRoom : roomId = {}, memberId = {}", roomId, memberId);
// return gameRoomSocketService.enterGameRoom(roomId, memberId);
// }
// 세션 ID를 게임 룸 멤버에 추가
@MessageMapping("/game-room/{roomId}/enter")
@SendTo("/from/game-room/{roomId}/enter")
public void setSessionId(
@Header("MemberId") Long memberId,
@DestinationVariable Long roomId,
SimpMessageHeaderAccessor headerAccessor) {
final String sessionId = headerAccessor.getSessionId();
log.info(">>>>>> enterGameRoom : roomId = {}, memberId = {}, sessionId = {}", roomId, memberId, sessionId);
gameRoomService.enterSessionId(roomId, memberId, sessionId);
}
//
// // 게임방 퇴장
// @MessageMapping("/game-room/{roomId}/exit")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,34 @@
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.WebSocketHandlerDecorator;

import com.pgms.api.domain.game.service.GameRoomService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CustomWebSocketHandlerDecorator extends WebSocketHandlerDecorator {

private final GameRoomService gameRoomService;

private final ConcurrentHashMap<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();

public CustomWebSocketHandlerDecorator(WebSocketHandler delegate) {
public CustomWebSocketHandlerDecorator(WebSocketHandler delegate, GameRoomService gameRoomService) {
super(delegate);
this.gameRoomService = gameRoomService;
}

@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
log.info(">>>> decorator established {} ", session);
final Long memberId = (Long)session.getAttributes().get("MemberId");
final String roomId = (String)session.getAttributes().get("RoomId");
sessionMap.put(memberId + ":" + roomId, session);
sessionMap.put(session.getId(), session);
super.afterConnectionEstablished(session);
}

// TODO : 브라우저 종료 시, 웹소켓 연결 종료 처리 로직 추후에 필요함
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
log.info(">>>> decorator closed {} ", session);
gameRoomService.exitGameRoom(session.getId());

sessionMap.values().remove(session);
super.afterConnectionClosed(session, closeStatus);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,8 @@ public void enterRoom() {
public void exitRoom() {
this.currentPlayer--;
}

public void updateHostId(Long memberId) {
this.hostId = memberId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,8 @@ public void update(boolean readyStatus, String webSessionId) {
this.readyStatus = readyStatus;
this.webSessionId = webSessionId;
}

public void setSessionId(String sessionId) {
this.webSessionId = sessionId;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.pgms.coredomain.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

import com.pgms.coredomain.domain.game.GameRoomMember;
Expand All @@ -8,4 +11,10 @@ public interface GameRoomMemberRepository extends JpaRepository<GameRoomMember,
boolean existsByMemberId(Long memberId);

void deleteByMemberId(Long memberId);

List<GameRoomMember> findAllByGameRoomId(Long roomId);

Optional<GameRoomMember> findByMemberId(Long memberId);

Optional<GameRoomMember> findByWebSessionId(String sessionId);
}
7 changes: 3 additions & 4 deletions http/test.http
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ Content-Type: application/json
<> 2024-02-08T214523.200.json
<> 2024-02-08T214506.500.json

###
### 방 만들기 > 게임방 멤버 정보 구독 + 세션 ID 저장용 SEND
POST http://localhost:8080/api/v1/rooms
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzM4NCJ9.eyJpZCI6MSwic3ViIjoidGVzdEBuYXZlci5jb20iLCJpYXQiOjE3MDc4MTM5NjgsImV4cCI6MTcwNzgxNTc2OCwicm9sZXMiOiJST0xFX1VTRVIifQ.Z2DK3ey23nhMVHq02NpV2MZEEjkYp31v6_yddN2lXrr-oqTAmXqNTvRSgjChD1z1
Authorization: Bearer eyJhbGciOiJIUzM4NCJ9.eyJpZCI6MSwic3ViIjoidGVzdEBuYXZlci5jb20iLCJpYXQiOjE3MDc4NDE3NjAsImV4cCI6MTcwNzg0MzU2MCwicm9sZXMiOiJST0xFX1VTRVIifQ.dSz5M6c8tT6rS6bfYoYFvEdzPrXCiBHAbdokWy1NGKpe0C44JUfxXSsectYNFpQS

{
"title": "빙봉의 게임",
Expand All @@ -77,8 +77,7 @@ Authorization: Bearer eyJhbGciOiJIUzM4NCJ9.eyJpZCI6MSwic3ViIjoidGVzdEBuYXZlci5jb
### 게임방 입장
POST http://localhost:8080/api/v1/rooms/1/enter
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzM4NCJ9.eyJpZCI6Mywic3ViIjoidGVzdDJAbmF2ZXIuY29tIiwiaWF0IjoxNzA3ODE0MDE2LCJleHAiOjE3MDc4MTU4MTYsInJvbGVzIjoiUk9MRV9VU0VSIn0.3APOlOHhfI_R4yG89kqshhezdXBL_Zj4ryJqdr9eIVMC_zgAH8y-wY1y9Lk25_Wx

Authorization: Bearer eyJhbGciOiJIUzM4NCJ9.eyJpZCI6MSwic3ViIjoidGVzdEBuYXZlci5jb20iLCJpYXQiOjE3MDc4NDE3NjAsImV4cCI6MTcwNzg0MzU2MCwicm9sZXMiOiJST0xFX1VTRVIifQ.dSz5M6c8tT6rS6bfYoYFvEdzPrXCiBHAbdokWy1NGKpe0C44JUfxXSsectYNFpQS

### 조회
GET http://localhost:8081/api/v1/rooms?page=1&size=10

0 comments on commit 9b6c0ee

Please sign in to comment.