Changeset - 004f9410384a
[Not reviewed]
0 9 0
Jan Kaluza - 10 years ago 2015-12-21 13:41:30
jkaluza@redhat.com
Slack: Handle disconnection from 3rd-party network
9 files changed with 39 insertions and 3 deletions:
0 comments (0 inline, 0 general)
include/transport/User.h
Show inline comments
 
@@ -113,58 +113,63 @@ class User {
 
		void setIgnoreDisconnect(bool ignoreDisconnect);
 

	
 
		bool isConnected() {
 
			return m_connected;
 
		}
 

	
 
		int getResourceCount() {
 
			return m_resources;
 
		}
 

	
 
		void addUserSetting(const std::string &key, const std::string &value) {
 
			m_settings[key] = value;
 
		}
 

	
 
		const std::string &getUserSetting(const std::string &key) {
 
			return m_settings[key];
 
		}
 

	
 
		void setCacheMessages(bool cacheMessages);
 

	
 
		bool shouldCacheMessages() {
 
			return m_cacheMessages;
 
		}
 

	
 
		void setReconnectLimit(int limit) {
 
			m_reconnectLimit = limit;
 
		}
 

	
 
		boost::signal<void ()> onReadyToConnect;
 
		boost::signal<void (Swift::Presence::ref presence)> onPresenceChanged;
 
		boost::signal<void (Swift::Presence::ref presence)> onRawPresenceReceived;
 
		boost::signal<void (const Swift::JID &who, 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;
 
		PresenceOracle *m_presenceOracle;
 
		UserInfo m_userInfo;
 
		void *m_data;
 
		bool m_connected;
 
		bool m_readyForConnect;
 
		bool m_ignoreDisconnect;
 
		Swift::Timer::ref m_reconnectTimer;
 
		boost::shared_ptr<Swift::Connection> connection;
 
		time_t m_lastActivity;
 
		std::map<Swift::JID, Swift::DiscoInfo::ref> m_legacyCaps;
 
		std::vector<boost::shared_ptr<Swift::OutgoingFileTransfer> > m_filetransfers;
 
		int m_resources;
 
		int m_reconnectCounter;
 
		std::list<Swift::Presence::ref> m_joinedRooms;
 
		std::map<std::string, std::string> m_settings;
 
		bool m_cacheMessages;
 
		int m_reconnectLimit;
 
};
 

	
 
}
spectrum/src/frontends/slack/SlackFrontend.cpp
Show inline comments
 
@@ -77,49 +77,51 @@ void SlackFrontend::sendVCard(Swift::VCard::ref vcard, Swift::JID to) {
 
void SlackFrontend::sendRosterRequest(Swift::RosterPayload::ref payload, Swift::JID to) {
 
}
 

	
 
void SlackFrontend::sendMessage(boost::shared_ptr<Swift::Message> message) {
 
	return static_cast<SlackUserManager *>(m_userManager)->sendMessage(message);
 
}
 

	
 
void SlackFrontend::sendIQ(boost::shared_ptr<Swift::IQ> iq) {
 
}
 

	
 
boost::shared_ptr<Swift::DiscoInfo> SlackFrontend::sendCapabilitiesRequest(Swift::JID to) {
 

	
 
	return Swift::DiscoInfo::ref();
 
}
 

	
 
void SlackFrontend::reconnectUser(const std::string &user) {
 
	return static_cast<SlackUserManager *>(m_userManager)->reconnectUser(user);
 
}
 

	
 
RosterManager *SlackFrontend::createRosterManager(User *user, Component *component) {
 
	return new SlackRosterManager(user, component);
 
}
 

	
 
User *SlackFrontend::createUser(const Swift::JID &jid, UserInfo &userInfo, Component *component, UserManager *userManager) {
 
	return new SlackUser(jid, userInfo, component, userManager);
 
	SlackUser *user = new SlackUser(jid, userInfo, component, userManager);
 
	user->setReconnectLimit(-1);
 
	return user;
 
}
 

	
 
UserManager *SlackFrontend::createUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) {
 
	m_userManager = new SlackUserManager(component, userRegistry, storageBackend);
 
	return m_userManager;
 
}
 

	
 

	
 
void SlackFrontend::connectToServer() {
 
	LOG4CXX_INFO(logger, "Started.");
 
	m_transport->handleConnected();
 
}
 

	
 
std::string SlackFrontend::setOAuth2Code(const std::string &code, const std::string &state) {
 
	return static_cast<SlackUserManager *>(m_userManager)->handleOAuth2Code(code, state);
 
}
 

	
 
