Add initial implementation for showing and kicking connected clients
authorJanne Koschinski <janne@kuschku.de>
Sun, 27 Aug 2017 02:29:53 +0000 (04:29 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Tue, 19 Dec 2017 22:25:23 +0000 (23:25 +0100)
Adds the possibility to show a list of connected clients, and allow
to kick other (or your own) clients of the same user.

src/client/client.cpp
src/client/client.h
src/common/peer.h
src/common/signalproxy.cpp
src/common/signalproxy.h
src/core/coreauthhandler.cpp
src/core/corecoreinfo.cpp
src/core/coresession.cpp
src/core/coresession.h
src/qtui/coreinfodlg.cpp

index 343ad85..0a19351 100644 (file)
@@ -160,6 +160,8 @@ void Client::init()
     p->attachSignal(this, SIGNAL(requestPasswordChange(PeerPtr,QString,QString,QString)), SIGNAL(changePassword(PeerPtr,QString,QString,QString)));
     p->attachSlot(SIGNAL(passwordChanged(PeerPtr,bool)), this, SLOT(corePasswordChanged(PeerPtr,bool)));
 
     p->attachSignal(this, SIGNAL(requestPasswordChange(PeerPtr,QString,QString,QString)), SIGNAL(changePassword(PeerPtr,QString,QString,QString)));
     p->attachSlot(SIGNAL(passwordChanged(PeerPtr,bool)), this, SLOT(corePasswordChanged(PeerPtr,bool)));
 
+    p->attachSignal(this, SIGNAL(requestKickClient(int)), SIGNAL(kickClient(int)));
+
     //connect(mainUi(), SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &)));
     connect(mainUi(), SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore()));
     connect(this, SIGNAL(connected()), mainUi(), SLOT(connectedToCore()));
     //connect(mainUi(), SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &)));
     connect(mainUi(), SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore()));
     connect(this, SIGNAL(connected()), mainUi(), SLOT(connectedToCore()));
@@ -685,6 +687,11 @@ void Client::changePassword(const QString &oldPassword, const QString &newPasswo
 }
 
 
 }
 
 
+void Client::kickClient(int peerId) {
+    emit instance()->requestKickClient(peerId);
+}
+
+
 void Client::corePasswordChanged(PeerPtr, bool success)
 {
     if (success)
 void Client::corePasswordChanged(PeerPtr, bool success)
 {
     if (success)
index 23f7d32..4b83d90 100644 (file)
@@ -149,6 +149,7 @@ public:
     static void purgeKnownBufferIds();
 
     static void changePassword(const QString &oldPassword, const QString &newPassword);
     static void purgeKnownBufferIds();
 
     static void changePassword(const QString &oldPassword, const QString &newPassword);
+    static void kickClient(int peerId);
 
 #if QT_VERSION < 0x050000
     static void logMessage(QtMsgType type, const char *msg);
 
 #if QT_VERSION < 0x050000
     static void logMessage(QtMsgType type, const char *msg);
@@ -201,6 +202,8 @@ signals:
 
     //! Requests a password change (user name must match the currently logged in user)
     void requestPasswordChange(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword);
 
     //! Requests a password change (user name must match the currently logged in user)
     void requestPasswordChange(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword);
+
+    void requestKickClient(int peerId);
     void passwordChanged(bool success);
 
 public slots:
     void passwordChanged(bool success);
 
 public slots:
index 2bbbf72..8c17811 100644 (file)
@@ -50,6 +50,11 @@ public:
 
     virtual int lag() const = 0;
 
 
     virtual int lag() const = 0;
 
+    int _id = -1;
+
+    QString _buildDate;
+    QString _clientVersion;
+
 public slots:
     /* Handshake messages */
     virtual void dispatch(const Protocol::RegisterClient &) = 0;
 public slots:
     /* Handshake messages */
     virtual void dispatch(const Protocol::RegisterClient &) = 0;
index deb78ad..45f3b50 100644 (file)
@@ -288,7 +288,12 @@ bool SignalProxy::addPeer(Peer *peer)
     if (!peer->parent())
         peer->setParent(this);
 
     if (!peer->parent())
         peer->setParent(this);
 
+    if (peer->_id < 0) {
+        peer->_id = nextPeerId();
+    }
+
     _peers.insert(peer);
     _peers.insert(peer);
+    _peerMap[peer->_id] = peer;
 
     peer->setSignalProxy(this);
 
 
     peer->setSignalProxy(this);
 
@@ -331,6 +336,7 @@ void SignalProxy::removePeer(Peer *peer)
     disconnect(peer, 0, this, 0);
     peer->setSignalProxy(0);
 
     disconnect(peer, 0, this, 0);
     peer->setSignalProxy(0);
 
+    _peerMap.remove(peer->_id);
     _peers.remove(peer);
     emit peerRemoved(peer);
 
     _peers.remove(peer);
     emit peerRemoved(peer);
 
@@ -810,6 +816,24 @@ void SignalProxy::updateSecureState()
         emit secureStateChanged(_secure);
 }
 
         emit secureStateChanged(_secure);
 }
 
