scar-chat7/server/session.cpp
2025-12-07 12:00:44 -07:00

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