summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp4
-rw-r--r--Swiften/Disco/DummyEntityCapsProvider.cpp6
-rw-r--r--Swiften/Disco/DummyEntityCapsProvider.h4
-rw-r--r--Swiften/Disco/EntityCapsManager.cpp18
-rw-r--r--Swiften/Disco/EntityCapsManager.h6
-rw-r--r--Swiften/Disco/EntityCapsProvider.h4
-rw-r--r--Swiften/Disco/FeatureOracle.cpp6
7 files changed, 38 insertions, 10 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index add7848..8f43b08 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -1,32 +1,32 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/Controllers/Chat/MUCController.h>
#include <algorithm>
#include <memory>
#include <boost/bind.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <Swiften/Avatars/AvatarManager.h>
#include <Swiften/Base/Log.h>
#include <Swiften/Base/format.h>
#include <Swiften/Base/Tristate.h>
#include <Swiften/Client/BlockList.h>
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swiften/Elements/Delay.h>
#include <Swiften/Elements/Thread.h>
#include <Swiften/MUC/MUC.h>
#include <Swiften/MUC/MUCBookmark.h>
#include <Swiften/MUC/MUCBookmarkManager.h>
#include <Swiften/Network/Timer.h>
#include <Swiften/Network/TimerFactory.h>
#include <Swiften/Roster/XMPPRoster.h>
@@ -212,61 +212,61 @@ void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item
if (muc_->getOccupant(item->getJID().getResource()).getRealJID()) {
actions.push_back(ChatWindow::AddContact);
}
actions.push_back(ChatWindow::ShowProfile);
}
chatWindow_->setAvailableOccupantActions(actions);
}
void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction action, ContactRosterItem* item) {
JID mucJID = item->getJID();
MUCOccupant occupant = muc_->getOccupant(mucJID.getResource());
JID realJID;
if (occupant.getRealJID()) {
realJID = occupant.getRealJID().get();
}
switch (action) {
case ChatWindow::Kick: muc_->kickOccupant(mucJID);break;
case ChatWindow::Ban: muc_->changeAffiliation(realJID, MUCOccupant::Outcast);break;
case ChatWindow::MakeModerator: muc_->changeOccupantRole(mucJID, MUCOccupant::Moderator);break;
case ChatWindow::MakeParticipant: muc_->changeOccupantRole(mucJID, MUCOccupant::Participant);break;
case ChatWindow::MakeVisitor: muc_->changeOccupantRole(mucJID, MUCOccupant::Visitor);break;
case ChatWindow::AddContact: if (occupant.getRealJID()) eventStream_->send(std::make_shared<RequestAddUserDialogUIEvent>(realJID, occupant.getNick()));break;
case ChatWindow::ShowProfile: eventStream_->send(std::make_shared<ShowProfileForRosterItemUIEvent>(mucJID));break;
}
}
void MUCController::handleBareJIDCapsChanged(const JID& /*jid*/) {
Tristate support = Yes;
bool any = false;
for (const auto& nick : currentOccupants_) {
- DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_.toBare().toString() + "/" + nick);
+ DiscoInfo::ref disco = entityCapsProvider_->getCapsCached(toJID_.toBare().toString() + "/" + nick);
if (disco && disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) {
any = true;
} else {
support = Maybe;
}
}
if (!any) {
support = No;
}
chatWindow_->setCorrectionEnabled(support);
}
/**
* Join the MUC if not already in it.
*/
void MUCController::rejoin() {
if (parting_) {
joined_ = false;
parting_ = false;
if (password_) {
muc_->setPassword(*password_);
}
//FIXME: check for received activity
#ifdef SWIFT_EXPERIMENTAL_HISTORY
if (lastActivity_ == boost::posix_time::not_a_date_time && historyController_) {
lastActivity_ = historyController_->getLastTimeStampFromMUC(selfJID_, toJID_);
}
#endif
if (lastActivity_ == boost::posix_time::not_a_date_time) {
muc_->joinAs(nick_);
diff --git a/Swiften/Disco/DummyEntityCapsProvider.cpp b/Swiften/Disco/DummyEntityCapsProvider.cpp
index fce38fe..eba58ac 100644
--- a/Swiften/Disco/DummyEntityCapsProvider.cpp
+++ b/Swiften/Disco/DummyEntityCapsProvider.cpp
@@ -1,19 +1,23 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/Disco/DummyEntityCapsProvider.h>
namespace Swift {
DiscoInfo::ref DummyEntityCapsProvider::getCaps(const JID& jid) const {
std::map<JID, DiscoInfo::ref>::const_iterator i = caps.find(jid);
if (i != caps.end()) {
return i->second;
}
return DiscoInfo::ref();
}
+DiscoInfo::ref DummyEntityCapsProvider::getCapsCached(const JID& jid) {
+ return getCaps(jid);
+}
+
}
diff --git a/Swiften/Disco/DummyEntityCapsProvider.h b/Swiften/Disco/DummyEntityCapsProvider.h
index 5171c91..971e183 100644
--- a/Swiften/Disco/DummyEntityCapsProvider.h
+++ b/Swiften/Disco/DummyEntityCapsProvider.h
@@ -1,24 +1,26 @@
/*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <map>
#include <Swiften/Base/API.h>
#include <Swiften/Disco/EntityCapsProvider.h>
namespace Swift {
class SWIFTEN_API DummyEntityCapsProvider : public EntityCapsProvider {
public:
DummyEntityCapsProvider() {
}
DiscoInfo::ref getCaps(const JID& jid) const;
+ DiscoInfo::ref getCapsCached(const JID& jid);
+
std::map<JID, DiscoInfo::ref> caps;
};
}
diff --git a/Swiften/Disco/EntityCapsManager.cpp b/Swiften/Disco/EntityCapsManager.cpp
index 64d90be..28c525f 100644
--- a/Swiften/Disco/EntityCapsManager.cpp
+++ b/Swiften/Disco/EntityCapsManager.cpp
@@ -1,32 +1,32 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/Disco/EntityCapsManager.h>
#include <boost/bind.hpp>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Disco/CapsProvider.h>
namespace Swift {
EntityCapsManager::EntityCapsManager(CapsProvider* capsProvider, StanzaChannel* stanzaChannel) : capsProvider(capsProvider) {
stanzaChannel->onPresenceReceived.connect(boost::bind(&EntityCapsManager::handlePresenceReceived, this, _1));
stanzaChannel->onAvailableChanged.connect(boost::bind(&EntityCapsManager::handleStanzaChannelAvailableChanged, this, _1));
capsProvider->onCapsAvailable.connect(boost::bind(&EntityCapsManager::handleCapsAvailable, this, _1));
}
void EntityCapsManager::handlePresenceReceived(std::shared_ptr<Presence> presence) {
JID from = presence->getFrom();
if (presence->isAvailable()) {
std::shared_ptr<CapsInfo> capsInfo = presence->getPayload<CapsInfo>();
if (!capsInfo || capsInfo->getHash() != "sha-1" || presence->getPayload<ErrorPayload>()) {
return;
}
std::string hash = capsInfo->getVersion();
std::map<JID, std::string>::iterator i = caps.find(from);
if (i == caps.end() || i->second != hash) {
caps.insert(std::make_pair(from, hash));
@@ -49,31 +49,47 @@ void EntityCapsManager::handlePresenceReceived(std::shared_ptr<Presence> presenc
}
}
void EntityCapsManager::handleStanzaChannelAvailableChanged(bool available) {
if (available) {
std::map<JID, std::string> capsCopy;
capsCopy.swap(caps);
for (std::map<JID,std::string>::const_iterator i = capsCopy.begin(); i != capsCopy.end(); ++i) {
onCapsChanged(i->first);
}
}
}
void EntityCapsManager::handleCapsAvailable(const std::string& hash) {
// TODO: Use Boost.Bimap ?
for (std::map<JID,std::string>::const_iterator i = caps.begin(); i != caps.end(); ++i) {
if (i->second == hash) {
onCapsChanged(i->first);
}
}
}
DiscoInfo::ref EntityCapsManager::getCaps(const JID& jid) const {
std::map<JID, std::string>::const_iterator i = caps.find(jid);
if (i != caps.end()) {
return capsProvider->getCaps(i->second);
}
return DiscoInfo::ref();
}
+DiscoInfo::ref EntityCapsManager::getCapsCached(const JID& jid) {
+ DiscoInfo::ref result;
+ auto capsHit = caps.find(jid);
+ if (capsHit != caps.end()) {
+ result = lruDiscoCache.get(capsHit->second, [&](const std::string& capsHash) {
+ boost::optional<DiscoInfo::ref> fileCacheResult;
+ auto fileCacheDiscoInfo = capsProvider->getCaps(capsHash);
+ if (fileCacheDiscoInfo) {
+ fileCacheResult = fileCacheDiscoInfo;
+ }
+ return fileCacheResult;
+ }).get_value_or(DiscoInfo::ref());
+ }
+ return result;
+}
+
}
diff --git a/Swiften/Disco/EntityCapsManager.h b/Swiften/Disco/EntityCapsManager.h
index 4236326..3934fc7 100644
--- a/Swiften/Disco/EntityCapsManager.h
+++ b/Swiften/Disco/EntityCapsManager.h
@@ -1,47 +1,51 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <map>
#include <boost/signals2.hpp>
#include <Swiften/Base/API.h>
+#include <Swiften/Base/LRUCache.h>
#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/ErrorPayload.h>
#include <Swiften/Elements/Presence.h>
namespace Swift {
class StanzaChannel;
class CapsProvider;
/**
* This class is responsible for gathering and providing
* information about capabilities of entities on the network.
* This information is provided in the form of service discovery
* information.
*/
class SWIFTEN_API EntityCapsManager : public EntityCapsProvider, public boost::signals2::trackable {
public:
EntityCapsManager(CapsProvider*, StanzaChannel*);
/**
* Returns the service discovery information of the given JID.
*/
DiscoInfo::ref getCaps(const JID&) const;
+ DiscoInfo::ref getCapsCached(const JID&);
+
private:
void handlePresenceReceived(std::shared_ptr<Presence>);
void handleStanzaChannelAvailableChanged(bool);
void handleCapsAvailable(const std::string&);
private:
CapsProvider* capsProvider;
std::map<JID, std::string> caps;
+ LRUCache<std::string, DiscoInfo::ref, 64> lruDiscoCache;
};
}
diff --git a/Swiften/Disco/EntityCapsProvider.h b/Swiften/Disco/EntityCapsProvider.h
index 5f4af18..e50a745 100644
--- a/Swiften/Disco/EntityCapsProvider.h
+++ b/Swiften/Disco/EntityCapsProvider.h
@@ -1,35 +1,37 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <boost/signals2.hpp>
#include <Swiften/Base/API.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/JID/JID.h>
namespace Swift {
/**
* This class provides information about capabilities of entities on the network.
* This information is provided in the form of service discovery
* information.
*/
class SWIFTEN_API EntityCapsProvider {
public:
virtual ~EntityCapsProvider();
/**
* Returns the service discovery information of the given JID.
*/
virtual DiscoInfo::ref getCaps(const JID&) const = 0;
+ virtual DiscoInfo::ref getCapsCached(const JID&) = 0;
+
/**
* Emitted when the capabilities of a JID changes.
*/
boost::signals2::signal<void (const JID&)> onCapsChanged;
};
}
diff --git a/Swiften/Disco/FeatureOracle.cpp b/Swiften/Disco/FeatureOracle.cpp
index 2baf87c..63f7a4e 100644
--- a/Swiften/Disco/FeatureOracle.cpp
+++ b/Swiften/Disco/FeatureOracle.cpp
@@ -1,32 +1,32 @@
/*
- * Copyright (c) 2015-2016 Isode Limited.
+ * Copyright (c) 2015-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/Disco/FeatureOracle.h>
#include <algorithm>
#include <iterator>
#include <unordered_set>
#include <vector>
#include <Swiften/Base/Log.h>
#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swiften/Elements/Idle.h>
#include <Swiften/Elements/Presence.h>
#include <Swiften/FileTransfer/FileTransferManager.h>
#include <Swiften/JID/JID.h>
#include <Swiften/Presence/PresenceOracle.h>
namespace Swift {
FeatureOracle::FeatureOracle(EntityCapsProvider* capsProvider, PresenceOracle* presenceOracle) : capsProvider_(capsProvider), presenceOracle_(presenceOracle) {
}
Tristate FeatureOracle::isFileTransferSupported(const JID& jid) {
Tristate fileTransferSupported = No;
auto isYesOrMaybe = [](Tristate tristate) { return tristate == Yes || tristate == Maybe; };
auto isYes = [](Tristate tristate) { return tristate == Yes; };
@@ -127,75 +127,75 @@ class PresenceFeatureAvailablityComparator {
JID FeatureOracle::getMostAvailableClientForFileTrasfer(const JID& bareJID) {
JID fullJID;
assert(bareJID.isBare());
std::vector<Presence::ref> allPresences = presenceOracle_->getAllPresence(bareJID);
std::sort(allPresences.begin(), allPresences.end(), PresenceFeatureAvailablityComparator());
for (const auto& presence : allPresences) {
if (presence->isAvailable()) {
if (isFileTransferSupported(presence->getFrom()) == Yes) {
fullJID = presence->getFrom();
break;
}
}
}
SWIFT_LOG_ASSERT(!fullJID.isBare(), error);
return fullJID;
}
std::unordered_map<std::string, Tristate> FeatureOracle::getFeaturesForJID(const JID& jid) {
std::unordered_map<std::string, Tristate> supportedFeatures;
if (jid.isBare()) {
// Calculate the union of disco features of all most available results and return that.
std::vector<DiscoInfo::ref> onlineDiscoInfos;
std::unordered_set<std::string> features;
// Collect relevant disco info results and the set of features.
for (auto&& presence : presenceOracle_->getAllPresence(jid)) {
if (presence->getType() == Presence::Available) {
- DiscoInfo::ref presenceDiscoInfo = capsProvider_->getCaps(presence->getFrom());
+ DiscoInfo::ref presenceDiscoInfo = capsProvider_->getCapsCached(presence->getFrom());
if (presenceDiscoInfo) {
onlineDiscoInfos.push_back(presenceDiscoInfo);
features.insert(presenceDiscoInfo->getFeatures().begin(), presenceDiscoInfo->getFeatures().end());
}
}
}
// Calculate supportedFeaturesMap.
for (auto&& feature : features) {
Tristate supported = Yes;
for (auto&& discoInfo : onlineDiscoInfos) {
if (!discoInfo->hasFeature(feature)) {
supported = Maybe;
break;
}
}
supportedFeatures[feature] = supported;
}
}
else {
// Return the disco result of the full JID.
- auto discoInfo = capsProvider_->getCaps(jid);
+ auto discoInfo = capsProvider_->getCapsCached(jid);
if (discoInfo) {
for (auto&& feature : discoInfo->getFeatures()) {
supportedFeatures[feature] = Yes;
}
}
}
return supportedFeatures;
}
Tristate FeatureOracle::isFeatureSupported(const std::unordered_map<std::string, Tristate>& supportedFeatures, const std::string& feature) {
Tristate supported = No;
auto lookupResult = supportedFeatures.find(feature);
if (lookupResult != supportedFeatures.end()) {
supported = lookupResult->second;
}
return supported;
}
}