Automatically synchronize CoreInfo when on connect and disconnect
authorJanne Koschinski <janne@kuschku.de>
Fri, 2 Mar 2018 03:04:50 +0000 (21:04 -0600)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 6 Jun 2018 17:37:44 +0000 (19:37 +0200)
This refactors CoreInfo to be a single common class rather than
separate classes for the core and client, adjusts it to properly
use the SyncableObject infrastructure, and adds support for
dynamically updating the list on both the client and core when a
client connects or disconnects, keeping the list up-to-date at all
times.  Forwards and backwards compatibility is maintained, though
the updated client is required in order for the automatic updating
to work.

Signed-off-by: Janne Koschinski <janne@kuschku.de>
Co-authored-by: Janne Koschinski <janne@kuschku.de>
Co-authored-by: Michael Marley <michael@michaelmarley.com>
13 files changed:
src/client/CMakeLists.txt
src/client/client.cpp
src/client/client.h
src/client/clientcoreinfo.h [deleted file]
src/common/CMakeLists.txt
src/common/coreinfo.cpp [moved from src/core/corecoreinfo.h with 72% similarity]
src/common/coreinfo.h
src/core/CMakeLists.txt
src/core/corecoreinfo.cpp [deleted file]
src/core/coresession.cpp
src/core/coresession.h
src/qtui/coreinfodlg.cpp
src/qtui/coreinfodlg.h

index f0733f0..7e171d2 100644 (file)
@@ -36,7 +36,6 @@ set(SOURCES
 
     # needed for automoc
     abstractui.h
-    clientcoreinfo.h
 )
 
 if (USE_QT5)
index f8627d0..0c71bef 100644 (file)
@@ -101,6 +101,7 @@ Client::Client(QObject *parent)
     _backlogManager(new ClientBacklogManager(this)),
     _bufferViewManager(0),
     _bufferViewOverlay(new BufferViewOverlay(this)),
+    _coreInfo(nullptr),
     _dccConfig(0),
     _ircListHelper(new ClientIrcListHelper(this)),
     _inputHandler(0),
@@ -400,6 +401,11 @@ void Client::setSyncedToCore()
     SignalProxy *p = signalProxy();
     p->synchronize(bufferSyncer());
 
+    // create CoreInfo
+    Q_ASSERT(!_coreInfo);
+    _coreInfo = new CoreInfo(this);
+    p->synchronize(coreInfo());
+
     // create a new BufferViewManager
     Q_ASSERT(!_bufferViewManager);
     _bufferViewManager = new ClientBufferViewManager(p, this);
@@ -500,6 +506,11 @@ void Client::setDisconnectedFromCore()
         _bufferSyncer = 0;
     }
 
