From 18e73025a15b98aae008ffe5a19570a0e5ea19ef Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Tue, 7 Dec 2010 02:02:42 +0100 Subject: Completed framework for reconnection. Still missing client-fallback and resync upon reconnect. --- server/client.cpp | 51 ++++++++++++++++++++++++++++++++++----------------- server/client.h | 30 +++++++++++++++--------------- server/lobby.cpp | 48 ++++++++++++++++++++++++++++++++++-------------- server/lobby.h | 2 +- 4 files changed, 84 insertions(+), 47 deletions(-) diff --git a/server/client.cpp b/server/client.cpp index 07a59f4..af2494e 100644 --- a/server/client.cpp +++ b/server/client.cpp @@ -2,32 +2,53 @@ #include -Client::p Client::create(Connection::p c, boost::function f) { - Client::p p(new Client(c)); - p->start(f); +std::map > Client::client_list; + +Client::p Client::create(Connection::p c, std::string n) { + Client::p p(new Client(c, n)); + p->start(); return p; } -Client::Client(Connection::p c) : connection(c), timer(c->socket.get_io_service()) { +Client::p Client::exists(Message::Login::p login_msg) { + if(client_list.count(login_msg->cookie)) { + // Obtain shared pointer to existing client. + Client::p client = client_list[login_msg->cookie].lock(); + + // TODO: Check if game still is ongoing? + // A client should only be reconnected to if still participating in an active game. + // It may however be proven that a client is always destructed if the game has ended, so this test might not be neccessary. + + return client; + + } else { + // No or invalid existing client found. + return Client::p(); + } +} + +Client::Client(Connection::p c, std::string n) : connection(c), timer(c->socket.get_io_service()), nick_(n) { } -void Client::disconnect() { - //delete connection; - //connection = NULL; - //We need to make this player dumb? +Client::~Client() { + client_list.erase(cookie); } void Client::reconnect(Connection::p c) { connection = c; + // TODO: Resync client. } -void Client::start(boost::function f) { - // Send Hello. - connection->send(make_shared("aotenjoud git")); +void Client::start() { + // Create a unique cookie for this client. + cookie = uint64_t(this); // TODO: Use a better cookie source. + + // Store a weak pointer to this client. + client_list[cookie] = shared_from_this(); - // Wait for Login. - connection->recv(boost::bind(&Client::handle_login, shared_from_this(), _1, f)); + // Logged in to lobby. + connection->send(make_shared(Message::LoginResponse::Lobby)); } void Client::handle_login(Message::p msg, boost::function login_callback) { @@ -94,10 +115,6 @@ void Client::lobby_status(const std::vector& game_modes, boost::fun connection->recv(boost::bind(&Client::handle_lobby, shared_from_this(), _1, callback)); } -unsigned int Client::id() { - return id_; -} - std::string Client::nick() { return nick_; } diff --git a/server/client.h b/server/client.h index 676264e..82968b4 100644 --- a/server/client.h +++ b/server/client.h @@ -2,6 +2,7 @@ #define CLIENT_H #include +#include #include #include #include @@ -16,9 +17,6 @@ class ClientBase { virtual ~ClientBase() {} - //! Return client's id. - virtual unsigned int id() = 0; - //! Return client's nick. virtual std::string nick() = 0; @@ -44,21 +42,29 @@ class Client : public ClientBase, public boost::enable_shared_from_this public: typedef boost::shared_ptr p; - static p create(Connection::p c, boost::function f); + //! Construct and return a new Client instance. + static p create(Connection::p c, std::string n); + + //! Check if a Client instance of the user already exists and return it. + static p exists(Message::Login::p login_msg); + + ~Client(); private: + uint64_t cookie; + + static std::map > client_list; + Connection::p connection; boost::asio::deadline_timer timer; - unsigned int id_; - std::string nick_; - Client(Connection::p c); + Client(Connection::p c, std::string n); //! Start communicating. - void start(boost::function f); + void start(); //! Handle Login-message. void handle_login(Message::p msg, boost::function login_callback); @@ -76,9 +82,6 @@ class Client : public ClientBase, public boost::enable_shared_from_this //! Inform client of lobby status (available game modes). void lobby_status(const std::vector& game_modes, boost::function callback); - //! Return client's id. - virtual unsigned int id(); - //! Return client's nick. virtual std::string nick(); @@ -97,10 +100,7 @@ class Client : public ClientBase, public boost::enable_shared_from_this //! Get action. Upon connection error, last element of expected_actions will be provided. virtual void get_action(boost::function callback, Actions expected_actions); - //! Dis-connect a player. - virtual void disconnect(); - - //! Re-connect a player. + //! Reconnect a player. virtual void reconnect(Connection::p c); }; diff --git a/server/lobby.cpp b/server/lobby.cpp index 7939977..9fb769e 100644 --- a/server/lobby.cpp +++ b/server/lobby.cpp @@ -7,27 +7,47 @@ #include "game.h" void Lobby::handle_connect(Connection::p connection) { - // Create player. - Client::create(connection, boost::bind(&Lobby::handle_login, this, _1)); + // Send Hello. + connection->send(make_shared("aotenjoud git")); + + // Wait for Login. + connection->recv(boost::bind(&Lobby::handle_login, this, connection, _1)); // Get another connection. server.get_connection(boost::bind(&Lobby::handle_connect, this, _1)); } -void Lobby::handle_login(Client::p client) { - std::cout << "Client " << client->nick() << " entered the lobby." << std::endl; +void Lobby::handle_login(Connection::p connection, Message::p msg) { + if(msg->type != Message::Types::Login) { + return; + } - if(0) {//client->id != 0 - //We check if player is in an ongoing game? - - } else { - std::vector game_modes; - - game_modes.push_back("1p test mode"); - game_modes.push_back("4p test mode"); - - client->lobby_status(game_modes, boost::bind(&Lobby::handle_action, this, client, _1)); + Message::Login::p login_msg = dynamic_pointer_cast(msg); + + Client::p client; + + // Check if this is a reconnection attempt and whether a reconnection is possible. + if(login_msg->cookie && (client = Client::exists(login_msg))) { + client->reconnect(connection); + return; } + + // Validate nick. + if(login_msg->nick.size() == 0) { + connection->send(make_shared(Message::LoginResponse::Invalid)); + connection->recv(boost::bind(&Lobby::handle_login, this, connection, _1)); + return; + } + + // Create a new client. + client = Client::create(connection, login_msg->nick); + + std::vector game_modes; + + game_modes.push_back("1p test mode"); + game_modes.push_back("4p test mode"); + + client->lobby_status(game_modes, boost::bind(&Lobby::handle_action, this, client, _1)); } void Lobby::handle_action(Client::p client, int game_mode) { diff --git a/server/lobby.h b/server/lobby.h index fa0e5fe..c445506 100644 --- a/server/lobby.h +++ b/server/lobby.h @@ -19,7 +19,7 @@ class Lobby { void handle_connect(Connection::p connection); //! Handle login. - void handle_login(Client::p client); + void handle_login(Connection::p connection, Message::p msg); //! Handle action. void handle_action(Client::p client, int game_mode); -- cgit v1.2.3