linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #05761
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2962: rework user matching synchronization
------------------------------------------------------------
revno: 2962
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Sat 2012-06-23 12:44:48 +0200
message:
rework user matching synchronization
modified:
dcpp/ClientManager.cpp
dcpp/ClientManager.h
dcpp/UserMatchManager.cpp
dcpp/UserMatchManager.h
win32/UserInfoBase.cpp
win32/UserInfoBase.h
win32/WinUtil.cpp
--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk
Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'dcpp/ClientManager.cpp'
--- dcpp/ClientManager.cpp 2012-06-21 18:52:47 +0000
+++ dcpp/ClientManager.cpp 2012-06-23 10:44:48 +0000
@@ -303,6 +303,13 @@
return CID(th.finalize());
}
+void ClientManager::updateUsers() {
+ Lock l(cs);
+ for(auto client: clients) {
+ client->updateUsers();
+ }
+}
+
void ClientManager::putOnline(OnlineUser* ou) noexcept {
{
Lock l(cs);
@@ -359,11 +366,15 @@
return 0;
}
-OnlineUser* ClientManager::findOnlineUser(const HintedUser& user) {
+OnlineUser* ClientManager::findOnlineUser(const HintedUser& user) const {
return findOnlineUser(user.user->getCID(), user.hint);
}
-OnlineUser* ClientManager::findOnlineUser(const CID& cid, const string& hintUrl) {
+OnlineUser* ClientManager::findOnlineUserHint(const HintedUser& user) const {
+ return findOnlineUserHint(user.user->getCID(), user.hint);
+}
+
+OnlineUser* ClientManager::findOnlineUser(const CID& cid, const string& hintUrl) const {
OnlinePairC p;
OnlineUser* u = findOnlineUserHint(cid, hintUrl, p);
if(u) // found an exact match (CID + hint).
=== modified file 'dcpp/ClientManager.h'
--- dcpp/ClientManager.h 2012-05-15 23:26:22 +0000
+++ dcpp/ClientManager.h 2012-06-23 10:44:48 +0000
@@ -92,9 +92,10 @@
/** Get an OnlineUser object - lock it with lock()!
* @return OnlineUser* found by CID, using the hub URL as a hint.
*/
- OnlineUser* findOnlineUser(const HintedUser& user);
- OnlineUser* findOnlineUser(const CID& cid, const string& hintUrl);
+ OnlineUser* findOnlineUser(const HintedUser& user) const;
+ OnlineUser* findOnlineUser(const CID& cid, const string& hintUrl) const;
/// @return OnlineUser* found by CID and hint; discard any user that doesn't match the hint.
+ OnlineUser* findOnlineUserHint(const HintedUser& user) const;
OnlineUser* findOnlineUserHint(const CID& cid, const string& hintUrl) const;
UserPtr findUser(const string& aNick, const string& aHubUrl) const noexcept { return findUser(makeCid(aNick, aHubUrl)); }
@@ -111,6 +112,8 @@
/** Constructs a synthetic, hopefully unique CID */
CID makeCid(const string& nick, const string& hubUrl) const noexcept;
+ /** Send a ClientListener::Updated signal for every connected user. */
+ void updateUsers();
void putOnline(OnlineUser* ou) noexcept;
void putOffline(OnlineUser* ou, bool disconnect = false) noexcept;
=== modified file 'dcpp/UserMatchManager.cpp'
--- dcpp/UserMatchManager.cpp 2012-06-22 14:46:44 +0000
+++ dcpp/UserMatchManager.cpp 2012-06-23 10:44:48 +0000
@@ -35,28 +35,30 @@
SettingsManager::getInstance()->removeListener(this);
}
-const UserMatchManager::UserMatches& UserMatchManager::getList() const {
+UserMatchManager::UserMatches UserMatchManager::getList() const {
+ boost::shared_lock<boost::shared_mutex> lock(mutex);
return list;
}
-void UserMatchManager::setList(UserMatches&& newList) {
+void UserMatchManager::setList(UserMatches&& newList, bool updateUsers) {
if(list.empty() && newList.empty())
return;
- // operate within the ClientManager lock.
- auto cm = ClientManager::getInstance();
- auto lock = cm->lock();
-
- // assign the new list.
- const_cast<UserMatches&>(list) = move(newList);
-
- // refresh user matches.
- for(auto i: cm->getClients()) {
- i->updateUsers();
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mutex);
+ const_cast<UserMatches&>(list) = move(newList);
+ }
+
+ if(updateUsers) {
+ /* this is here as a convenience because user properties have to be refreshed most of the
+ time when the matching list has been modified. */
+ ClientManager::getInstance()->updateUsers();
}
}
void UserMatchManager::match(OnlineUser& user) const {
+ boost::shared_lock<boost::shared_mutex> lock(mutex);
+
auto& identity = user.getIdentity();
bool chatSet = false;
@@ -88,20 +90,40 @@
identity.setStyle(std::move(style));
}
+pair<bool, bool> UserMatchManager::checkPredef() const {
+ boost::shared_lock<boost::shared_mutex> lock(mutex);
+ pair<bool, bool> ret(false, false);
+ for(auto& i: list) {
+ if(i.isSet(UserMatch::PREDEFINED)) {
+ if(i.isSet(UserMatch::FAVS)) { ret.first = true; }
+ else if(i.isSet(UserMatch::OPS)) { ret.second = true; }
+ if(ret.first && ret.second) { break; }
+ }
+ }
+ return ret;
+}
+
+unordered_set<string> UserMatchManager::getFonts() const {
+ boost::shared_lock<boost::shared_mutex> lock(mutex);
+ unordered_set<string> ret;
+ for(auto& i: list) {
+ if(!i.style.font.empty()) {
+ ret.insert(i.style.font);
+ }
+ }
+ return ret;
+}
+
void UserMatchManager::ignoreChat(const HintedUser& user, bool ignore) {
- setList(ignoreChatImpl(list, user, ignore));
-}
-
-void UserMatchManager::ignoreChat(const HintedUserList& users, bool ignore) {
- auto newList = list;
- for(auto& user: users) {
- newList = ignoreChatImpl(newList, user, ignore);
+ auto lock = ClientManager::getInstance()->lock();
+ auto ou = ClientManager::getInstance()->findOnlineUserHint(user);
+ if(!ou) {
+ return;
}
- setList(move(newList));
-}
-
-UserMatchManager::UserMatches UserMatchManager::ignoreChatImpl(const UserMatches& list, const HintedUser& user, bool ignore) {
- auto nick = ClientManager::getInstance()->getNicks(user)[0];
+ auto nick = ou->getIdentity().getNick();
+ // no need to re-match all users; just update this one.
+ ou->getIdentity().setNoChat(ignore);
+ lock.unlock();
UserMatch matcher;
matcher.setFlag(UserMatch::GENERATED);
@@ -144,7 +166,7 @@
}
newList.insert(newList.begin(), std::move(matcher));
- return newList;
+ setList(move(newList), false);
}
void UserMatchManager::on(SettingsManagerListener::Load, SimpleXML& xml) noexcept {
@@ -196,6 +218,8 @@
}
void UserMatchManager::on(SettingsManagerListener::Save, SimpleXML& xml) noexcept {
+ boost::shared_lock<boost::shared_mutex> lock(mutex);
+
xml.addTag("UserMatches");
xml.stepIn();
for(auto& i: list) {
=== modified file 'dcpp/UserMatchManager.h'
--- dcpp/UserMatchManager.h 2012-06-22 14:46:44 +0000
+++ dcpp/UserMatchManager.h 2012-06-23 10:44:48 +0000
@@ -19,43 +19,61 @@
#ifndef DCPLUSPLUS_DCPP_USER_MATCH_MANAGER_H
#define DCPLUSPLUS_DCPP_USER_MATCH_MANAGER_H
+#include <string>
+#include <unordered_set>
+#include <vector>
+
#include "forward.h"
#include "SettingsManager.h"
+#include "Singleton.h"
#include "UserMatch.h"
+#include <boost/thread/locks.hpp>
+#include <boost/thread/shared_mutex.hpp>
+
namespace dcpp {
-/** This class manages user matching definitions. The list doesn't have to be locked; instead,
-special care is taken when updating it. */
+using std::string;
+using std::unordered_set;
+using std::vector;
+
+/** This class manages user matching definitions. Online users are matched against these
+definitions to find properties to apply (such as chat ignoring, custom colors...). */
class UserMatchManager :
public Singleton<UserMatchManager>,
private SettingsManagerListener
{
- typedef std::vector<UserMatch> UserMatches;
+ typedef vector<UserMatch> UserMatches;
public:
- /// Retrieve the list of user matching definitions.
- const UserMatches& getList() const;
- /// Assign a new list of user matching definitions. All current users will be re-matched.
- void setList(UserMatches&& newList);
+ /** Retrieve the list of user matching definitions. */
+ UserMatches getList() const;
+ /** Assign a new list of user matching definitions. */
+ void setList(UserMatches&& newList, bool updateUsers = true);
/** Match the given user against current user matching definitions. The user's identity object
will be modified accordingly. */
void match(OnlineUser& user) const;
+ /** Helper function that tells whether predefined definitions for favorites (pair.first) and
+ operators (pair.second) are existing. */
+ pair<bool, bool> checkPredef() const;
+ /** Get a list of the fonts required by current user matching definitions. */
+ unordered_set<string> getFonts() const;
+ /** Add a user matching definition at the top of the list to match the given user and force her
+ to be ignored or un-ignored. If an untampered previously generated definition is already
+ existing, it is removed. */
void ignoreChat(const HintedUser& user, bool ignore);
- void ignoreChat(const HintedUserList& users, bool ignore);
private:
friend class Singleton<UserMatchManager>;
const UserMatches list; // const to make sure only setList can change this.
+ mutable boost::shared_mutex mutex; // shared to allow multiple readers (each hub).
UserMatchManager();
virtual ~UserMatchManager();
- static UserMatches ignoreChatImpl(const UserMatches& list, const HintedUser& user, bool ignore);
-
void on(SettingsManagerListener::Load, SimpleXML& xml) noexcept;
void on(SettingsManagerListener::Save, SimpleXML& xml) noexcept;
};
=== modified file 'win32/UserInfoBase.cpp'
--- win32/UserInfoBase.cpp 2012-06-22 14:46:44 +0000
+++ win32/UserInfoBase.cpp 2012-06-23 10:44:48 +0000
@@ -80,10 +80,6 @@
UserMatchManager::getInstance()->ignoreChat(user, ignore);
}
-void UserInfoBase::ignoreChat(const HintedUserList& users, bool ignore) {
- UserMatchManager::getInstance()->ignoreChat(users, ignore);
-}
-
tstring UserInfoBase::getTooltip() const {
static const size_t maxChars = 100; // max chars per tooltip line
=== modified file 'win32/UserInfoBase.h'
--- win32/UserInfoBase.h 2012-06-22 14:46:44 +0000
+++ win32/UserInfoBase.h 2012-06-23 10:44:48 +0000
@@ -47,7 +47,6 @@
virtual void removeFromQueue();
virtual void connectFav(TabViewPtr);
virtual void ignoreChat(bool ignore);
- static void ignoreChat(const HintedUserList& users, bool ignore);
tstring getTooltip() const;
@@ -128,10 +127,7 @@
handleUserFunction([&](UserInfoBase* u) { u->connectFav(parent); });
}
void handleIgnoreChat(bool ignore) {
- // group multiple ignore calls into a single one.
- HintedUserList users;
- handleUserFunction([&users](UserInfoBase* u) { users.push_back(u->getUser()); });
- UserInfoBase::ignoreChat(users, ignore);
+ handleUserFunction([ignore](UserInfoBase* u) { u->ignoreChat(ignore); });
}
void appendUserItems(TabViewPtr parent, Menu* menu, bool defaultIsGetList = true, bool includeSendPM = true) {
=== modified file 'win32/WinUtil.cpp'
--- win32/WinUtil.cpp 2012-06-21 18:52:47 +0000
+++ win32/WinUtil.cpp 2012-06-23 10:44:48 +0000
@@ -444,20 +444,12 @@
void WinUtil::initUserMatching() {
// make sure predefined definitions are here.
- bool favDefHere = false, opDefHere = false;
- const auto& list = UserMatchManager::getInstance()->getList();
- for(auto& i: list) {
- if(i.isSet(UserMatch::PREDEFINED)) {
- if(i.isSet(UserMatch::FAVS)) { favDefHere = true; }
- else if(i.isSet(UserMatch::OPS)) { opDefHere = true; }
- if(favDefHere && opDefHere) { break; }
- }
- }
-
- if(!favDefHere || !opDefHere) {
- auto newList = list;
-
- if(!favDefHere) {
+ auto here = UserMatchManager::getInstance()->checkPredef();
+
+ if(!here.first || !here.second) {
+ auto newList = UserMatchManager::getInstance()->getList();
+
+ if(!here.first) {
// add a matcher for favs.
UserMatch matcher;
matcher.setFlag(UserMatch::PREDEFINED);
@@ -468,7 +460,7 @@
newList.push_back(std::move(matcher));
}
- if(!opDefHere) {
+ if(!here.second) {
// add a matcher for ops.
UserMatch matcher;
matcher.setFlag(UserMatch::PREDEFINED);
@@ -487,12 +479,10 @@
void WinUtil::updateUserMatchFonts() {
userMatchFonts.clear();
- for(auto& i: UserMatchManager::getInstance()->getList()) {
- if(!i.style.font.empty()) {
- LOGFONT lf;
- decodeFont(Text::toT(i.style.font), lf);
- userMatchFonts[i.style.font] = new dwt::Font(lf);
- }
+ for(auto& font: UserMatchManager::getInstance()->getFonts()) {
+ LOGFONT lf;
+ decodeFont(Text::toT(font), lf);
+ userMatchFonts[font] = new dwt::Font(lf);
}
}