+    if (_coreInfo) {
+        _coreInfo->deleteLater();
+        _coreInfo = nullptr;
+    }
+
     if (_bufferViewManager) {
         _bufferViewManager->deleteLater();
         _bufferViewManager = 0;
index 4b8c4bc..3dc261a 100644 (file)
@@ -24,6 +24,7 @@
 #include <QPointer>
 
 #include "bufferinfo.h"
+#include "coreinfo.h"
 #include "coreaccount.h"
 #include "coreconnection.h"
 #include "highlightrulemanager.h"
@@ -115,6 +116,7 @@ public:
 
     static inline ClientAliasManager *aliasManager() { return instance()->_aliasManager; }
     static inline ClientBacklogManager *backlogManager() { return instance()->_backlogManager; }
+    static inline CoreInfo *coreInfo() { return instance()->_coreInfo; }
     static inline DccConfig *dccConfig() { return instance()->_dccConfig; }
     static inline ClientIrcListHelper *ircListHelper() { return instance()->_ircListHelper; }
     static inline ClientBufferViewManager *bufferViewManager() { return instance()->_bufferViewManager; }
@@ -264,6 +266,7 @@ private:
     ClientBacklogManager *_backlogManager;
     ClientBufferViewManager *_bufferViewManager;
     BufferViewOverlay *_bufferViewOverlay;
+    CoreInfo *_coreInfo;
     DccConfig *_dccConfig;
     ClientIrcListHelper *_ircListHelper;
     ClientUserInputHandler *_inputHandler;
diff --git a/src/client/clientcoreinfo.h b/src/client/clientcoreinfo.h
deleted file mode 100644 (file)
index 60a96d0..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005-2018 by the Quassel Project                        *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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) version 3.                                           *
- *                                                                         *
- *   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  02110-1301, USA.         *
- ***************************************************************************/
-
-#ifndef CLIENTCOREINFO_H
-#define CLIENTCOREINFO_H
-
-#include "coreinfo.h"
-
-/*
- * Yes this name is somewhat stupid... but it fits the general naming scheme
- * which is prefixing client specific sync objects with "Client"... ;)
- */
-class ClientCoreInfo : public CoreInfo
-{
-    Q_OBJECT
-        SYNCABLE_OBJECT
-
-public:
-    ClientCoreInfo(QObject *parent = 0) : CoreInfo(parent) {}
-
-    inline virtual const QMetaObject *syncMetaObject() const { return &CoreInfo::staticMetaObject; }
-
-    inline QVariant &operator[](const QString &key) { return _coreData[key]; }
-
-public slots:
-    inline virtual void setCoreData(const QVariantMap &data) { _coreData = data; }
-
-private:
-    QVariantMap _coreData;
-};
-
-
-#endif //CLIENTCOREINFO_H
index 8ec2bed..d330d2c 100644 (file)
@@ -10,6 +10,7 @@ set(SOURCES
     bufferviewconfig.cpp
     bufferviewmanager.cpp
     compressor.cpp
+    coreinfo.cpp
     ctcpevent.cpp
     dccconfig.cpp
     event.cpp
@@ -47,7 +48,6 @@ set(SOURCES
     protocols/legacy/legacypeer.cpp
 
     # needed for automoc
-    coreinfo.h
     irccap.h
     protocol.h
 )
similarity index 72%
rename from src/core/corecoreinfo.h
rename to src/common/coreinfo.cpp
index 991ebf9..e4019c7 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef CORECOREINFO_H
-#define CORECOREINFO_H
-
 #include "coreinfo.h"
 
-class CoreSession;
+INIT_SYNCABLE_OBJECT(CoreInfo)
+CoreInfo::CoreInfo(QObject *parent) : SyncableObject(parent) {}
 
-/*
- * Yes this name is somewhat stupid... but it fits the general naming scheme
- * which is prefixing core specific sync objects with "Core"... ;)
- */
-class CoreCoreInfo : public CoreInfo
+QVariantMap CoreInfo::coreData() const
 {
-    SYNCABLE_OBJECT
-        Q_OBJECT
-
-public:
-    CoreCoreInfo(CoreSession *parent);
-
-    inline virtual const QMetaObject *syncMetaObject() const { return &CoreInfo::staticMetaObject; }
-
-public slots:
-    virtual QVariantMap coreData() const;
-
-private:
-    CoreSession *_coreSession;
-};
+    return _coreData;
+}
 
+void CoreInfo::setCoreData(const QVariantMap &coreData)
+{
+    _coreData = coreData;
+    SYNC(ARG(coreData));
+    emit coreDataChanged(coreData);
+}
 
-#endif //CORECOREINFO_H
+void CoreInfo::setConnectedClientData(const int peerCount, const QVariantList peerData)
+{
+    _coreData["sessionConnectedClients"] = peerCount;
+    _coreData["sessionConnectedClientData"] = peerData;
+    setCoreData(_coreData);
+}
index 291f5a1..26879d4 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef COREINFO_H
-#define COREINFO_H
+#pragma once
 
 #include "syncableobject.h"
 
 /*
- * gather various informations about the core.
+ * gather various information about the core.
  */
 
 class CoreInfo : public SyncableObject
 {
     Q_OBJECT
+    SYNCABLE_OBJECT
 
-    Q_PROPERTY(QVariantMap coreData READ coreData WRITE setCoreData STORED false)
+    Q_PROPERTY(QVariantMap coreData READ coreData WRITE setCoreData)
 
-public :
-        CoreInfo(QObject *parent = 0) : SyncableObject(parent) {}
+public:
+    explicit CoreInfo(QObject *parent = nullptr);
+    inline QVariant &at(const QString &key) { return _coreData[key]; }
 
-public slots:
-    virtual inline QVariantMap coreData() const { return QVariantMap(); }
-    virtual inline void setCoreData(const QVariantMap &) {}
-};
+    void setConnectedClientData(int, QVariantList);
 
