Changeset - 3dc02f0cb31d
[Not reviewed]
0 4 0
Jan Kaluza - 14 years ago 2011-05-27 14:57:44
hanzz.k@gmail.com
Disconnect XMPP user if backend crashes or is killed
4 files changed with 63 insertions and 52 deletions:
0 comments (0 inline, 0 general)
docs/Doxyfile
Show inline comments
 
@@ -1400,97 +1400,97 @@ TEMPLATE_RELATIONS     = NO
 
# other documented files.
 

	
 
INCLUDE_GRAPH          = YES
 

	
 
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
 
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
 
# documented header file showing the documented files that directly or 
 
# indirectly include this file.
 

	
 
INCLUDED_BY_GRAPH      = YES
 

	
 
# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
 
# doxygen will generate a call dependency graph for every global function 
 
# or class method. Note that enabling this option will significantly increase 
 
# the time of a run. So in most cases it will be better to enable call graphs 
 
# for selected functions only using the \callgraph command.
 

	
 
CALL_GRAPH             = NO
 

	
 
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
 
# doxygen will generate a caller dependency graph for every global function 
 
# or class method. Note that enabling this option will significantly increase 
 
# the time of a run. So in most cases it will be better to enable caller 
 
# graphs for selected functions only using the \callergraph command.
 

	
 
CALLER_GRAPH           = NO
 

	
 
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
 
# will graphical hierarchy of all classes instead of a textual one.
 

	
 
GRAPHICAL_HIERARCHY    = YES
 

	
 
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
 
# then doxygen will show the dependencies a directory has on other directories 
 
# in a graphical way. The dependency relations are determined by the #include 
 
# relations between the files in the directories.
 

	
 
DIRECTORY_GRAPH        = YES
 

	
 
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
 
# generated by dot. Possible values are png, jpg, or gif 
 
# If left blank png will be used.
 

	
 
DOT_IMAGE_FORMAT       = png
 

	
 
# The tag DOT_PATH can be used to specify the path where the dot tool can be 
 
# found. If left blank, it is assumed the dot tool can be found in the path.
 

	
 
DOT_PATH               = ""
 
DOT_PATH               = "/usr/bin"
 

	
 
# The DOTFILE_DIRS tag can be used to specify one or more directories that 
 
# contain dot files that are included in the documentation (see the 
 
# \dotfile command).
 

	
 
DOTFILE_DIRS           = 
 

	
 
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
 
# nodes that will be shown in the graph. If the number of nodes in a graph 
 
# becomes larger than this value, doxygen will truncate the graph, which is 
 
# visualized by representing a node as a red box. Note that doxygen if the 
 
# number of direct children of the root node in a graph is already larger than 
 
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
 
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
 

	
 
DOT_GRAPH_MAX_NODES    = 50
 

	
 
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
 
# graphs generated by dot. A depth value of 3 means that only nodes reachable 
 
# from the root by following a path via at most 3 edges will be shown. Nodes 
 
# that lay further from the root node will be omitted. Note that setting this 
 
# option to 1 or 2 may greatly reduce the computation time needed for large 
 
# code bases. Also note that the size of a graph can be further restricted by 
 
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
 

	
 
MAX_DOT_GRAPH_DEPTH    = 0
 

	
 
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
 
# background. This is disabled by default, because dot on Windows does not 
 
# seem to support this out of the box. Warning: Depending on the platform used, 
 
# enabling this option may lead to badly anti-aliased labels on the edges of 
 
# a graph (i.e. they become hard to read).
 

	
 
DOT_TRANSPARENT        = YES
 

	
 
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
 
# files in one run (i.e. multiple -o and -T options on the command line). This 
 
# makes dot run faster, but since only newer versions of dot (>1.8.10) 
 
# support this, this feature is disabled by default.
 

	
 
DOT_MULTI_TARGETS      = NO
 

	
 
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
 
# generate a legend page explaining the meaning of the various boxes and 
 
# arrows in the dot generated graphs.
 

	
 
GENERATE_LEGEND        = YES
 

	
include/transport/networkpluginserver.h
Show inline comments
 
