Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/#4 : 게임 Feign 추가, Socket 관련 코드 추가 #9

Merged
merged 4 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -0,0 +1,20 @@
package urdego.io.urdego_notification_service.common.enums;

public enum MessageType {
// 알림
NOTIFICATION,
// 대기방
PLAYER_JOINED,
PLAYER_REMOVED,
PLAYER_READY,
CONTENT_SELECTED,
// 게임
SCORE_UPDATED,
GAME_ENDED,
// 라운드 진행
QUESTION_GIVEN,
ANSWER_SUBMITTED



}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import urdego.io.urdego_notification_service.controller.dto.request.NotificationRequest;
import urdego.io.urdego_notification_service.controller.dto.response.WebSocketMessageResponse;
import urdego.io.urdego_notification_service.controller.dto.request.notification.NotificationRequest;
import urdego.io.urdego_notification_service.controller.dto.WebSocketMessage;
import urdego.io.urdego_notification_service.domain.entity.Notification;
import urdego.io.urdego_notification_service.domain.service.NotificationService;

Expand All @@ -24,10 +24,10 @@ public class NotificationController {
private final NotificationService notificationService;

@PostMapping("/send")
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = WebSocketMessageResponse.class)))
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = WebSocketMessage.class)))
@Operation(summary = "게임초대 알림 전송",description = "userId로 게임초대 알림 전송")
public ResponseEntity<WebSocketMessageResponse<Notification>> sendNotification(@RequestBody NotificationRequest request) {
WebSocketMessageResponse<Notification> response = notificationService.publishNotification(request);
public ResponseEntity<WebSocketMessage<Notification>> sendNotification(@RequestBody NotificationRequest request) {
WebSocketMessage<Notification> response = notificationService.publishNotification(request);
return ResponseEntity.ok().body(response);

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,66 @@
package urdego.io.urdego_notification_service.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import urdego.io.urdego_notification_service.common.enums.MessageType;
import urdego.io.urdego_notification_service.controller.client.GameServiceClient;
import urdego.io.urdego_notification_service.controller.dto.request.ContentSelectReq;
import urdego.io.urdego_notification_service.controller.dto.request.PlayerReq;
import urdego.io.urdego_notification_service.controller.dto.response.RoomPlayersRes;
import urdego.io.urdego_notification_service.controller.dto.WebSocketMessage;
import urdego.io.urdego_notification_service.controller.dto.request.game.AnswerReq;
import urdego.io.urdego_notification_service.controller.dto.request.game.QuestionReq;
import urdego.io.urdego_notification_service.controller.dto.request.game.ScoreReq;
import urdego.io.urdego_notification_service.controller.dto.request.room.ContentSelectReq;
import urdego.io.urdego_notification_service.controller.dto.request.room.PlayerReq;
import urdego.io.urdego_notification_service.controller.util.ReflectionUtil;

@Slf4j
@Controller
@RequiredArgsConstructor
public class NotificationSocketController {

private final GameServiceClient gameServiceClient;
private final SimpMessagingTemplate messagingTemplate;

// 플레이어 참여
@MessageMapping("/room/player/invite")
public void invitePlayer(PlayerReq request) {
RoomPlayersRes response = gameServiceClient.invitePlayer(request).getBody();
messagingTemplate.convertAndSend("/urdego/sub/" + response.roomId(), response);
@MessageMapping("/room/event")
public void handleRoomEvent(WebSocketMessage<?> request) {
Object response = null;
switch (request.messageType()) {
case PLAYER_JOINED -> response = gameServiceClient.invitePlayer((PlayerReq) request.payload()).getBody();
case PLAYER_REMOVED -> response = gameServiceClient.removePlayer((PlayerReq) request.payload()).getBody();
case PLAYER_READY -> response = gameServiceClient.readyPlayer((PlayerReq) request.payload()).getBody();
case CONTENT_SELECTED -> response = gameServiceClient.selectContent((ContentSelectReq) request.payload()).getBody();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

최신 case 문이네요 ..
까먹고 있었습니다 보기 좋네요 !

}
sendMessage(response, request.messageType());
}

// 플레이어 삭제
@MessageMapping("/room/player/remove")
public void removePlayer(PlayerReq request) {
RoomPlayersRes response = gameServiceClient.removePlayer(request).getBody();
messagingTemplate.convertAndSend("/urdego/sub/" + response.roomId(), response);
}
@MessageMapping("/game/event")
public void handleGameEvent(WebSocketMessage<?> request) {
Object response = null;
switch (request.messageType()) {
case SCORE_UPDATED -> response = gameServiceClient.giveScores((ScoreReq) request.payload()).getBody();
case GAME_ENDED -> response = gameServiceClient.endGame((String) request.payload()).getBody();
case QUESTION_GIVEN -> response = gameServiceClient.giveQuestion((QuestionReq) request.payload()).getBody();
case ANSWER_SUBMITTED -> response = gameServiceClient.submitAnswer((AnswerReq) request.payload()).getBody();

// 플레이어 준비
@MessageMapping("/room/player/ready")
public void readyPlayer(PlayerReq request) {
RoomPlayersRes response = gameServiceClient.readyPlayer(request).getBody();
messagingTemplate.convertAndSend("/urdego/sub/" + response.roomId(), response);
}
sendMessage(response, request.messageType());
}

// 컨텐츠 선택
@MessageMapping("/room/select-content")
public void selectContent(ContentSelectReq request) {
gameServiceClient.selectContent(request);
private <T> void sendMessage(T response, MessageType messageType) {
if (response == null) {
log.info("빈 응답이므로 기본 메시지를 전송합니다.");
return;
}
try {
String roomId = ReflectionUtil.getRoomIdFromResponse(response);
messagingTemplate.convertAndSend(
"/urdego/sub/" + roomId,
new WebSocketMessage<>(messageType, response)
);
} catch (IllegalArgumentException e) {
log.error("roomId 조회 실패: {}", e.getMessage());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,42 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import urdego.io.urdego_notification_service.controller.dto.request.ContentSelectReq;
import urdego.io.urdego_notification_service.controller.dto.request.PlayerReq;
import urdego.io.urdego_notification_service.controller.dto.response.RoomPlayersRes;
import org.springframework.web.bind.annotation.RequestMapping;
import urdego.io.urdego_notification_service.controller.dto.request.game.AnswerReq;
import urdego.io.urdego_notification_service.controller.dto.request.game.QuestionReq;
import urdego.io.urdego_notification_service.controller.dto.request.game.ScoreReq;
import urdego.io.urdego_notification_service.controller.dto.request.room.ContentSelectReq;
import urdego.io.urdego_notification_service.controller.dto.request.room.PlayerReq;
import urdego.io.urdego_notification_service.controller.dto.response.game.AnswerRes;
import urdego.io.urdego_notification_service.controller.dto.response.game.GameEndRes;
import urdego.io.urdego_notification_service.controller.dto.response.game.QuestionRes;
import urdego.io.urdego_notification_service.controller.dto.response.game.ScoreRes;
import urdego.io.urdego_notification_service.controller.dto.response.room.RoomPlayersRes;

@FeignClient(name = "game-service", url = "${feign.client.config.service.url}")
@FeignClient(name = "game-service")
@RequestMapping("/api/game-service")
public interface GameServiceClient {
@PostMapping("/player/invite")
@PostMapping("/room/player/invite")
ResponseEntity<RoomPlayersRes> invitePlayer(@RequestBody PlayerReq request);

@PostMapping("/player/remove")
@PostMapping("/room/player/remove")
ResponseEntity<RoomPlayersRes> removePlayer(@RequestBody PlayerReq request);

@PostMapping("/player/ready")
@PostMapping("/room/player/ready")
ResponseEntity<RoomPlayersRes> readyPlayer(@RequestBody PlayerReq request);

@PostMapping("/select-content")
@PostMapping("/room/select-content")
ResponseEntity<Void> selectContent(@RequestBody ContentSelectReq request);

@PostMapping("/game/score")
ResponseEntity<ScoreRes> giveScores(@RequestBody ScoreReq request);

@PostMapping("/game/end")
ResponseEntity<GameEndRes> endGame(@RequestBody String gameId);

@PostMapping("/round/question")
ResponseEntity<QuestionRes> giveQuestion(@RequestBody QuestionReq request);

@PostMapping("/round/answer")
ResponseEntity<AnswerRes> submitAnswer(@RequestBody AnswerReq request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package urdego.io.urdego_notification_service.controller.dto;

import urdego.io.urdego_notification_service.common.enums.MessageType;

public record WebSocketMessage<T>(
MessageType messageType,
T payload
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package urdego.io.urdego_notification_service.controller.dto.request.game;

public record AnswerReq(
String questionId,
String userId,
double latitude,
double longitude
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package urdego.io.urdego_notification_service.controller.dto.request.game;

public record QuestionReq(
String roomId,
int roundNum
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package urdego.io.urdego_notification_service.controller.dto.request.game;

public record ScoreReq(
String gameId,
int roundNum
) {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package urdego.io.urdego_notification_service.controller.dto.request;
package urdego.io.urdego_notification_service.controller.dto.request.notification;

import lombok.Builder;
import urdego.io.urdego_notification_service.domain.entity.Notification;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package urdego.io.urdego_notification_service.controller.dto.request;
package urdego.io.urdego_notification_service.controller.dto.request.room;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package urdego.io.urdego_notification_service.controller.dto.request;
package urdego.io.urdego_notification_service.controller.dto.request.room;

public record PlayerReq(
String roomId,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package urdego.io.urdego_notification_service.controller.dto.response.game;

public record AnswerRes(
String questionId,
String userId,
double latitude,
double longitude
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package urdego.io.urdego_notification_service.controller.dto.response.game;

import urdego.io.urdego_notification_service.common.enums.Status;

import java.util.Map;

public record GameEndRes(
String gameId,
String roomId,
Status status,
Map<String, Integer> totalScores,
Map<String, Integer> exp
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package urdego.io.urdego_notification_service.controller.dto.response.game;

import java.util.List;

public record QuestionRes(
String questionId,
String roomId,
int roundNum,
double latitude,
double longitude,
String hint,
List<String> contents
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package urdego.io.urdego_notification_service.controller.dto.response.game;

import java.util.Map;

public record ScoreRes(
String roomId,
Map<Integer, Map<String, Integer>> roundScores,
Map<String, Integer> totalScores
) {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package urdego.io.urdego_notification_service.controller.dto.response;
package urdego.io.urdego_notification_service.controller.dto.response.notification;

import java.util.UUID;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package urdego.io.urdego_notification_service.controller.dto.response;
package urdego.io.urdego_notification_service.controller.dto.response.room;

import urdego.io.urdego_notification_service.common.enums.Status;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package urdego.io.urdego_notification_service.controller.util;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class ReflectionUtil {
private static final Map<Class<?>, Method> methodCache = new ConcurrentHashMap<>();

public static String getRoomIdFromResponse(Object response) {
if (response == null) {
throw new IllegalArgumentException("응답 객체가 null입니다.");
}

try {
Method method = methodCache.computeIfAbsent(response.getClass(), clazz -> {
try {
return clazz.getMethod("roomId");
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("roomId를 찾을 수 없는 응답 타입: " + clazz.getSimpleName(), e);
}
});

return (String) method.invoke(response);

} catch (Exception e) {
throw new IllegalArgumentException("roomId 호출 실패: " + response.getClass().getSimpleName(), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
import urdego.io.urdego_notification_service.common.enums.Action;
import urdego.io.urdego_notification_service.controller.dto.request.NotificationRequest;
import urdego.io.urdego_notification_service.controller.dto.request.notification.NotificationRequest;

import java.io.Serializable;
import java.time.LocalDateTime;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package urdego.io.urdego_notification_service.domain.service;

import org.springframework.stereotype.Service;
import urdego.io.urdego_notification_service.controller.dto.request.NotificationRequest;
import urdego.io.urdego_notification_service.controller.dto.response.NotificationResponse;
import urdego.io.urdego_notification_service.controller.dto.response.WebSocketMessageResponse;
import urdego.io.urdego_notification_service.controller.dto.request.notification.NotificationRequest;
import urdego.io.urdego_notification_service.controller.dto.WebSocketMessage;
import urdego.io.urdego_notification_service.domain.entity.Notification;

import java.util.List;

public interface NotificationService {

//메세지 발행
public WebSocketMessageResponse<Notification> publishNotification(NotificationRequest notificationRequest);
public WebSocketMessage<Notification> publishNotification(NotificationRequest notificationRequest);

//사용자 별 메세지 확인
List<Object> getUserNotifications(Long userId);
Expand Down
Loading