148 lines
5.2 KiB
C++
148 lines
5.2 KiB
C++
|
|
#include "session.h"
|
||
|
|
#include "server.h"
|
||
|
|
#include <iostream>
|
||
|
|
|
||
|
|
namespace scar {
|
||
|
|
|
||
|
|
Session::Session(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket,
|
||
|
|
std::shared_ptr<Authenticator> auth,
|
||
|
|
Server* server)
|
||
|
|
: socket_(std::move(socket)), auth_(auth), server_(server), authenticated_(false) {}
|
||
|
|
|
||
|
|
void Session::start() {
|
||
|
|
doHandshake();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Session::doHandshake() {
|
||
|
|
auto self(shared_from_this());
|
||
|
|
socket_.async_handshake(boost::asio::ssl::stream_base::server,
|
||
|
|
[this, self](const boost::system::error_code& error) {
|
||
|
|
if (!error) {
|
||
|
|
std::cout << "SSL handshake completed" << std::endl;
|
||
|
|
doReadHeader();
|
||
|
|
} else {
|
||
|
|
std::cerr << "SSL handshake error: " << error.message() << std::endl;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
void Session::doReadHeader() {
|
||
|
|
read_buffer_.resize(sizeof(MessageHeader));
|
||
|
|
|
||
|
|
auto self(shared_from_this());
|
||
|
|
boost::asio::async_read(socket_,
|
||
|
|
boost::asio::buffer(read_buffer_),
|
||
|
|
[this, self](const boost::system::error_code& error, std::size_t /*length*/) {
|
||
|
|
if (!error) {
|
||
|
|
MessageHeader header;
|
||
|
|
std::memcpy(&header, read_buffer_.data(), sizeof(MessageHeader));
|
||
|
|
|
||
|
|
if (header.length > sizeof(MessageHeader)) {
|
||
|
|
doReadBody(header.length - sizeof(MessageHeader));
|
||
|
|
} else {
|
||
|
|
doReadHeader();
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
std::cerr << "Read error: " << error.message() << std::endl;
|
||
|
|
if (authenticated_) {
|
||
|
|
server_->removeSession(shared_from_this());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
void Session::doReadBody(uint32_t length) {
|
||
|
|
auto body_buffer = std::make_shared<std::vector<uint8_t>>(length);
|
||
|
|
|
||
|
|
auto self(shared_from_this());
|
||
|
|
boost::asio::async_read(socket_,
|
||
|
|
boost::asio::buffer(*body_buffer),
|
||
|
|
[this, self, body_buffer](const boost::system::error_code& error, std::size_t /*bytes*/) {
|
||
|
|
if (!error) {
|
||
|
|
// Combine header and body
|
||
|
|
std::vector<uint8_t> full_message;
|
||
|
|
full_message.insert(full_message.end(), read_buffer_.begin(), read_buffer_.end());
|
||
|
|
full_message.insert(full_message.end(), body_buffer->begin(), body_buffer->end());
|
||
|
|
|
||
|
|
try {
|
||
|
|
auto message = Message::deserialize(full_message);
|
||
|
|
handleMessage(std::move(message));
|
||
|
|
} catch (const std::exception& e) {
|
||
|
|
std::cerr << "Message deserialization error: " << e.what() << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
doReadHeader();
|
||
|
|
} else {
|
||
|
|
std::cerr << "Read error: " << error.message() << std::endl;
|
||
|
|
if (authenticated_) {
|
||
|
|
server_->removeSession(shared_from_this());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
void Session::handleMessage(std::unique_ptr<Message> message) {
|
||
|
|
std::cout << "Received message type: " << static_cast<int>(message->type()) << std::endl;
|
||
|
|
|
||
|
|
switch (message->type()) {
|
||
|
|
case MessageType::LOGIN_REQUEST:
|
||
|
|
handleLoginRequest(*dynamic_cast<LoginRequest*>(message.get()));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MessageType::TEXT_MESSAGE:
|
||
|
|
if (authenticated_) {
|
||
|
|
server_->broadcastMessage(*dynamic_cast<TextMessage*>(message.get()));
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
std::cerr << "Unhandled message type" << std::endl;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void Session::handleLoginRequest(const LoginRequest& request) {
|
||
|
|
std::cout << "LoginRequest received - Username: '" << request.username()
|
||
|
|
<< "', Password length: " << request.password().length() << std::endl;
|
||
|
|
|
||
|
|
std::string token = auth_->authenticate(request.username(), request.password());
|
||
|
|
|
||
|
|
if (!token.empty()) {
|
||
|
|
authenticated_ = true;
|
||
|
|
username_ = request.username();
|
||
|
|
|
||
|
|
LoginResponse response(true, token);
|
||
|
|
std::cout << "Sending successful LoginResponse with token" << std::endl;
|
||
|
|
send(response);
|
||
|
|
|
||
|
|
server_->addSession(shared_from_this());
|
||
|
|
} else {
|
||
|
|
LoginResponse response(false, "", ErrorCode::AUTH_FAILED);
|
||
|
|
std::cout << "Sending failed LoginResponse" << std::endl;
|
||
|
|
send(response);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void Session::send(const Message& message) {
|
||
|
|
auto self(shared_from_this());
|
||
|
|
write_buffer_ = message.serialize();
|
||
|
|
|
||
|
|
std::cout << "Sending message type " << static_cast<int>(message.type())
|
||
|
|
<< ", size: " << write_buffer_.size() << " bytes" << std::endl;
|
||
|
|
|
||
|
|
boost::asio::async_write(socket_,
|
||
|
|
boost::asio::buffer(write_buffer_),
|
||
|
|
[this, self](const boost::system::error_code& error, std::size_t bytes) {
|
||
|
|
if (error) {
|
||
|
|
std::cerr << "Write error: " << error.message() << std::endl;
|
||
|
|
if (authenticated_) {
|
||
|
|
server_->removeSession(shared_from_this());
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
std::cout << "Successfully sent " << bytes << " bytes" << std::endl;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace scar
|