std::string SlackFrontend::getOAuth2URL(const std::vector<std::string> &args) {
 
	return static_cast<SlackUserManager *>(m_userManager)->getOAuth2URL(args);
 
}
 

	
 
void SlackFrontend::disconnectFromServer() {
 

	
 
}
spectrum/src/frontends/slack/SlackFrontendPlugin.cpp
Show inline comments
 
@@ -13,40 +13,40 @@
 
 * 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
 
 */
 

	
 
#include "SlackFrontendPlugin.h"
 
#include "SlackFrontend.h"
 

	
 
#include <boost/dll/alias.hpp>
 

	
 
namespace Transport {
 

	
 
SlackFrontendPlugin::SlackFrontendPlugin() { 
 

	
 
}
 

	
 
SlackFrontendPlugin::~SlackFrontendPlugin() {
 
	
 
}
 

	
 
std::string SlackFrontendPlugin::name() const {
 
	return "xmpp";
 
	return "slack";
 
}
 

	
 
Frontend *SlackFrontendPlugin::createFrontend() {
 
	return new SlackFrontend();
 
}
 

	
 
// SlackFrontendPlugin plugin;
 

	
 
boost::shared_ptr<FrontendPlugin> get_slack_frontend_plugin() {
 
	return boost::make_shared<SlackFrontendPlugin>();
 
}
 

	
 
// BOOST_DLL_AUTO_ALIAS(plugin)
 

	
 
}
spectrum/src/frontends/slack/SlackSession.cpp
Show inline comments
 
@@ -70,48 +70,58 @@ void SlackSession::sendOnlineBuddies() {
 
	std::map<std::string, Conversation *> convs = m_user->getConversationManager()->getConversations();
 
	for (std::map<std::string, Conversation *> ::const_iterator it = convs.begin(); it != convs.end(); it++) {
 
		Conversation *conv = it->second;
 
		if (!conv) {
 
			continue;
 
		}
 

	
 
		std::string onlineBuddies = "Online users: " + conv->getParticipants();
 

	
 
		if (m_onlineBuddies[it->first] != onlineBuddies) {
 
			m_onlineBuddies[it->first] = onlineBuddies;
 
			std::string legacyName = it->first;
 
			if (legacyName.find_last_of("@") != std::string::npos) {
 
				legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK
 
			}
 

	
 

	
 
			std::string to = legacyName + "@" + m_component->getJID().toBare().toString();
 
			setPurpose(onlineBuddies, m_jid2channel[to]);
 
		}
 
	}
 
	m_onlineBuddiesTimer->start();
 
}
 

	
 
void SlackSession::sendMessageToAll(const std::string &msg) {
 
	std::vector<std::string> channels;
 
	for (std::map<std::string, std::string>::const_iterator it = m_jid2channel.begin(); it != m_jid2channel.end(); it++) {
 
		if (std::find(channels.begin(), channels.end(), it->second) == channels.end()) {
 
			channels.push_back(it->second);
 
			m_rtm->getAPI()->sendMessage("Soectrum 2", it->second, msg);
 
		}
 
	}
 
}
 

	
 
