diff options
Diffstat (limited to 'Sluift/SluiftComponent.cpp')
-rw-r--r-- | Sluift/SluiftComponent.cpp | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/Sluift/SluiftComponent.cpp b/Sluift/SluiftComponent.cpp new file mode 100644 index 0000000..c08a103 --- /dev/null +++ b/Sluift/SluiftComponent.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014 Kevin Smith and Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/SluiftComponent.h> + +#include <boost/numeric/conversion/cast.hpp> + +#include <Swiften/Component/ComponentXMLTracer.h> +#include <Swiften/Component/Component.h> +#include <Swiften/Roster/XMPPRoster.h> +#include <Sluift/SluiftGlobals.h> +#include <Sluift/Lua/Exception.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Queries/RawRequest.h> +#include <Sluift/Helpers.h> +#include <Swiften/Elements/Presence.h> + +using namespace Swift; + +SluiftComponent::SluiftComponent( + const JID& jid, + const std::string& password, + NetworkFactories* networkFactories, + SimpleEventLoop* eventLoop): + networkFactories(networkFactories), + eventLoop(eventLoop), + tracer(NULL) { + component = new Component(jid, password, networkFactories); + component->onError.connect(boost::bind(&SluiftComponent::handleError, this, _1)); + component->onMessageReceived.connect(boost::bind(&SluiftComponent::handleIncomingMessage, this, _1)); + component->onPresenceReceived.connect(boost::bind(&SluiftComponent::handleIncomingPresence, this, _1)); +} + +SluiftComponent::~SluiftComponent() { + delete tracer; + delete component; +} + +void SluiftComponent::connect(const std::string& host, int port) { + disconnectedError = boost::optional<ComponentError>(); + component->connect(host, port); +} + +void SluiftComponent::setTraceEnabled(bool b) { + if (b && !tracer) { + tracer = new ComponentXMLTracer(component); + } + else if (!b && tracer) { + delete tracer; + tracer = NULL; + } +} + +void SluiftComponent::waitConnected(int timeout) { + Watchdog watchdog(timeout, networkFactories->getTimerFactory()); + while (!watchdog.getTimedOut() && !disconnectedError && !component->isAvailable()) { + eventLoop->runUntilEvents(); + } + if (watchdog.getTimedOut()) { + component->disconnect(); + throw Lua::Exception("Timeout while connecting"); + } + if (disconnectedError) { + throw Lua::Exception(getErrorString(*disconnectedError)); + } +} + +bool SluiftComponent::isConnected() const { + return component->isAvailable(); +} + +void SluiftComponent::disconnect() { + component->disconnect(); + while (component->isAvailable()) { + eventLoop->runUntilEvents(); + } +} + +void SluiftComponent::setSoftwareVersion(const std::string& name, const std::string& version, const std::string& os) { + component->setSoftwareVersion(name, version); +} + +boost::optional<SluiftComponent::Event> SluiftComponent::getNextEvent( + int timeout, boost::function<bool (const Event&)> condition) { + Watchdog watchdog(timeout, networkFactories->getTimerFactory()); + size_t currentIndex = 0; + while (true) { + // Look for pending events in the queue + while (currentIndex < pendingEvents.size()) { + Event event = pendingEvents[currentIndex]; + if (!condition || condition(event)) { + pendingEvents.erase( + pendingEvents.begin() + + boost::numeric_cast<int>(currentIndex)); + return event; + } + ++currentIndex; + } + + // Wait for new events + while (!watchdog.getTimedOut() && currentIndex >= pendingEvents.size() && component->isAvailable()) { + eventLoop->runUntilEvents(); + } + + // Finish if we're disconnected or timed out + if (watchdog.getTimedOut() || !component->isAvailable()) { + return boost::optional<Event>(); + } + } +} + +void SluiftComponent::handleIncomingMessage(boost::shared_ptr<Message> stanza) { + pendingEvents.push_back(Event(stanza)); +} + +void SluiftComponent::handleIncomingPresence(boost::shared_ptr<Presence> stanza) { + pendingEvents.push_back(Event(stanza)); +} + +void SluiftComponent::handleRequestResponse(boost::shared_ptr<Payload> response, boost::shared_ptr<ErrorPayload> error) { + requestResponse = response; + requestError = error; + requestResponseReceived = true; +} + +void SluiftComponent::handleError(const boost::optional<ComponentError>& error) { + disconnectedError = error; +} + +Sluift::Response SluiftComponent::doSendRequest(boost::shared_ptr<Request> request, int timeout) { + requestResponse.reset(); + requestError.reset(); + requestResponseReceived = false; + request->send(); + + Watchdog watchdog(timeout, networkFactories->getTimerFactory()); + while (!watchdog.getTimedOut() && !requestResponseReceived) { + eventLoop->runUntilEvents(); + } + return Sluift::Response(requestResponse, watchdog.getTimedOut() ? + boost::make_shared<ErrorPayload>(ErrorPayload::RemoteServerTimeout) : requestError); +} |