235
235
_ircUsers[nick] = ircuser;
237
SYNC_OTHER(addIrcUser, ARG(hostmask))
238
// emit ircUserAdded(hostmask);
237
// This method will be called with a nick instead of hostmask by setInitIrcUsersAndChannels().
238
// Not a problem because initData contains all we need; however, making sure here to get the real
239
// hostmask out of the IrcUser afterwards.
240
QString mask = ircuser->hostmask();
241
SYNC_OTHER(addIrcUser, ARG(mask));
242
// emit ircUserAdded(mask);
239
243
emit ircUserAdded(ircuser);
781
// There's potentially a lot of users and channels, so it makes sense to optimize the format of this.
782
// Rather than sending a thousand maps with identical keys, we convert this into one map containing lists
783
// where each list index corresponds to a particular IrcUser. This saves sending the key names a thousand times.
784
// Benchmarks have shown space savings of around 56%, resulting in saving several MBs worth of data on sync
785
// (without compression) with a decent amount of IrcUsers.
777
786
QVariantMap Network::initIrcUsersAndChannels() const
779
788
QVariantMap usersAndChannels;
781
QVariantMap channels;
783
QHash<QString, IrcUser *>::const_iterator userIter = _ircUsers.constBegin();
784
QHash<QString, IrcUser *>::const_iterator userIterEnd = _ircUsers.constEnd();
785
while (userIter != userIterEnd) {
786
users[userIter.value()->hostmask()] = userIter.value()->toVariantMap();
789
usersAndChannels["users"] = users;
791
QHash<QString, IrcChannel *>::const_iterator channelIter = _ircChannels.constBegin();
792
QHash<QString, IrcChannel *>::const_iterator channelIterEnd = _ircChannels.constEnd();
793
while (channelIter != channelIterEnd) {
794
channels[channelIter.value()->name()] = channelIter.value()->toVariantMap();
797
usersAndChannels["channels"] = channels;
790
if (_ircUsers.count()) {
791
QHash<QString, QVariantList> users;
792
QHash<QString, IrcUser *>::const_iterator it = _ircUsers.begin();
793
QHash<QString, IrcUser *>::const_iterator end = _ircUsers.end();
795
const QVariantMap &map = it.value()->toVariantMap();
796
QVariantMap::const_iterator mapiter = map.begin();
797
while (mapiter != map.end()) {
798
users[mapiter.key()] << mapiter.value();
803
// Can't have a container with a value type != QVariant in a QVariant :(
804
// However, working directly on a QVariantMap is awkward for appending, thus the detour via the hash above.
806
foreach(const QString &key, users.keys())
807
userMap[key] = users[key];
808
usersAndChannels["Users"] = userMap;
811
if (_ircChannels.count()) {
812
QHash<QString, QVariantList> channels;
813
QHash<QString, IrcChannel *>::const_iterator it = _ircChannels.begin();
814
QHash<QString, IrcChannel *>::const_iterator end = _ircChannels.end();
816
const QVariantMap &map = it.value()->toVariantMap();
817
QVariantMap::const_iterator mapiter = map.begin();
818
while (mapiter != map.end()) {
819
channels[mapiter.key()] << mapiter.value();
824
QVariantMap channelMap;
825
foreach(const QString &key, channels.keys())
826
channelMap[key] = channels[key];
827
usersAndChannels["Channels"] = channelMap;
799
830
return usersAndChannels;
805
836
Q_ASSERT(proxy());
806
837
if (isInitialized()) {
807
qWarning() << "Network" << networkId() << "received init data for users and channels allthough there allready are known users or channels!";
838
qWarning() << "Network" << networkId() << "received init data for users and channels although there already are known users or channels!";
811
QVariantMap users = usersAndChannels.value("users").toMap();
812
QVariantMap::const_iterator userIter = users.constBegin();
813
QVariantMap::const_iterator userIterEnd = users.constEnd();
814
while (userIter != userIterEnd) {
815
newIrcUser(userIter.key(), userIter.value().toMap());
819
QVariantMap channels = usersAndChannels.value("channels").toMap();
820
QVariantMap::const_iterator channelIter = channels.constBegin();
821
QVariantMap::const_iterator channelIterEnd = channels.constEnd();
822
while (channelIter != channelIterEnd) {
823
newIrcChannel(channelIter.key(), channelIter.value().toMap());
842
// toMap() and toList() are cheap, so we can avoid copying to lists...
843
// However, we really have to make sure to never accidentally detach from the shared data!
845
const QVariantMap &users = usersAndChannels["Users"].toMap();
848
int count = users["nick"].toList().count();
849
foreach(const QString &key, users.keys()) {
850
if (users[key].toList().count() != count) {
851
qWarning() << "Received invalid usersAndChannels init data, sizes of attribute lists don't match!";
856
// now create the individual IrcUsers
857
for(int i = 0; i < count; i++) {
859
foreach(const QString &key, users.keys())
860
map[key] = users[key].toList().at(i);
861
newIrcUser(map["nick"].toString(), map); // newIrcUser() properly handles the hostmask being just the nick
864
// same thing for IrcChannels
865
const QVariantMap &channels = usersAndChannels["Channels"].toMap();
868
count = channels["name"].toList().count();
869
foreach(const QString &key, channels.keys()) {
870
if (channels[key].toList().count() != count) {
871
qWarning() << "Received invalid usersAndChannels init data, sizes of attribute lists don't match!";
875
// now create the individual IrcChannels
876
for(int i = 0; i < count; i++) {
878
foreach(const QString &key, channels.keys())
879
map[key] = channels[key].toList().at(i);
880
newIrcChannel(map["name"].toString(), map);