+signals:
+    void coreDataChanged(QVariantMap);
 
-#endif //COREINFO_H
+public slots:
+    QVariantMap coreData() const;
+    void setCoreData(const QVariantMap &);
+
+private:
+    QVariantMap _coreData;
+};
index 1ec6797..be5133b 100644 (file)
@@ -12,7 +12,6 @@ set(SOURCES
     corebuffersyncer.cpp
     corebufferviewconfig.cpp
     corebufferviewmanager.cpp
-    corecoreinfo.cpp
     coredccconfig.cpp
     corehighlightrulemanager.cpp
     coreidentity.cpp
diff --git a/src/core/corecoreinfo.cpp b/src/core/corecoreinfo.cpp
deleted file mode 100644 (file)
index b92e4d4..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2005-2018 by the Quassel Project                        *
- *   devel@quassel-irc.org                                                 *
- *                                                                         *
- *   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) version 3.                                           *
- *                                                                         *
- *   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  02110-1301, USA.         *
- ***************************************************************************/
-
-#include "corecoreinfo.h"
-
-#include "core.h"
-#include "coresession.h"
-#include "quassel.h"
-#include "signalproxy.h"
-
-INIT_SYNCABLE_OBJECT(CoreCoreInfo)
-CoreCoreInfo::CoreCoreInfo(CoreSession *parent)
-    : CoreInfo(parent),
-    _coreSession(parent)
-{
-}
-
-
-QVariantMap CoreCoreInfo::coreData() const
-{
-    QVariantMap data;
-    data["quasselVersion"] = Quassel::buildInfo().fancyVersionString;
-    data["quasselBuildDate"] = Quassel::buildInfo().commitDate; // "BuildDate" for compatibility
-    data["startTime"] = Core::instance()->startTime();
-    data["sessionConnectedClients"] = _coreSession->signalProxy()->peerCount();
-    data["sessionConnectedClientData"] = _coreSession->signalProxy()->peerData();
-    return data;
-}
index 64f4608..afaf48d 100644 (file)
@@ -31,6 +31,7 @@
 #include "coreeventmanager.h"
 #include "coreidentity.h"
 #include "coreignorelistmanager.h"
+#include "coreinfo.h"
 #include "coreirclisthelper.h"
 #include "corenetwork.h"
 #include "corenetworkconfig.h"
@@ -68,7 +69,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     _dccConfig(new CoreDccConfig(this)),
     _ircListHelper(new CoreIrcListHelper(this)),
     _networkConfig(new CoreNetworkConfig("GlobalNetworkConfig", this)),
-    _coreInfo(this),
+    _coreInfo(new CoreInfo(this)),
     _transferManager(new CoreTransferManager(this)),
     _eventManager(new CoreEventManager(this)),
     _eventStringifier(new EventStringifier(this)),
@@ -109,6 +110,13 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     p->attachSlot(SIGNAL(kickClient(int)), this, SLOT(kickClient(int)));
     p->attachSignal(this, SIGNAL(disconnectFromCore()));
 
+    QVariantMap data;
+    data["quasselVersion"] = Quassel::buildInfo().fancyVersionString;
+    data["quasselBuildDate"] = Quassel::buildInfo().commitDate; // "BuildDate" for compatibility
+    data["startTime"] = Core::instance()->startTime();
+    data["sessionConnectedClients"] = 0;
+    _coreInfo->setCoreData(data);
+
     loadSettings();
     initScriptEngine();
 
@@ -130,7 +138,7 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     p->synchronize(dccConfig());
     p->synchronize(ircListHelper());
     p->synchronize(networkConfig());
-    p->synchronize(&_coreInfo);
+    p->synchronize(_coreInfo);
     p->synchronize(&_ignoreListManager);
     p->synchronize(&_highlightRuleManager);
     p->synchronize(transferManager());
