개요
클라이언트로 부터 요청이 들어 왔을 때 session.cpp에서 action을 분석하여 알맞은 컨트롤러 핸들러에 request를 할당해 주었었다, 이제 해당 컨트롤러 핸들러로부터 알맞은 서비스 로직으로 요청을 전달하게 된다.
서비스 로직 후 받은 리턴값을 다시 session으로 반환하게 되며, 각 response에 맞게 클라이언트에게 응답을 write하는 작업을 진행하게 된다. 이 과정에서 컨트롤러가 담당하는 부분을 구현한 로직을 공유하도록 하겠다.
controller.h
// controller/controller.h
#pragma once
#include <string>
#include <nlohmann/json.hpp>
namespace game_server {
class Controller {
public:
virtual ~Controller() = default;
virtual nlohmann::json handleRequest(nlohmann::json& request) = 0;
};
} // namespace game_server
기본이 되는 컨트롤러 핸들러의 헤드이다, 각 기능의 컨트롤러는 해당 헤더파일을 상속받는다.
auth_controller.h
// controller/auth_controller.h
#pragma once
#include "controller.h"
#include "../service/auth_service.h"
#include <memory>
namespace game_server {
class AuthController : public Controller {
public:
explicit AuthController(std::shared_ptr<AuthService> authService);
~AuthController() override = default;
nlohmann::json handleRequest(nlohmann::json& request) override;
private:
nlohmann::json handleRegister(nlohmann::json& request);
nlohmann::json handleLogin(nlohmann::json& request);
nlohmann::json handleRegisterCheckAndLogin(nlohmann::json& request);
nlohmann::json handleUpdateNickName(nlohmann::json& request);
std::shared_ptr<AuthService> authService_;
};
} // namespace game_server
인증 관련 컨트롤러의 헤더파일이다.
auth_controller.cpp
// controller/auth_controller.cpp
// 인증 컨트롤러 구현 파일
// 사용자 등록 및 로그인 요청을 처리하는 컨트롤러
#include "auth_controller.h"
#include <spdlog/spdlog.h>
#include <nlohmann/json.hpp>
namespace game_server {
using json = nlohmann::json;
AuthController::AuthController(std::shared_ptr<AuthService> authService)
: authService_(authService) {
}
nlohmann::json AuthController::handleRequest(json& request) {
// 요청의 action 필드에 따라 적절한 핸들러 호출
std::string action = request["action"];
if (action == "register") {
return handleRegister(request);
}
else if (action == "login") {
return handleLogin(request);
}
else if (action == "SSAFYlogin") {
return handleRegisterCheckAndLogin(request);
}
else if (action == "updateNickName") {
return handleUpdateNickName(request);
}
else {
json error_response = {
{"status", "error"},
{"message", "알 수 없는 인증 액션"}
};
return error_response;
}
}
nlohmann::json AuthController::handleRegister(json& request) {
// 서비스 계층 호출하여 사용자 등록 실행
json response = authService_->registerUser(request);
return response;
}
nlohmann::json AuthController::handleLogin(json& request) {
json response = authService_->loginUser(request);
return response;
}
nlohmann::json AuthController::handleRegisterCheckAndLogin(nlohmann::json& request) {
json response = authService_->registerCheckAndLogin(request);
return response;
}
nlohmann::json AuthController::handleUpdateNickName(nlohmann::json& request) {
json response = authService_->updateNickName(request);
return response;
}
} // namespace game_server
클라이언트 세션을 통해 요청받은 action값에 따라 각 요청에 맞는 핸들러에 request를 매개변수로 전달하여 실행해 준다. 각 핸들러 메서드는 알맞은 비즈니스 로직을 수행하고, reponse를 받아 세션에 응답을 리턴해 준다.
인증 컨트롤러에서 주로 받아 핸들하는 내용은 다음과 같다.
- 회원가입 요청
- 로그인 요청
- 회원가입 여부를 체크하고 로그인을 진행하는 요청
- 닉네임 변경 요청
room_controller.h
// controller/room_controller.h
#pragma once
#include "controller.h"
#include "../service/room_service.h"
#include <memory>
namespace game_server {
class RoomController : public Controller {
public:
explicit RoomController(std::shared_ptr<RoomService> roomService);
~RoomController() override = default;
nlohmann::json handleRequest(nlohmann::json& request) override;
private:
nlohmann::json handleCreateRoom(nlohmann::json& request);
nlohmann::json handleJoinRoom(nlohmann::json& request);
nlohmann::json handleExitRoom(nlohmann::json& request);
nlohmann::json handleListRooms(nlohmann::json& request);
std::shared_ptr<RoomService> roomService_;
};
} // namespace game_server
방과 관련된 요청을 핸들링하는 컨트롤러의 헤더파일이다.
room_controller.cpp
// controller/room_controller.cpp
// 방 컨트롤러 구현 파일
// 방 생성, 참가, 목록 조회 등의 요청을 처리하는 컨트롤러
#include "room_controller.h"
#include <spdlog/spdlog.h>
#include <nlohmann/json.hpp>
namespace game_server {
using json = nlohmann::json;
RoomController::RoomController(std::shared_ptr<RoomService> roomService)
: roomService_(roomService) {
}
nlohmann::json RoomController::handleRequest(json& request) {
// 요청의 action 필드에 따라 적절한 핸들러 호출
std::string action = request["action"];
if (action == "createRoom") {
return handleCreateRoom(request);
}
else if (action == "joinRoom") {
return handleJoinRoom(request);
}
else if (action == "exitRoom") {
return handleExitRoom(request);
}
else if (action == "listRooms") {
return handleListRooms(request);
}
else {
json error_response = {
{"status", "error"},
{"message", "알 수 없는 방 액션"}
};
return error_response;
}
}
nlohmann::json RoomController::handleCreateRoom(json& request) {
json response = roomService_->createRoom(request);
return response;
}
nlohmann::json RoomController::handleJoinRoom(json& request) {
json response = roomService_->joinRoom(request);
return response;
}
nlohmann::json RoomController::handleExitRoom(json& request) {
json response = roomService_->exitRoom(request);
return response;
}
nlohmann::json RoomController::handleListRooms(json& request) {
auto response = roomService_->listRooms();
return response;
}
} // namespace game_server
인증 컨트롤러와 마찬가지로 각 action에 따라 메서드를 할당하고, 알맞은 비즈니스 로직을 수행한다.
룸 컨트롤러에서 주로 받아 핸들하는 내용은 다음과 같다.
- 방 생성 요청
- 방 참가 요청
- 방 퇴장 요청
- 방 정보 요청
game_controller.h
#pragma once
#include "controller.h"
#include "../service/game_service.h"
#include <memory>
namespace game_server {
class GameController : public Controller {
public:
explicit GameController(std::shared_ptr<GameService> gameService);
~GameController() override = default;
nlohmann::json handleRequest(nlohmann::json& request) override;
private:
nlohmann::json handleStartGame(nlohmann::json& request);
nlohmann::json handleEndGame(nlohmann::json& request);
std::shared_ptr<GameService> gameService_;
};
} // namespace game_server
게임 관련 컨트롤러 로직이 작성된 헤더 파일이다.
game_controller.cpp
// controller/game_controller.cpp
// 게임 컨트롤러 구현 파일
// 게임 시작 및 종료 요청을 처리하는 컨트롤러
#include "game_controller.h"
#include <spdlog/spdlog.h>
#include <nlohmann/json.hpp>
namespace game_server {
using json = nlohmann::json;
GameController::GameController(std::shared_ptr<GameService> gameService)
: gameService_(gameService) {
}
nlohmann::json GameController::handleRequest(json& request) {
// 요청의 action 필드에 따라 적절한 핸들러 호출
std::string action = request["action"];
if (action == "gameStart") {
return handleStartGame(request);
}
else if (action == "gameEnd") {
return handleEndGame(request);
}
else {
json error_response = {
{"status", "error"},
{"message", "알 수 없는 게임 액션"}
};
return error_response;
}
}
nlohmann::json GameController::handleStartGame(json& request) {
json response = gameService_->startGame(request);
return response;
}
nlohmann::json GameController::handleEndGame(json& request) {
json response = gameService_->endGame(request);
return response;
}
} // namespace game_server
게임 컨트롤러에서 주로 받아 핸들하는 내용은 다음과 같다.
- 게임 시작 요청
- 게임 종료 요청
사실 요청이라기 보단 게임 시작과 종료 수행 시 DB트랜잭션 처리와 관련된 내용이 주를 이룬다.
회고
기존 웹 프레임워크를 사용해 MVC패턴을 구현할 때에는 HTTP 요청에 따른 매핑이 필요하여 API호출을 컨트롤러 계층에서 받곤 했었다. 하지만 현재는 세션을 통해 action값의 종류에 따라 API를 핸들링 하기 때문에 컨트롤러의 로직이 매우 짧은 편에 속한다.
대신 세션이나 서비스 로직이 길어지는 부작용이 발생하였는데, request의 유효성 검증을 절차를 해당 로직에서 수행했으면 어떨까 하는 아쉬움이 남기는 한다. 하지만 어떤것이 정답인지는 잘 모르겠기 때문에 오히려 컨트롤러 쪽은 한번 작성 후 수정될 내용이 없어 좋은 것 같기도 하다.
'프로젝트 > [메타버스 게임] 캐쥬얼 배틀로얄' 카테고리의 다른 글
[SmashUp!] 캐쥬얼 배틀로얄 프로젝트 레포지토리 계층 (1) | 2025.04.09 |
---|---|
[SmashUp!] 캐쥬얼 배틀로얄 프로젝트 서비스 계층 (0) | 2025.04.09 |
[SmashUp!] 캐쥬얼 배틀로얄 프로젝트 코어 계층(서버, 세션) (1) | 2025.04.08 |
[SmashUp!] 캐쥬얼 배틀로얄 프로젝트 계층형 아키텍쳐 구현 (0) | 2025.04.01 |
[SmashUp!] 캐쥬얼 배틀로얄 프로젝트 Linux 빌드 환경 세팅(Makefile) (0) | 2025.03.31 |