Another part of AdHoc support

This commit is contained in:
Jan Kaluza 2012-06-25 19:55:57 +02:00
parent cfa85cd21c
commit 851ef18260
8 changed files with 520 additions and 0 deletions

View file

@ -0,0 +1,69 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
*
* 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 <string>
#include <algorithm>
#include <map>
#include "Swiften/Swiften.h"
namespace Transport {
class Component;
class AdHocCommand {
public:
/// Creates new AdHocManager.
/// \param component Transport instance associated with this AdHocManager.
AdHocCommand(Component *component, const Swift::JID &initiator, const Swift::JID &to);
/// Destructor.
virtual ~AdHocCommand();
virtual boost::shared_ptr<Swift::Command> handleRequest(boost::shared_ptr<Swift::Command> payload) = 0;
const std::string &getId() {
return m_id;
}
void refreshLastActivity() {
m_lastActivity = time(NULL);
}
time_t getLastActivity() {
return m_lastActivity;
}
protected:
Component *m_component;
Swift::JID m_initiator;
Swift::JID m_to;
private:
std::string m_id;
// This is used to remove AdHocCommand after long inactivity to prevent memory leaks
// caused by users which disconnect before they finish the command.
// AdHocManager uses this to garbage collect old AdHocCommands.
time_t m_lastActivity;
};
}

View file

@ -0,0 +1,47 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
*
* 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 <string>
#include <algorithm>
#include <map>
#include "transport/adhoccommand.h"
#include "Swiften/Swiften.h"
namespace Transport {
class Component;
class AdHocCommandFactory {
public:
AdHocCommandFactory() {}
/// Destructor.
virtual ~AdHocCommandFactory() {}
virtual AdHocCommand *createAdHocCommand(Component *component, const Swift::JID &initiator, const Swift::JID &to) = 0;
virtual std::string getNode() = 0;
virtual std::string getName() = 0;
};
}

View file

@ -0,0 +1,75 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
*
* 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 <string>
#include <algorithm>
#include <map>
#include "Swiften/Swiften.h"
namespace Transport {
class Conversation;
class User;
class Component;
class DiscoItemsResponder;
class AdHocCommandFactory;
class AdHocCommand;
/// Listens for AdHoc commands and manages all AdHoc commands sessions
class AdHocManager : public Swift::Responder<Swift::Command> {
public:
typedef std::map<std::string, AdHocCommand *> CommandsMap;
typedef std::map<Swift::JID, CommandsMap> SessionsMap;
/// Creates new AdHocManager.
/// \param component Transport instance associated with this AdHocManager.
AdHocManager(Component *component, DiscoItemsResponder *discoItemsResponder);
/// Destructor.
virtual ~AdHocManager();
/// Starts handling AdHoc commands payloads.
void start();
/// Stops handling AdHoc commands payloads and destroys all existing
/// AdHoc commands sessions.
void stop();
/// Adds factory to create new AdHoc commands sessions of particular type.
void addAdHocCommand(AdHocCommandFactory *factory);
/// Remove sessions older than N seconds.
void removeOldSessions();
private:
virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::Command> payload);
virtual bool handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::Command> payload);
Component *m_component;
DiscoItemsResponder *m_discoItemsResponder;
std::map<std::string, AdHocCommandFactory *> m_factories;
SessionsMap m_sessions;
Swift::Timer::ref m_collectTimer;
};
}

View file

@ -0,0 +1,63 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
*
* 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 <string>
#include <algorithm>
#include <map>
#include "Swiften/Swiften.h"
#include "transport/adhoccommand.h"
#include "transport/adhoccommandfactory.h"
namespace Transport {
class Component;
class SettingsAdHocCommand : public AdHocCommand {
public:
SettingsAdHocCommand(Component *component, const Swift::JID &initiator, const Swift::JID &to);
/// Destructor.
virtual ~SettingsAdHocCommand();
virtual boost::shared_ptr<Swift::Command> handleRequest(boost::shared_ptr<Swift::Command> payload);
};
class SettingsAdHocCommandFactory : public AdHocCommandFactory {
public:
SettingsAdHocCommandFactory() {}
virtual ~SettingsAdHocCommandFactory() {}
AdHocCommand *createAdHocCommand(Component *component, const Swift::JID &initiator, const Swift::JID &to) {
return new SettingsAdHocCommand(component, initiator, to);
}
std::string getNode() {
return "settings";
}
std::string getName() {
return "Transport settings";
}
};
}

View file

@ -15,6 +15,8 @@
#include "transport/gatewayresponder.h"
#include "transport/logging.h"
#include "transport/discoitemsresponder.h"
#include "transport/adhocmanager.h"
#include "transport/settingsadhoccommand.h"
#include "Swiften/EventLoop/SimpleEventLoop.h"
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
@ -317,6 +319,12 @@ int main(int argc, char **argv)
DiscoItemsResponder discoItemsResponder(&transport);
discoItemsResponder.start();
AdHocManager adhocmanager(&transport, &discoItemsResponder);
adhocmanager.start();
SettingsAdHocCommandFactory settings;
adhocmanager.addAdHocCommand(&settings);
eventLoop_ = &eventLoop;
eventLoop.run();

48
src/adhoccommand.cpp Normal file
View file

@ -0,0 +1,48 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2012, Jan Kaluza <hanzz@soc.pidgin.im>
*
* 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
*/
#include "transport/adhoccommand.h"
#include "transport/adhoccommandfactory.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/buddy.h"
#include "transport/factory.h"
#include "transport/user.h"
#include "transport/logging.h"
namespace Transport {
DEFINE_LOGGER(logger, "AdHocCommand");
AdHocCommand::AdHocCommand(Component *component, const Swift::JID &initiator, const Swift::JID &to) {
m_component = component;
m_initiator = initiator;
m_to = to;
std::string bucket = "abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < 32; i++) {
m_id += bucket[rand() % bucket.size()];
}
}
AdHocCommand::~AdHocCommand() {
}
}