+QVariantList SignalProxy::peerData() {
+    QVariantList result;
+    for (auto peer : _peers) {
+        QVariantMap data;
+        data["id"] = peer->_id;
+        data["buildData"] = peer->_buildDate;
+        data["clientVersion"] = peer->_clientVersion;
+        data["description"] = peer->description();
+        data["secure"] = peer->isSecure();
+        result << data;
+    }
+    return result;
+}
+
+Peer *SignalProxy::peerById(int peerId) {
+    return _peerMap[peerId];
+}
+
 
 // ==================================================
 //  ExtendedMetaObject
 
 // ==================================================
 //  ExtendedMetaObject
index c07a86b..dce008a 100644 (file)
@@ -78,6 +78,9 @@ public:
     void dumpProxyStats();
     void dumpSyncMap(SyncableObject *object);
     inline int peerCount() const { return _peers.size(); }
     void dumpProxyStats();
     void dumpSyncMap(SyncableObject *object);
     inline int peerCount() const { return _peers.size(); }
+    QVariantList peerData();
+
+    Peer *peerById(int peerId);
 
 public slots:
     void detachObject(QObject *obj);
 
 public slots:
     void detachObject(QObject *obj);
@@ -117,6 +120,10 @@ private:
     void removePeer(Peer *peer);
     void removeAllPeers();
 
     void removePeer(Peer *peer);
     void removeAllPeers();
 
+    int nextPeerId() {
+        return _lastPeerId++;
+    }
+
     template<class T>
     void dispatch(const T &protoMessage);
     template<class T>
     template<class T>
     void dispatch(const T &protoMessage);
     template<class T>
@@ -140,6 +147,7 @@ private:
     static void disconnectDevice(QIODevice *dev, const QString &reason = QString());
 
     QSet<Peer *> _peers;
     static void disconnectDevice(QIODevice *dev, const QString &reason = QString());
 
     QSet<Peer *> _peers;
+    QHash<int, Peer*> _peerMap;
 
     // containg a list of argtypes for fast access
     QHash<const QMetaObject *, ExtendedMetaObject *> _extendedMetaObjects;
 
     // containg a list of argtypes for fast access
     QHash<const QMetaObject *, ExtendedMetaObject *> _extendedMetaObjects;
@@ -162,6 +170,8 @@ private:
 
     bool _secure; // determines if all connections are in a secured state (using ssl or internal connections)
 
 
     bool _secure; // determines if all connections are in a secured state (using ssl or internal connections)
 
+    int _lastPeerId = 0;
+
     friend class SignalRelay;
     friend class SyncableObject;
     friend class Peer;
     friend class SignalRelay;
     friend class SyncableObject;
     friend class Peer;
index 6f454fa..aa1d957 100644 (file)
@@ -183,6 +183,9 @@ void CoreAuthHandler::handle(const RegisterClient &msg)
     // XXX: FIXME: use client features here: we cannot pass authenticators if the client is too old!
     _peer->dispatch(ClientRegistered(Quassel::features(), configured, backends, useSsl, authenticators));
 
     // XXX: FIXME: use client features here: we cannot pass authenticators if the client is too old!
     _peer->dispatch(ClientRegistered(Quassel::features(), configured, backends, useSsl, authenticators));
 