@@ -266,6 +274,7 @@ void CoreSession::addClient(RemotePeer *peer)
 
     peer->dispatch(sessionState());
     signalProxy()->addPeer(peer);
+    _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData());
 
     signalProxy()->setTargetPeer(nullptr);
 }
@@ -283,6 +292,7 @@ void CoreSession::removeClient(Peer *peer)
     RemotePeer *p = qobject_cast<RemotePeer *>(peer);
     if (p)
         quInfo() << qPrintable(tr("Client")) << p->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt()));
+    _coreInfo->setConnectedClientData(signalProxy()->peerCount(), signalProxy()->peerData());
 }
 
 
index 72843a5..e13ff64 100644 (file)
@@ -24,7 +24,7 @@
 #include <QString>
 #include <QVariant>
 
-#include "corecoreinfo.h"
+#include "coreinfo.h"
 #include "corealiasmanager.h"
 #include "corehighlightrulemanager.h"
 #include "coreignorelistmanager.h"
@@ -223,7 +223,7 @@ private:
     CoreDccConfig *_dccConfig;
     CoreIrcListHelper *_ircListHelper;
     CoreNetworkConfig *_networkConfig;
-    CoreCoreInfo _coreInfo;
+    CoreInfo *_coreInfo;
     CoreTransferManager *_transferManager;
 
     EventManager *_eventManager;
index 3552880..e5eb7f4 100644 (file)
 
 #include "coreinfodlg.h"
 
-#include <QDateTime>
-
 #include "client.h"
-#include "signalproxy.h"
 #include "bufferwidget.h"
-#include "coresessionwidget.h"
 
