110 lines
3.4 KiB
C++
110 lines
3.4 KiB
C++
#include "Session.h"
|
|
#include "PacketHandler.h"
|
|
#include "SessionManager.h"
|
|
#include <boost/asio/co_spawn.hpp>
|
|
#include <boost/asio/detached.hpp>
|
|
#include <cstring>
|
|
|
|
Session::Session(tcp::socket socket) : socket_(std::move(socket)) {}
|
|
|
|
Session::~Session() {
|
|
// 필요한 경우 정리 작업 수행
|
|
}
|
|
|
|
void Session::SetNickname(const std::string &nickname) { nickname_ = nickname; }
|
|
const std::string &Session::GetNickname() const { return nickname_; }
|
|
|
|
void Session::SetGold(uint64_t gold) { gold_ = gold; }
|
|
uint64_t Session::GetGold() const { return gold_; }
|
|
|
|
void Session::SetSwordLevel(uint32_t level) { swordLevel_ = level; }
|
|
uint32_t Session::GetSwordLevel() const { return swordLevel_; }
|
|
|
|
void Session::Start() { DoReadHeader(); }
|
|
|
|
void Session::SendPacket(PacketID id) {
|
|
PacketHeader header;
|
|
header.id = static_cast<uint16_t>(id);
|
|
header.size = 0;
|
|
std::vector<uint8_t> buffer(sizeof(PacketHeader));
|
|
std::memcpy(buffer.data(), &header, sizeof(PacketHeader));
|
|
Send(buffer);
|
|
}
|
|
|
|
void Session::Send(std::span<const uint8_t> data) {
|
|
auto self(shared_from_this());
|
|
boost::asio::post(
|
|
socket_.get_executor(),
|
|
[this, self,
|
|
msg = std::vector<uint8_t>(data.begin(), data.end())]() mutable {
|
|
bool writeInProgress = !writeQueue_.empty();
|
|
writeQueue_.push_back(std::move(msg));
|
|
if (!writeInProgress) {
|
|
DoWrite();
|
|
}
|
|
});
|
|
}
|
|
|
|
void Session::DoReadHeader() {
|
|
auto self(shared_from_this());
|
|
boost::asio::async_read(
|
|
socket_, boost::asio::buffer(&packetHeader_, sizeof(PacketHeader)),
|
|
[this, self](boost::system::error_code ec, std::size_t /*length*/) {
|
|
if (!ec) {
|
|
// 바디 크기 결정
|
|
// 안전 확인: 메모리 고갈을 방지하기 위해 최대 패킷 크기 제한
|
|
if (packetHeader_.size > 1024 * 10) {
|
|
socket_.close();
|
|
return;
|
|
}
|
|
|
|
packetBody_.resize(packetHeader_.size);
|
|
DoReadBody();
|
|
} else {
|
|
// 연결 끊김 또는 에러 발생 시 매니저에서 제거
|
|
SessionManager::GetInstance().Leave(self);
|
|
}
|
|
});
|
|
}
|
|
|
|
void Session::DoReadBody() {
|
|
auto self(shared_from_this());
|
|
boost::asio::async_read(
|
|
socket_, boost::asio::buffer(packetBody_.data(), packetBody_.size()),
|
|
[this, self](boost::system::error_code ec, std::size_t /*length*/) {
|
|
if (!ec) {
|
|
Packet packet;
|
|
packet.header = packetHeader_;
|
|
packet.payload = packetBody_;
|
|
|
|
// 패킷 핸들러 코루틴 실행
|
|
boost::asio::co_spawn(
|
|
socket_.get_executor(),
|
|
PacketHandler::HandlePacket(self, std::move(packet)),
|
|
boost::asio::detached);
|
|
|
|
// 계속해서 읽기
|
|
DoReadHeader();
|
|
} else {
|
|
// 에러 발생 시 매니저에서 제거
|
|
SessionManager::GetInstance().Leave(self);
|
|
}
|
|
});
|
|
}
|
|
|
|
void Session::DoWrite() {
|
|
auto self(shared_from_this());
|
|
boost::asio::async_write(
|
|
socket_, boost::asio::buffer(writeQueue_.front()),
|
|
[this, self](boost::system::error_code ec, std::size_t /*length*/) {
|
|
if (!ec) {
|
|
writeQueue_.pop_front();
|
|
if (!writeQueue_.empty()) {
|
|
DoWrite();
|
|
}
|
|
} else {
|
|
// 에러 발생 시 매니저에서 제거
|
|
SessionManager::GetInstance().Leave(self);
|
|
}
|
|
});
|
|
}
|