163
src/adhocmanager.cpp Normal file
View file

@ -0,0 +1,163 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2012, Jan Kaluza <hanzz@soc.pidgin.im>
*
* 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
*/
#include "transport/adhocmanager.h"
#include "transport/adhoccommandfactory.h"
#include "transport/discoitemsresponder.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/buddy.h"
#include "transport/factory.h"
#include "transport/user.h"
#include "transport/logging.h"
namespace Transport {
DEFINE_LOGGER(logger, "AdHocManager");
AdHocManager::AdHocManager(Component *component, DiscoItemsResponder *discoItemsResponder) : Swift::Responder<Swift::Command>(component->getIQRouter()){
m_component = component;
m_discoItemsResponder = discoItemsResponder;
m_collectTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(20);
m_collectTimer->onTick.connect(boost::bind(&AdHocManager::removeOldSessions, this));
m_collectTimer->start();
}
AdHocManager::~AdHocManager() {
m_collectTimer->stop();
stop();
}
void AdHocManager::start() {
Swift::Responder<Swift::Command>::start();
}
void AdHocManager::stop() {
Swift::Responder<Swift::Command>::stop();
for (SessionsMap::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) {
std::vector<std::string> candidates;
for (CommandsMap::iterator ct = it->second.begin(); ct != it->second.end(); ct++) {
delete ct->second;
}
}
m_sessions.clear();
}
void AdHocManager::addAdHocCommand(AdHocCommandFactory *factory) {
if (m_factories.find(factory->getNode()) != m_factories.end()) {
LOG4CXX_ERROR(logger, "Command with node " << factory->getNode() << " is already registered. Ignoring this attempt.");
return;
}
m_factories[factory->getNode()] = factory;
m_discoItemsResponder->addAdHocCommand(factory->getNode(), factory->getName());
}
void AdHocManager::removeOldSessions() {
unsigned long removedCommands = 0;
time_t now = time(NULL);
std::vector<std::string> toRemove;
for (SessionsMap::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) {
std::vector<std::string> candidates;
for (CommandsMap::iterator ct = it->second.begin(); ct != it->second.end(); ct++) {
if (now - ct->second->getLastActivity() > 15*60) {
candidates.push_back(it->first);
delete ct->second;
removedCommands++;
}
}
BOOST_FOREACH(std::string &key, candidates) {
it->second.erase(key);
}
if (it->second.empty()) {
toRemove.push_back(it->first);
}
}
BOOST_FOREACH(std::string &key, toRemove) {
m_sessions.erase(key);
}
if (removedCommands > 0) {
LOG4CXX_INFO(logger, "Removed " << removedCommands << " old commands sessions.");
}
}
bool AdHocManager::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::Command> payload) {
return false;
}
bool AdHocManager::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::Command> payload) {
AdHocCommand *command = NULL;
// Try to find AdHocCommand according to 'from' and session_id
if (m_sessions.find(from) != m_sessions.end() && m_sessions[from].find(payload->getSessionID()) != m_sessions[from].end()) {
command = m_sessions[from][payload->getSessionID()];
}
// Check if we can create command with this node
else if (m_factories.find(payload->getNode()) != m_factories.end()) {
command = m_factories[payload->getNode()]->createAdHocCommand(m_component, from, to);
m_sessions[from][command->getId()] = command;
LOG4CXX_INFO(logger, from.toString() << ": Started new AdHoc command session with node " << payload->getNode());
}
else {
LOG4CXX_INFO(logger, from.toString() << ": Unknown node " << payload->getNode() << ". Can't start AdHoc command session.");
sendError(from, id, Swift::ErrorPayload::BadRequest, Swift::ErrorPayload::Modify);
return true;
}
if (!command) {
LOG4CXX_ERROR(logger, from.toString() << ": createAdHocCommand for node " << payload->getNode() << " returned NULL pointer");
sendError(from, id, Swift::ErrorPayload::BadRequest, Swift::ErrorPayload::Modify);
return true;
}
boost::shared_ptr<Swift::Command> response = command->handleRequest(payload);
if (!response) {
LOG4CXX_ERROR(logger, from.toString() << ": handleRequest for node " << payload->getNode() << " returned NULL pointer");
sendError(from, id, Swift::ErrorPayload::BadRequest, Swift::ErrorPayload::Modify);
return true;
}
response->setSessionID(command->getId());
sendResponse(from, id, response);
command->refreshLastActivity();
// Command completed, so we can remove it now
if (response->getStatus() == Swift::Command::Completed) {
m_sessions[from].erase(command->getId());
if (m_sessions[from].empty()) {
m_sessions.erase(from);
}
delete command;
}
return true;
}
}

View file

@ -0,0 +1,47 @@
/**
* XMPP - libpurple transport
*
* Copyright (C) 2012, Jan Kaluza <hanzz@soc.pidgin.im>
*
* 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
*/
#include "transport/settingsadhoccommand.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/buddy.h"
#include "transport/factory.h"
#include "transport/user.h"
#include "transport/logging.h"
namespace Transport {
DEFINE_LOGGER(logger, "SettingsAdHocCommand");
SettingsAdHocCommand::SettingsAdHocCommand(Component *component, const Swift::JID &initiator, const Swift::JID &to) : AdHocCommand(component, initiator, to) {
}
SettingsAdHocCommand::~SettingsAdHocCommand() {
}
boost::shared_ptr<Swift::Command> SettingsAdHocCommand::handleRequest(boost::shared_ptr<Swift::Command> payload) {
boost::shared_ptr<Swift::Command> response;
return response;
}
}