-CoreInfoDlg::CoreInfoDlg(QWidget *parent)
-    : QDialog(parent),
-    _coreInfo(this)
-{
+CoreInfoDlg::CoreInfoDlg(QWidget *parent) : QDialog(parent) {
     ui.setupUi(this);
-    connect(&_coreInfo, SIGNAL(initDone()), this, SLOT(coreInfoAvailable()));
-    Client::signalProxy()->synchronize(&_coreInfo);
+    CoreInfo *coreInfo = Client::coreInfo();
+    connect(coreInfo, SIGNAL(coreDataChanged(const QVariantMap &)), this, SLOT(coreInfoChanged(const QVariantMap &)));
+
+    coreInfoChanged(coreInfo->coreData());
+
+    updateUptime();
+    startTimer(1000);
 }
 
 
-void CoreInfoDlg::coreInfoAvailable()
-{
-    ui.labelCoreVersion->setText(_coreInfo["quasselVersion"].toString());
-    ui.labelCoreVersionDate->setText(_coreInfo["quasselBuildDate"].toString()); // "BuildDate" for compatibility
-    ui.labelClientCount->setNum(_coreInfo["sessionConnectedClients"].toInt());
+void CoreInfoDlg::coreInfoChanged(const QVariantMap &coreInfo) {
+    ui.labelCoreVersion->setText(coreInfo["quasselVersion"].toString());
+    ui.labelCoreVersionDate->setText(coreInfo["quasselBuildDate"].toString()); // "BuildDate" for compatibility
+    ui.labelClientCount->setNum(coreInfo["sessionConnectedClients"].toInt());
 
     auto coreSessionSupported = false;
-    for (const auto &peerData : _coreInfo["sessionConnectedClientData"].toList()) {
+    auto ids = _widgets.keys();
+    for (const auto &peerData : coreInfo["sessionConnectedClientData"].toList()) {
         coreSessionSupported = true;
 
-        auto coreSessionWidget = new CoreSessionWidget(ui.coreSessionScrollContainer);
-        coreSessionWidget->setData(peerData.toMap());
-        ui.coreSessionContainer->addWidget(coreSessionWidget);
-        connect(coreSessionWidget, SIGNAL(disconnectClicked(int)), this, SLOT(disconnectClicked(int)));
+        auto peerMap = peerData.toMap();
+        int peerId = peerMap["id"].toInt();
+
+        ids.removeAll(peerId);
+
+        bool isNew = false;
+        CoreSessionWidget *coreSessionWidget = _widgets[peerId];
+        if (coreSessionWidget == nullptr) {
+            coreSessionWidget = new CoreSessionWidget(ui.coreSessionScrollContainer);
+            isNew = true;
+        }
+        coreSessionWidget->setData(peerMap);
+        if (isNew) {
+            _widgets[peerId] = coreSessionWidget;
+            ui.coreSessionContainer->addWidget(coreSessionWidget);
+            connect(coreSessionWidget, SIGNAL(disconnectClicked(int)), this, SLOT(disconnectClicked(int)));
+        }
     }
 
-    ui.coreSessionScrollArea->setVisible(coreSessionSupported);
+    for (const auto &key : ids) {
+        delete _widgets[key];
+        _widgets.remove(key);
+    }
 
+    ui.coreSessionScrollArea->setVisible(coreSessionSupported);
     ui.coreSessionContainer->addStretch(1);
-
-    updateUptime();
-    startTimer(1000);
 }
 
 
-void CoreInfoDlg::updateUptime()
-{
-    QDateTime startTime = _coreInfo["startTime"].toDateTime();
+void CoreInfoDlg::updateUptime() {
+    CoreInfo *coreInfo = Client::coreInfo();
+    if (coreInfo) {
+        QDateTime startTime = coreInfo->at("startTime").toDateTime();
 
-    int uptime = startTime.secsTo(QDateTime::currentDateTime().toUTC());
-    int updays = uptime / 86400; uptime %= 86400;
-    int uphours = uptime / 3600; uptime %= 3600;
-    int upmins = uptime / 60; uptime %= 60;
+        int64_t uptime = startTime.secsTo(QDateTime::currentDateTime().toUTC());
+        int64_t updays = uptime / 86400;
+        uptime %= 86400;
+        int64_t uphours = uptime / 3600;
+        uptime %= 3600;
+        int64_t upmins = uptime / 60;
+        uptime %= 60;
 
-    QString uptimeText = tr("%n Day(s)", "", updays)
-                         + tr(" %1:%2:%3 (since %4)").arg(uphours, 2, 10, QChar('0')).arg(upmins, 2, 10, QChar('0')).arg(uptime, 2, 10, QChar('0')).arg(startTime.toLocalTime().toString(Qt::TextDate));
-    ui.labelUptime->setText(uptimeText);
+        QString uptimeText = tr("%n Day(s)", "", updays) +
+                             tr(" %1:%2:%3 (since %4)")
+                                     .arg(uphours, 2, 10, QChar('0'))
+                                     .arg(upmins, 2, 10, QChar('0'))
+                                     .arg(uptime, 2, 10, QChar('0'))
+                                     .arg(startTime.toLocalTime().toString(Qt::TextDate));
+        ui.labelUptime->setText(uptimeText);
+    }
 }
-void CoreInfoDlg::disconnectClicked(int peerId)
-{
+
+void CoreInfoDlg::disconnectClicked(int peerId) {
     Client::kickClient(peerId);
 }
index 038c427..85a9211 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef COREINFODLG_H
-#define COREINFODLG_H
+#pragma once
 
-#include "ui_coreinfodlg.h"
 #include <QDialog>
 
-#include "clientcoreinfo.h"
+#include "ui_coreinfodlg.h"
+#include "coreinfo.h"
+#include "coresessionwidget.h"
 
-class CoreInfoDlg : public QDialog
-{
-    Q_OBJECT
+class CoreInfoDlg : public QDialog {
+Q_OBJECT
 
 public:
-    CoreInfoDlg(QWidget *parent = 0);
+    explicit CoreInfoDlg(QWidget *parent = nullptr);
 
 public slots:
-    void coreInfoAvailable();
+    void coreInfoChanged(const QVariantMap &);
 
 protected:
-    virtual void timerEvent(QTimerEvent *) { updateUptime(); }
+    void timerEvent(QTimerEvent *) override { updateUptime(); }
 
 private slots:
     void on_closeButton_clicked() { reject(); }
@@ -46,8 +45,5 @@ private slots:
 
 private:
     Ui::CoreInfoDlg ui;
-    ClientCoreInfo _coreInfo;
+    QMap<int, CoreSessionWidget *> _widgets;
 };
-
-
-#endif //COREINFODLG_H