/* libobby - Network text editing library * Copyright (C) 2005, 2006 0x539 dev group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _OBBY_HOST_BUFFER_HPP_ #define _OBBY_HOST_BUFFER_HPP_ #include #include #include "command.hpp" #include "host_document_info.hpp" #include "server_buffer.hpp" #include "local_buffer.hpp" namespace obby { template class basic_host_buffer: virtual public basic_local_buffer, virtual public basic_server_buffer { public: // Document info typedef typename basic_server_buffer:: base_document_info_type base_document_info_type; typedef basic_host_document_info document_info_type; // Network typedef typename basic_server_buffer:: base_net_type base_net_type; typedef net6::basic_host net_type; // TODO: Move this parameters into the open() call. The call would have // to lose its virtualness, but should be better nevertheless. /** Creates a new host_buffer. * @param username User name for the local user. * @param colour Local user colour. */ basic_host_buffer(const std::string& username, const colour& colour); /** Opens the server on the given port. */ virtual void open(unsigned int port); /** Opens the server on the given port and resumes the obby session * stored in the given file. */ virtual void open(const std::string& session, unsigned int port); /** Looks for a document with the given ID which belongs to the user * with the given owner ID. Note that we do not take a real user object * here because the ID is enough and one might not have a user object * to the corresponding ID. So a time-consuming lookup is obsolete. */ document_info_type* document_find(unsigned int owner_id, unsigned int id) const; /** Returns the local user. */ virtual const user& get_self() const; /** Sends a global message to all users. */ virtual void send_message(const std::string& message); /** Sends a message to the given user. */ virtual void send_message(const std::string& message, const user& to); /** @brief Executes a command. */ virtual void send_command(const command_query& query); /** Creates a new document with predefined content. * signal_insert_document will be emitted and may be used to access * the resulting obby::document. */ virtual void document_create(const std::string& title, const std::string& encoding, const std::string& content); /** Sets a new colour for the local user. */ virtual void set_colour(const colour& colour); protected: /** Creates a new document info object according to the type of buffer. */ virtual base_document_info_type* new_document_info(const user* owner, unsigned int id, const std::string& title, const std::string& encoding, const std::string& content); /** Creates a new document info deserialised from a serialisation * object according to the type of buffer. */ virtual base_document_info_type* new_document_info(const serialise::object& obj); /** Creates the underlaying net6 network object corresponding to the * buffer's type. */ virtual base_net_type* new_net(); /** @brief Creates the local user after the user table has been * deserialised. */ void on_user_table_deserialised(); /** @brief Closes the session. */ virtual void session_close(); /** @brief Implementation of session_close() that does not call * a base function. */ void session_close_impl(); std::string m_username; colour m_colour; const user* m_self; private: /** @brief Common initialisation function called by both constructors * to avoid code duplication. */ void init_impl(); /** This function provides access to the underlaying net6::basic_host * object. */ net_type& net6_host(); /** This function provides access to the underlaying net6::basic_host * object. */ const net_type& net6_host() const; }; typedef basic_host_buffer host_buffer; template basic_host_buffer:: basic_host_buffer(const std::string& username, const colour& colour): basic_buffer(), basic_local_buffer(), basic_server_buffer(), m_username(username), m_colour(colour), m_self(NULL) { init_impl(); } template void basic_host_buffer::open(unsigned int port) { // Must NULL m_self here. If server open fails, the user table will // be cleared without having called on_user_table_deserialised // and m_self would refer to nothing anymore. m_self = NULL; basic_server_buffer::open(port); on_user_table_deserialised(); } template void basic_host_buffer::open(const std::string& session, unsigned int port) { m_self = NULL; // (same as above) basic_server_buffer::open(session, port); // on_user_table_deserialised() is called automatically by the user // table after all other users have been loaded } template typename basic_host_buffer::document_info_type* basic_host_buffer:: document_find(unsigned int owner_id, unsigned int id) const { return dynamic_cast( basic_server_buffer::document_find( owner_id, id ) ); } template const user& basic_host_buffer::get_self() const { if(m_self == NULL) { throw std::logic_error( "obby::host_buffer::get_self:\n" "Local user is not available This probably means that " "the server has never been opened" ); } return *m_self; } template void basic_host_buffer:: send_message(const std::string& message) { if(m_self == NULL) { throw std::logic_error( "obby::host_buffer::send_message:\n" "Local user is not available. This probably means " "that the server has never been opened" ); } // Send message from local user instead of server basic_server_buffer::send_message_impl( message, m_self ); } template void basic_host_buffer:: send_message(const std::string& message, const user& to) { if(m_self == NULL) { throw std::logic_error( "obby::host_buffer::send_message:\n" "Local user is not available. This probably means " "that the server has never been opened" ); } // Send message from local user instead of server basic_server_buffer::send_message_impl( message, m_self, to ); } template void basic_host_buffer:: send_command(const command_query& query) { if(m_self == NULL) { throw std::logic_error( "obby::host_buffer::send_command:\n" "Local user is not available. This probably means " "that the server has never been opened" ); } // Execute command locally, report result basic_local_buffer::m_command_queue.query(query); command_result result = basic_server_buffer:: m_command_map.exec_command(*m_self, query); basic_local_buffer::m_command_queue.result(result); } template void basic_host_buffer:: document_create(const std::string& title, const std::string& encoding, const std::string& content) { if(m_self == NULL) { throw std::logic_error( "obby::host_buffer::document_create:\n" "Local user is not available This probably means that " "the server has never been opened" ); } unsigned int id = ++ basic_buffer::m_doc_counter; // Create document with local user as owner instead of NULL indicating // that it is the server's document. basic_server_buffer::document_create_impl( m_self, id, title, encoding, content ); } template void basic_host_buffer::set_colour(const colour& colour) { if(m_self == NULL) { throw std::logic_error( "obby::host_buffer::set_colour:\n" "Local user is not available This probably means that " "the server has never been opened" ); } // Check for colour conflicts // TODO: user_colour_impl should check this if(!basic_buffer::check_colour(colour, m_self)) { basic_local_buffer:: m_signal_user_colour_failed.emit(); } else { basic_server_buffer::user_colour_impl( *m_self, colour ); } } template void basic_host_buffer::on_user_table_deserialised() { // Create user local user m_self = basic_buffer::m_user_table.add_user( basic_buffer::m_user_table.find_free_id(), net6_host().get_self(), m_colour ); basic_buffer::m_signal_user_join.emit(*m_self); } template void basic_host_buffer::session_close() { session_close_impl(); basic_local_buffer::session_close_impl(); basic_buffer::session_close_impl(); } template void basic_host_buffer::session_close_impl() { // Keep self until reopening } template void basic_host_buffer::init_impl() { user_table& table = this->m_user_table; table.deserialised_event().connect( sigc::mem_fun( *this, &basic_host_buffer::on_user_table_deserialised ) ); } template typename basic_host_buffer::base_document_info_type* basic_host_buffer:: new_document_info(const user* owner, unsigned int id, const std::string& title, const std::string& encoding, const std::string& content) { // Create host_document_info, according to host_buffer return new document_info_type( *this, net6_host(), owner, id, title, encoding, content ); } template typename basic_host_buffer::base_document_info_type* basic_host_buffer:: new_document_info(const serialise::object& obj) { // Create host_document_info, according to host_buffer return new document_info_type(*this, net6_host(), obj); } template typename basic_host_buffer::base_net_type* basic_host_buffer::new_net() { return new net_type(m_username); } template typename basic_host_buffer::net_type& basic_host_buffer::net6_host() { return dynamic_cast( *basic_buffer::m_net ); } template const typename basic_host_buffer::net_type& basic_host_buffer::net6_host() const { return dynamic_cast( *basic_buffer::m_net ); } } // namespace obby #endif // _OBBY_HOST_BUFFER_HPP_