/**
 
 * libtransport -- C++ library for easy XMPP Transports development
 
 *
 
 * Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
 
 *
 
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#pragma once
 

	
 
#include <time.h>
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Presence/PresenceOracle.h"
 
#include "Swiften/Disco/EntityCapsManager.h"
 
#include "Swiften/Network/ConnectionServer.h"
 
#include "Swiften/Network/Connection.h"
 
#include "storagebackend.h"
 

	
 
namespace Transport {
 

	
 
class UserManager;
 
class User;
 
class Component;
 
class Buddy;
 
class LocalBuddy;
 
class Config;
 
class NetworkConversation;
 

	
 
class NetworkPluginServer {
 
	public:
 
		struct Client {
 
			bool pongReceived;
 
			std::list<User *> users;
 
			std::string data;
 
			boost::shared_ptr<Swift::Connection> connection;
 
		};
 

	
 
		NetworkPluginServer(Component *component, Config *config, UserManager *userManager);
 

	
 
		virtual ~NetworkPluginServer();
 

	
 
		void handleMessageReceived(NetworkConversation *conv, boost::shared_ptr<Swift::Message> &message);
 

	
 
	private:
 
		void handleNewClientConnection(boost::shared_ptr<Swift::Connection> c);
 
		void handleSessionFinished(boost::shared_ptr<Swift::Connection>);
 
		void handleDataRead(boost::shared_ptr<Swift::Connection>, const Swift::ByteArray&);
 
		void handleSessionFinished(Client *c);
 
		void handleDataRead(Client *c, const Swift::ByteArray&);
 

	
 
		void handleConnectedPayload(const std::string &payload);
 
		void handleDisconnectedPayload(const std::string &payload);
 
		void handleBuddyChangedPayload(const std::string &payload);
 
		void handleConvMessagePayload(const std::string &payload, bool subject = false);
 
		void handleParticipantChangedPayload(const std::string &payload);
 
		void handleRoomChangedPayload(const std::string &payload);
 

	
 
		void handleUserCreated(User *user);
 
		void handleRoomJoined(User *user, const std::string &room, const std::string &nickname, const std::string &password);
 
		void handleRoomLeft(User *user, const std::string &room);
 
		void handleUserReadyToConnect(User *user);
 
		void handleUserDestroyed(User *user);
 

	
 
		void send(boost::shared_ptr<Swift::Connection> &, const std::string &data);
 

	
 
		void pingTimeout();
 
		void sendPing(boost::shared_ptr<Swift::Connection> c);
 
		boost::shared_ptr<Swift::Connection> getFreeClient();
 
		void sendPing(Client *c);
 
		Client *getFreeClient();
 

	
 
		UserManager *m_userManager;
 
		Config *m_config;
 
		boost::shared_ptr<Swift::ConnectionServer> m_server;
 
		std::map<boost::shared_ptr<Swift::Connection>, Client >  m_clients;
 
		std::list<Client *>  m_clients;
 
		Swift::Timer::ref m_pingTimer;
 
};
 

	
 
}
include/transport/user.h
Show inline comments
 
@@ -52,52 +52,51 @@ class User {
 
		const Swift::JID &getJID();
 

	
 
		/// Returns UserInfo struct with informations needed to connect the legacy network.
 
		/// \return UserInfo struct
 
		UserInfo &getUserInfo() { return m_userInfo; }
 

	
 
		RosterManager *getRosterManager() { return m_rosterManager; }
 

	
 
		ConversationManager *getConversationManager() { return m_conversationManager; }
 

	
 
		Component *getComponent() { return m_component; }
 

	
 
		void setData(void *data) { m_data = data; }
 
		void *getData() { return m_data; }
 

	
 
		/// Handles presence from XMPP JID associated with this user.
 
		/// \param presence Swift::Presence.
 
		void handlePresence(Swift::Presence::ref presence);
 

	
 
		void handleSubscription(Swift::Presence::ref presence);
 

	
 
		/// Returns language.
 
		/// \return language
 
		const char *getLang() { return "en"; }
 

	
 
		void handleDisconnected(const std::string &error);
 

	
 
		boost::signal<void ()> onReadyToConnect;
 
		boost::signal<void (const std::string &room, const std::string &nickname, const std::string &password)> onRoomJoined;
 
		boost::signal<void (const std::string &room)> onRoomLeft;
 
		boost::signal<void ()> onDisconnected;
 

	
 
	private:
 
		void onConnectingTimeout();
 

	
 
		Swift::JID m_jid;
 
		Component *m_component;
 
		RosterManager *m_rosterManager;
 
		UserManager *m_userManager;
 
		ConversationManager *m_conversationManager;
 
		Swift::EntityCapsManager *m_entityCapsManager;
 
		Swift::PresenceOracle *m_presenceOracle;
 
		UserInfo m_userInfo;
 
		void *m_data;
 
		bool m_connected;
 
		bool m_readyForConnect;
 
		Swift::Timer::ref m_reconnectTimer;
 
		boost::shared_ptr<Swift::Connection> connection;
 
		friend class NetworkPluginServer;
 
};
 

	
 
}
src/networkpluginserver.cpp
Show inline comments
 
@@ -81,117 +81,120 @@ static int exec_(const char *path, const char *host, const char *port, const cha
 
		// child process
 
		execlp(path, path, "--host", host, "--port", port, config, NULL);
 
		exit(1);
 
	} else if ( pid < 0 ) {
 
		// fork failed
 
		status = -1;
 
	}
 
	return status;
 
}
 

	
 
static void SigCatcher(int n) {
 
	wait3(NULL,WNOHANG,NULL);
 
}
 

	
 
static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payload) {
 
	buddy->setName(payload.buddyname());
 
	buddy->setAlias(payload.alias());
 
	std::vector<std::string> groups;
 
	groups.push_back(payload.groups());
 
	buddy->setGroups(groups);
 
	buddy->setStatus(Swift::StatusShow((Swift::StatusShow::Type) payload.status()), payload.statusmessage());
 
	buddy->setIconHash(payload.iconhash());
 
}
 

	
 
NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, UserManager *userManager) {
 
	m_userManager = userManager;
 
	m_config = config;
 
	component->m_factory = new NetworkFactory(this);
 
	m_userManager->onUserCreated.connect(boost::bind(&NetworkPluginServer::handleUserCreated, this, _1));
 
	m_userManager->onUserDestroyed.connect(boost::bind(&NetworkPluginServer::handleUserDestroyed, this, _1));
 

	
 
	m_pingTimer = component->getFactories()->getTimerFactory()->createTimer(10000);
 
	m_pingTimer->onTick.connect(boost::bind(&NetworkPluginServer::pingTimeout, this)); 
 

	
 
	m_server = component->getFactories()->getConnectionFactory()->createConnectionServer(10000);
 
	m_server->onNewConnection.connect(boost::bind(&NetworkPluginServer::handleNewClientConnection, this, _1));
 
	m_server->start();
 

	
 
	signal(SIGCHLD, SigCatcher);
 

	
 
	exec_(CONFIG_STRING(m_config, "service.backend").c_str(), "localhost", "10000", m_config->getConfigFile().c_str());
 
}
 

	
 
NetworkPluginServer::~NetworkPluginServer() {
 
	m_pingTimer->stop();
 
}
 

	
 
void NetworkPluginServer::handleNewClientConnection(boost::shared_ptr<Swift::Connection> c) {
 
	Client client;
 
	client.pongReceived = true;
 
	Client *client = new Client;
 
	client->pongReceived = true;
 
	client->connection = c;
 

	
 
	m_clients[c] = client;
 
	m_clients.push_back(client);
 

	
 
	c->onDisconnected.connect(boost::bind(&NetworkPluginServer::handleSessionFinished, this, c));
 
	c->onDataRead.connect(boost::bind(&NetworkPluginServer::handleDataRead, this, c, _1));
 
	sendPing(c);
 
	c->onDisconnected.connect(boost::bind(&NetworkPluginServer::handleSessionFinished, this, client));
 
	c->onDataRead.connect(boost::bind(&NetworkPluginServer::handleDataRead, this, client, _1));
 
	sendPing(client);
 
	m_pingTimer->start();
 
}
 

	
 
void NetworkPluginServer::handleSessionFinished(boost::shared_ptr<Swift::Connection> c) {
 
	for (std::list<User *>::const_iterator it = m_clients[c].users.begin(); it != m_clients[c].users.end(); it++) {
 
void NetworkPluginServer::handleSessionFinished(Client *c) {
 
	for (std::list<User *>::const_iterator it = c->users.begin(); it != c->users.end(); it++) {
 
		(*it)->setData(NULL);
 
		(*it)->handleDisconnected("Internal Server Error, please reconnect.");
 
	}
 

	
 
	m_clients.erase(c);
 
	m_clients.remove(c);
 
	delete c;
 

	
 
	// Execute new session only if there's no free one after this crash/disconnection
 
	for (std::map<boost::shared_ptr<Swift::Connection>, Client>::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) {
 
		if ((*it).second.users.size() < 1) {
 
	for (std::list<Client *>::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) {
 
		if ((*it)->users.size() < 1) {
 
			return;
 
		}
 
	}
 
	exec_(CONFIG_STRING(m_config, "service.backend").c_str(), "localhost", "10000", m_config->getConfigFile().c_str());
 
}
 

	
 
void NetworkPluginServer::handleConnectedPayload(const std::string &data) {
 
	pbnetwork::Connected payload;
 
	if (payload.ParseFromString(data) == false) {
 
		// TODO: ERROR
 
		return;
 
	}
 
// 	std::cout << payload.name() << "\n";
 
}
 

	
 
void NetworkPluginServer::handleDisconnectedPayload(const std::string &data) {
 
	pbnetwork::Disconnected payload;
 
	if (payload.ParseFromString(data) == false) {
 
		// TODO: ERROR
 
		return;
 
	}
 

	
 
	User *user = m_userManager->getUser(payload.user());
 
	if (!user)
 
		return;
 

	
 
	user->handleDisconnected(payload.message());
 
}
 

	
 
void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) {
 
	pbnetwork::Buddy payload;
 
	if (payload.ParseFromString(data) == false) {
 
		// TODO: ERROR
 
		return;
 
	}
 

	
 
	User *user = m_userManager->getUser(payload.username());
 
	if (!user)
 
		return;
 

	
 
	LocalBuddy *buddy = (LocalBuddy *) user->getRosterManager()->getBuddy(payload.buddyname());
 
	if (buddy) {
 
		handleBuddyPayload(buddy, payload);
 
		buddy->buddyChanged();
 
	}
 
	else {
 
		buddy = new LocalBuddy(user->getRosterManager(), -1);
 
		handleBuddyPayload(buddy, payload);
 
@@ -232,259 +235,267 @@ void NetworkPluginServer::handleParticipantChangedPayload(const std::string &dat
 

	
 
void NetworkPluginServer::handleRoomChangedPayload(const std::string &data) {
 
	pbnetwork::Room payload;
 
	if (payload.ParseFromString(data) == false) {
 
		return;
 
	}
 

	
 
	User *user = m_userManager->getUser(payload.username());
 
	if (!user)
 
		return;
 

	
 
	NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.room());
 
	if (!conv) {
 
		return;
 
	}
 

	
 
	conv->setNickname(payload.nickname());
 
}
 

	
 
void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool subject) {
 
	pbnetwork::ConversationMessage payload;
 
// 	std::cout << "payload...\n";
 
	if (payload.ParseFromString(data) == false) {
 
		// TODO: ERROR
 
		return;
 
	}
 
// 	std::cout << "payload 2...\n";
 
	User *user = m_userManager->getUser(payload.username());
 
	if (!user)
 
		return;
 

	
 
	boost::shared_ptr<Swift::Message> msg(new Swift::Message());
 
	if (subject) {
 
		msg->setSubject(payload.message());
 
	}
 
	else {
 
		msg->setBody(payload.message());
 
	}
 

	
 
	NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.buddyname());
 
	if (!conv) {
 
		conv = new NetworkConversation(user->getConversationManager(), payload.buddyname());
 
		conv->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, this, _1, _2));
 
	}
 

	
 
	conv->handleMessage(msg, payload.nickname());
 
}
 

	
 
void NetworkPluginServer::handleDataRead(boost::shared_ptr<Swift::Connection> c, const Swift::ByteArray &data) {
 
void NetworkPluginServer::handleDataRead(Client *c, const Swift::ByteArray &data) {
 
	long expected_size = 0;
 
	m_clients[c].data += data.toString();
 
	c->data += data.toString();
 
// 	std::cout << "received data; size = " << m_data.size() << "\n";
 
	while (m_clients[c].data.size() != 0) {
 
		if (m_clients[c].data.size() >= 4) {
 
			unsigned char * head = (unsigned char*) m_clients[c].data.c_str();
 
	while (c->data.size() != 0) {
 
		if (c->data.size() >= 4) {
 
			unsigned char * head = (unsigned char*) c->data.c_str();
 
			expected_size = (((((*head << 8) | *(head + 1)) << 8) | *(head + 2)) << 8) | *(head + 3);
 
			//expected_size = m_data[0];
 
// 			std::cout << "expected_size=" << expected_size << "\n";
 
			if (m_clients[c].data.size() - 4 < expected_size)
 
			if (c->data.size() - 4 < expected_size)
 
				return;
 
		}
 
		else {
 
			return;
 
		}
 

	
 
		std::string msg = m_clients[c].data.substr(4, expected_size);
 
		m_clients[c].data.erase(0, 4 + expected_size);
 
		std::string msg = c->data.substr(4, expected_size);
 
		c->data.erase(0, 4 + expected_size);
 

	
 
		pbnetwork::WrapperMessage wrapper;
 
		if (wrapper.ParseFromString(msg) == false) {
 
			// TODO: ERROR
 
			return;
 
		}
 

	
 
		switch(wrapper.type()) {
 
			case pbnetwork::WrapperMessage_Type_TYPE_CONNECTED:
 
				handleConnectedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_DISCONNECTED:
 
				handleDisconnectedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_BUDDY_CHANGED:
 
				handleBuddyChangedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_CONV_MESSAGE:
 
				handleConvMessagePayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_ROOM_SUBJECT_CHANGED:
 
				handleConvMessagePayload(wrapper.payload(), true);
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_PONG:
 
				m_clients[c].pongReceived = true;
 
				c->pongReceived = true;
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_PARTICIPANT_CHANGED:
 
				handleParticipantChangedPayload(wrapper.payload());
 
				break;
 
			case pbnetwork::WrapperMessage_Type_TYPE_ROOM_NICKNAME_CHANGED:
 
				handleRoomChangedPayload(wrapper.payload());
 
				break;
 
			default:
 
				return;
 
		}
 
	}
 
}
 

	
 
void NetworkPluginServer::send(boost::shared_ptr<Swift::Connection> &c, const std::string &data) {
 
	std::string header("    ");
 
	for (int i = 0; i != 4; ++i)
 
		header.at(i) = static_cast<char>(data.size() >> (8 * (3 - i)));
 
	
 
	c->write(Swift::ByteArray(header + data));
 
}
 

	
 
void NetworkPluginServer::pingTimeout() {
 
	std::cout << "pingtimeout\n";
 
	for (std::map<boost::shared_ptr<Swift::Connection>, Client>::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) {
 
		if ((*it).second.pongReceived) {
 
			sendPing((*it).first);
 
	for (std::list<Client *>::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) {
 
		if ((*it)->pongReceived) {
 
			sendPing((*it));
 
			m_pingTimer->start();
 
		}
 
		else {
 
			exec_(CONFIG_STRING(m_config, "service.backend").c_str(), "localhost", "10000", m_config->getConfigFile().c_str());
 
		}
 
	}
 
}
 

	
 
void NetworkPluginServer::handleUserCreated(User *user) {
 
	user->connection = getFreeClient();
 
	m_clients[user->connection].users.push_back(user);
 
	Client *c = getFreeClient();
 
	user->setData(c);
 
	c->users.push_back(user);
 

	
 
// 	UserInfo userInfo = user->getUserInfo();
 
	user->onReadyToConnect.connect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user));
 
	user->onRoomJoined.connect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3));
 
	user->onRoomLeft.connect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1));
 
}
 

	
 
void NetworkPluginServer::handleUserReadyToConnect(User *user) {
 
	UserInfo userInfo = user->getUserInfo();
 

	
 
	pbnetwork::Login login;
 
	login.set_user(user->getJID().toBare());
 
	login.set_legacyname(userInfo.uin);
 
	login.set_password(userInfo.password);
 

	
 
	std::string message;
 
	login.SerializeToString(&message);
 

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_LOGIN);
 

	
 
	send(user->connection, message);
 
	Client *c = (Client *) user->getData();
 
	send(c->connection, message);
 
}
 

	
 
void NetworkPluginServer::handleRoomJoined(User *user, const std::string &r, const std::string &nickname, const std::string &password) {
 
	UserInfo userInfo = user->getUserInfo();
 

	
 
	pbnetwork::Room room;
 
	room.set_username(user->getJID().toBare());
 
	room.set_nickname(nickname);
 
	room.set_room(r);
 
	room.set_password(password);
 

	
 
	std::string message;
 
	room.SerializeToString(&message);
 

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_JOIN_ROOM);
 
 
 
	send(user->connection, message);
 
	Client *c = (Client *) user->getData();
 
	send(c->connection, message);
 

	
 
	NetworkConversation *conv = new NetworkConversation(user->getConversationManager(), r, true);
 
	conv->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, this, _1, _2));
 
	conv->setNickname(nickname);
 
}
 

	
 
void NetworkPluginServer::handleRoomLeft(User *user, const std::string &r) {
 
	UserInfo userInfo = user->getUserInfo();
 

	
 
	pbnetwork::Room room;
 
	room.set_username(user->getJID().toBare());
 
	room.set_nickname("");
 
	room.set_room(r);
 
	room.set_password("");
 

	
 
	std::string message;
 
	room.SerializeToString(&message);
 

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_LEAVE_ROOM);
 
 
 
	send(user->connection, message);
 
	Client *c = (Client *) user->getData();
 
	send(c->connection, message);
 

	
 
	NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(r);
 
	if (!conv) {
 
		return;
 
	}
 

	
 
	delete conv;
 
}
 

	
 
void NetworkPluginServer::handleUserDestroyed(User *user) {
 
	UserInfo userInfo = user->getUserInfo();
 

	
 
	pbnetwork::Logout logout;
 
	logout.set_user(user->getJID().toBare());
 
	logout.set_legacyname(userInfo.uin);
 

	
 
	std::string message;
 
	logout.SerializeToString(&message);
 

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_LOGOUT);
 
 
 
	send(user->connection, message);
 

	
 
	m_clients[user->connection].users.remove(user);
 
	if (m_clients[user->connection].users.size() == 0) {
 
	Client *c = (Client *) user->getData();
 
	if (!c) {
 
		return;
 
	}
 
	send(c->connection, message);
 
	c->users.remove(user);
 
	if (c->users.size() == 0) {
 
		std::cout << "DISCONNECTING\n";
 
		user->connection->disconnect();
 
		user->connection.reset();
 
		m_clients.erase(user->connection);
 
		c->connection->disconnect();
 
		c->connection.reset();
 
// 		m_clients.erase(user->connection);
 
	}
 
}
 

	
 
void NetworkPluginServer::handleMessageReceived(NetworkConversation *conv, boost::shared_ptr<Swift::Message> &msg) {
 
	pbnetwork::ConversationMessage m;
 
	m.set_username(conv->getConversationManager()->getUser()->getJID().toBare());
 
	m.set_buddyname(conv->getLegacyName());
 
	m.set_message(msg->getBody());
 

	
 
	std::string message;
 
	m.SerializeToString(&message);
 

	
 
	WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_CONV_MESSAGE);
 

	
 
	send(conv->getConversationManager()->getUser()->connection, message);
 
	Client *c = (Client *) conv->getConversationManager()->getUser()->getData();
 
	send(c->connection, message);
 
}
 

	
 
void NetworkPluginServer::sendPing(boost::shared_ptr<Swift::Connection> c) {
 
void NetworkPluginServer::sendPing(Client *c) {
 

	
 
	std::string message;
 
	pbnetwork::WrapperMessage wrap;
 
	wrap.set_type(pbnetwork::WrapperMessage_Type_TYPE_PING);
 
	wrap.SerializeToString(&message);
 

	
 
	send(c, message);
 
	m_clients[c].pongReceived = false;
 
	send(c->connection, message);
 
	c->pongReceived = false;
 
	std::cout << "SENDING PING\n";
 
}
 

	
 
boost::shared_ptr<Swift::Connection> NetworkPluginServer::getFreeClient() {
 
	for (std::map<boost::shared_ptr<Swift::Connection>, Client>::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) {
 
		if ((*it).second.users.size() < 1) {
 
			if ((*it).second.users.size() + 1 == 1) {
 
NetworkPluginServer::Client *NetworkPluginServer::getFreeClient() {
 
	for (std::list<Client *>::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) {
 
		if ((*it)->users.size() < 1) {
 
			if ((*it)->users.size() + 1 == 1) {
 
				exec_(CONFIG_STRING(m_config, "service.backend").c_str(), "localhost", "10000", m_config->getConfigFile().c_str());
 
			}
 
			return (*it).first;
 
			return (*it);
 
		}
 
	}
 
	return boost::shared_ptr<Swift::Connection>(); 
 
	return NULL;
 
}
 

	
 
}
0 comments (0 inline, 0 general)