+    _peer->_buildDate = msg.buildDate;
+    _peer->_clientVersion = msg.clientVersion;
+
     if (_legacy && useSsl)
         startSsl();
 
     if (_legacy && useSsl)
         startSsl();
 
index 3c1d5fe..fb5d1fb 100644 (file)
@@ -40,5 +40,6 @@ QVariantMap CoreCoreInfo::coreData() const
     data["quasselBuildDate"] = Quassel::buildInfo().commitDate; // "BuildDate" for compatibility
     data["startTime"] = Core::instance()->startTime();
     data["sessionConnectedClients"] = _coreSession->signalProxy()->peerCount();
     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;
 }
     return data;
 }
index 3782f71..635067a 100644 (file)
@@ -105,6 +105,8 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     p->attachSlot(SIGNAL(changePassword(PeerPtr,QString,QString,QString)), this, SLOT(changePassword(PeerPtr,QString,QString,QString)));
     p->attachSignal(this, SIGNAL(passwordChanged(PeerPtr,bool)));
 
     p->attachSlot(SIGNAL(changePassword(PeerPtr,QString,QString,QString)), this, SLOT(changePassword(PeerPtr,QString,QString,QString)));
     p->attachSignal(this, SIGNAL(passwordChanged(PeerPtr,bool)));
 
+    p->attachSlot(SIGNAL(kickClient(int)), this, SLOT(kickClient(int)));
+
     loadSettings();
     initScriptEngine();
 
     loadSettings();
     initScriptEngine();
 
@@ -717,3 +719,11 @@ void CoreSession::changePassword(PeerPtr peer, const QString &userName, const QS
 
     emit passwordChanged(peer, success);
 }
 
     emit passwordChanged(peer, success);
 }
+
+void CoreSession::kickClient(int peerId) {
+    auto peer = signalProxy()->peerById(peerId);
+    if (!peer) {
+        qWarning() << "Invalid peer Id: " << peerId;
+    }
+    peer->close("Terminated by user action");
+}
index d7b2ceb..c4de8cc 100644 (file)
@@ -131,6 +131,8 @@ public slots:
 
     void changePassword(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword);
 
 
     void changePassword(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword);
 
+    void kickClient(int peerId);
+
     QHash<QString, QString> persistentChannels(NetworkId) const;
 
     /**
     QHash<QString, QString> persistentChannels(NetworkId) const;
 
     /**
index 8aa738c..030d1d0 100644 (file)
@@ -40,6 +40,23 @@ void CoreInfoDlg::coreInfoAvailable()
     ui.labelCoreVersion->setText(_coreInfo["quasselVersion"].toString());
     ui.labelCoreVersionDate->setText(_coreInfo["quasselBuildDate"].toString()); // "BuildDate" for compatibility
     ui.labelClientCount->setNum(_coreInfo["sessionConnectedClients"].toInt());
     ui.labelCoreVersion->setText(_coreInfo["quasselVersion"].toString());
     ui.labelCoreVersionDate->setText(_coreInfo["quasselBuildDate"].toString()); // "BuildDate" for compatibility
     ui.labelClientCount->setNum(_coreInfo["sessionConnectedClients"].toInt());
+
+    /*
+    qWarning() << _coreInfo["sessionConnectedClientData"];
+
+    int lastPeerId = -1;
+    QMap<QString, QVariant> lastPeerData;
+    for (const auto &peerData : _coreInfo["sessionConnectedClientData"].toList()) {
+        lastPeerData = peerData.toMap();
+        lastPeerId = lastPeerData["id"].toInt();
+    }
+
+    if (lastPeerId != -1) {
+        qWarning() << "Kicking client " << lastPeerId;
+        Client::kickClient(lastPeerId);
+    }
+    */
+
     updateUptime();
     startTimer(1000);
 }
     updateUptime();
     startTimer(1000);
 }