void SlackSession::sendMessage(boost::shared_ptr<Swift::Message> message) {
 
	if (m_user) {
 
		std::map<std::string, Conversation *> convs = m_user->getConversationManager()->getConversations();
 
		for (std::map<std::string, Conversation *> ::const_iterator it = convs.begin(); it != convs.end(); it++) {
 
			Conversation *conv = it->second;
 
			if (!conv) {
 
				continue;
 
			}
 

	
 
			if (conv->getNickname() == message->getFrom().getResource()) {
 
				return;
 
			}
 
		}
 
	}
 

	
 
	std::string from = message->getFrom().getResource();
 
	std::string channel = m_jid2channel[message->getFrom().toBare().toString()];
 
	LOG4CXX_INFO(logger, "JID is " << message->getFrom().toBare().toString());
 
	if (channel.empty()) {
 
		if (m_slackChannel.empty()) {
 
			LOG4CXX_ERROR(logger, m_uinfo.jid << ": Received message for unknown channel from " << message->getFrom().toBare().toString());
 
			return;
 
		}
 
		channel = m_slackChannel;
spectrum/src/frontends/slack/SlackSession.h
Show inline comments
 
@@ -30,48 +30,50 @@
 
#include "Swiften/Elements/Message.h"
 
#include "Swiften/Network/Timer.h"
 

	
 
#include <boost/signal.hpp>
 

	
 
namespace Transport {
 

	
 
class Component;
 
class StorageBackend;
 
class HTTPRequest;
 
class SlackRTM;
 
class SlackAPI;
 
class User;
 

	
 
class SlackSession {
 
	public:
 
		SlackSession(Component *component, StorageBackend *storageBackend, UserInfo uinfo);
 

	
 
		virtual ~SlackSession();
 

	
 
		boost::signal<void (const std::string &user)> onInstallationDone;
 

	
 
		void sendMessage(boost::shared_ptr<Swift::Message> message);
 

	
 
		void sendMessageToAll(const std::string &msg);
 

	
 
		void setPurpose(const std::string &purpose, const std::string &channel = "");
 

	
 
		void setUser(User *user) {
 
			m_user = user;
 
		}
 

	
 
	private:
 
		void handleRTMStarted();
 
		void handleMessageReceived(const std::string &channel, const std::string &user, const std::string &message, const std::string &ts, bool quiet);
 
		void handleImOpen(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
 

	
 
		void handleJoinMessage(const std::string &message, std::vector<std::string> &args, bool quiet = false);
 
		void handleLeaveMessage(const std::string &message, std::vector<std::string> &args, bool quiet = false);
 
		void handleRegisterMessage(const std::string &message, std::vector<std::string> &args, bool quiet = false);
 

	
 
		void sendOnlineBuddies();
 

	
 
	private:
 
		Component *m_component;
 
		StorageBackend *m_storageBackend;
 
		UserInfo m_uinfo;
 
		std::string m_ownerName;
 
		SlackRTM *m_rtm;
 
		std::string m_ownerChannel;
spectrum/src/frontends/slack/SlackUser.cpp
Show inline comments
 
@@ -34,29 +34,41 @@
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "SlackUser");
 

	
 
SlackUser::SlackUser(const Swift::JID &jid, UserInfo &userInfo, Component *component, UserManager *userManager) : User(jid, userInfo, component, userManager) {
 
	m_jid = jid.toBare();
 

	
 
	m_component = component;
 
	m_userManager = userManager;
 
	m_userInfo = userInfo;
 

	
 
	m_session = static_cast<SlackUserManager *>(userManager)->moveTempSession(m_jid.toString());
 
	m_session->setUser(this);
 
}
 

	
 
SlackUser::~SlackUser(){
 
	if (m_session) {
 
		delete m_session;
 
	}
 
}
 

	
 
void SlackUser::disconnectUser(const std::string &error, Swift::SpectrumErrorPayload::Error e) {
 
	if (!m_session) {
 
		return;
 
	}
 

	
 
	if (!error.empty()) {
 
		m_session->sendMessageToAll(error);
 
	}
 
	else {
 
		m_session->sendMessageToAll("Disconnected from 3rd-party network for unknown reason.");
 
	}
 
	m_session->sendMessageToAll("Try using ```.spectrum2 reconnect``` to reconnect.");
 
	static_cast<SlackUserManager *>(m_userManager)->moveTempSession(m_jid.toString(), m_session);
 
	m_session = NULL;
 
}
 

	
 

	
 
}
spectrum/src/frontends/slack/SlackUserManager.cpp
Show inline comments
 
@@ -56,39 +56,43 @@ void SlackUserManager::reconnectUser(const std::string &user) {
 

	
 
void SlackUserManager::sendVCard(unsigned int id, Swift::VCard::ref vcard) {
 

	
 
}
 

	
 
void SlackUserManager::sendMessage(boost::shared_ptr<Swift::Message> message) {
 
	User *user = getUser(message->getTo().toBare().toString());
 
	if (!user) {
 
		LOG4CXX_ERROR(logger, "Received message for unknown user " << message->getTo().toBare().toString());
 
		return;
 
	}
 

	
 
	static_cast<SlackUser *>(user)->getSession()->sendMessage(message);
 
}
 

	
 
SlackSession *SlackUserManager::moveTempSession(const std::string &user) {
 
	if (m_tempSessions.find(user) != m_tempSessions.end()) {
 
		SlackSession *session = m_tempSessions[user];
 
		m_tempSessions.erase(user);
 
		return session;
 
	}
 
	return NULL;
 
}
 

	
 
void SlackUserManager::moveTempSession(const std::string &user, SlackSession *session) {
 
	m_tempSessions[user] = session;
 
}
 

	
 

	
 
UserRegistration *SlackUserManager::getUserRegistration() {
 
	return m_userRegistration;
 
}
 

	
 
std::string SlackUserManager::handleOAuth2Code(const std::string &code, const std::string &state) {
 
	return static_cast<SlackUserRegistration *>(m_userRegistration)->handleOAuth2Code(code, state);
 
}
 

	
 
std::string SlackUserManager::getOAuth2URL(const std::vector<std::string> &args) {
 
	return static_cast<SlackUserRegistration *>(m_userRegistration)->createOAuth2URL(args);
 
}
 

	
 

	
 
}
spectrum/src/frontends/slack/SlackUserManager.h
Show inline comments
 
@@ -39,33 +39,34 @@ class XMPPUserRegistration;
 
class GatewayResponder;
 
class AdHocManager;
 
class SettingsAdHocCommandFactory;
 
class SlackSession;
 

	
 
class SlackUserManager : public UserManager {
 
	public:
 
		SlackUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend = NULL);
 

	
 
		virtual ~SlackUserManager();
 

	
 
		void reconnectUser(const std::string &user);
 

	
 
		virtual void sendVCard(unsigned int id, Swift::VCard::ref vcard);
 

	
 
		UserRegistration *getUserRegistration();
 

	
 
		std::string handleOAuth2Code(const std::string &code, const std::string &state);
 

	
 
		std::string getOAuth2URL(const std::vector<std::string> &args);
 

	
 
		void sendMessage(boost::shared_ptr<Swift::Message> message);
 

	
 
		SlackSession *moveTempSession(const std::string &user);
 
		void moveTempSession(const std::string &user, SlackSession *session);
 

	
 
	private:
 
		Component *m_component;
 
		UserRegistration *m_userRegistration;
 
		StorageBackend *m_storageBackend;
 
		std::map<std::string, SlackSession *> m_tempSessions;
 
};
 

	
 
}
src/User.cpp
Show inline comments
 
@@ -376,49 +376,49 @@ void User::onConnectingTimeout() {
 
		return;
 
	m_reconnectTimer->stop();
 
	m_readyForConnect = true;
 
	onReadyToConnect();
 

	
 
	Swift::Presence::ref highest = m_presenceOracle->getHighestPriorityPresence(m_jid.toBare());
 
	if (highest) {
 
		LOG4CXX_INFO(logger, m_jid.toString() << ": Changing legacy network presence to " << highest->getType());
 
		onPresenceChanged(highest);
 
	}
 
}
 

	
 
void User::setIgnoreDisconnect(bool ignoreDisconnect) {
 
	m_ignoreDisconnect = ignoreDisconnect;
 
	LOG4CXX_INFO(logger, m_jid.toString() << ": Setting ignoreDisconnect=" << m_ignoreDisconnect);
 
}
 

	
 
void User::handleDisconnected(const std::string &error, Swift::SpectrumErrorPayload::Error e) {
 
	if (m_ignoreDisconnect) {
 
		LOG4CXX_INFO(logger, m_jid.toString() << ": Disconnecting from legacy network ignored (probably moving between backends)");
 
		return;
 
	}
 

	
 
	if (e == Swift::SpectrumErrorPayload::CONNECTION_ERROR_OTHER_ERROR || e == Swift::SpectrumErrorPayload::CONNECTION_ERROR_NETWORK_ERROR) {
 
		if (m_reconnectCounter < 3) {
 
		if (m_reconnectLimit < 0 || m_reconnectCounter < m_reconnectLimit) {
 
			m_reconnectCounter++;
 
			LOG4CXX_INFO(logger, m_jid.toString() << ": Disconnecting from legacy network " << error << ", trying to reconnect automatically.");
 
			// Simulate destruction/resurrection :)
 
			// TODO: If this stops working, create onReconnect signal
 
			m_userManager->onUserDestroyed(this);
 
			m_userManager->onUserCreated(this);
 
			onReadyToConnect();
 
			return;
 
		}
 
	}
 

	
 
	if (error.empty()) {
 
		LOG4CXX_INFO(logger, m_jid.toString() << ": Disconnected from legacy network");
 
	}
 
	else {
 
		LOG4CXX_INFO(logger, m_jid.toString() << ": Disconnected from legacy network with error " << error);
 
	}
 
	onDisconnected();
 

	
 
	boost::shared_ptr<Swift::Message> msg(new Swift::Message());
 
	msg->setBody(error);
 
	msg->setTo(m_jid.toBare());
 
	msg->setFrom(m_component->getJID());
 
	msg->addPayload(boost::make_shared<Swift::SpectrumErrorPayload>(e));
0 comments (0 inline, 0 general)