qa: Replace deprecated qVariantFromValue() by QVariant::fromValue()
[quassel.git] / src / core / sessionthread.cpp
index c29d1ff..d8e8c4d 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-09 by the Quassel Project                          *
+ *   Copyright (C) 2005-2019 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   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.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#include <QMutexLocker>
-
 #include "sessionthread.h"
-#include "signalproxy.h"
-#include "coresession.h"
-#include "core.h"
 
-SessionThread::SessionThread(UserId uid, bool restoreState, QObject *parent)
-  : QThread(parent),
-    _session(0),
-    _user(uid),
-    _sessionInitialized(false),
-    _restoreState(restoreState)
-{
-  connect(this, SIGNAL(initialized()), this, SLOT(setSessionInitialized()));
-}
+#include <QPointer>
+#include <QTimer>
 
-SessionThread::~SessionThread() {
-  if(_session) {
-    _session->setParent(0);
-    _session->moveToThread(thread());
-    _session->deleteLater();
-    _session = 0;
-  }
-}
-
-CoreSession *SessionThread::session() {
-  return _session;
-}
-
-UserId SessionThread::user() {
-  return _user;
-}
+#include "core.h"
+#include "coresession.h"
+#include "internalpeer.h"
+#include "remotepeer.h"
+#include "signalproxy.h"
 
-bool SessionThread::isSessionInitialized() {
-  return _sessionInitialized;
-}
+namespace {
 
-void SessionThread::setSessionInitialized() {
-  _sessionInitialized = true;
-  foreach(QObject *peer, clientQueue) {
-    addClientToSession(peer);
-  }
-  clientQueue.clear();
+class Worker : public QObject
+{
+    Q_OBJECT
+
+public:
+    Worker(UserId userId, bool restoreState, bool strictIdentEnabled)
+        : _userId{userId}
+        , _restoreState{restoreState}
+        , _strictIdentEnabled{strictIdentEnabled}
+    {}
+
+public slots:
+    void initialize()
+    {
+        _session = new CoreSession{_userId, _restoreState, _strictIdentEnabled, this};
+        connect(_session, &QObject::destroyed, QThread::currentThread(), &QThread::quit);
+        connect(_session, &CoreSession::sessionStateReceived, Core::instance(), &Core::sessionStateReceived);
+        emit initialized();
+    }
+
+    void shutdown()
+    {
+        if (_session) {
+            _session->shutdown();
+        }
+    }
+
+    void addClient(Peer* peer)
+    {
+        if (!_session) {
+            qWarning() << "Session not initialized!";
+            return;
+        }
+
+        auto remotePeer = qobject_cast<RemotePeer*>(peer);
+        if (remotePeer) {
+            _session->addClient(remotePeer);
+            return;
+        }
+        auto internalPeer = qobject_cast<InternalPeer*>(peer);
+        if (internalPeer) {
+            _session->addClient(internalPeer);
+            return;
+        }
+
+        qWarning() << "SessionThread::addClient() received invalid peer!" << peer;
+    }
+
+signals:
+    void initialized();
+
+private:
+    UserId _userId;
+    bool _restoreState;
+    bool _strictIdentEnabled;  ///< Whether or not strict ident mode is enabled, locking users' idents to Quassel username
+    QPointer<CoreSession> _session;
+};
+
+}  // namespace
+
+SessionThread::SessionThread(UserId uid, bool restoreState, bool strictIdentEnabled, QObject* parent)
+    : QObject(parent)
+{
+    auto worker = new Worker(uid, restoreState, strictIdentEnabled);
+    worker->moveToThread(&_sessionThread);
+    connect(&_sessionThread, &QThread::started, worker, &Worker::initialize);
+    connect(&_sessionThread, &QThread::finished, worker, &QObject::deleteLater);
+    connect(worker, &Worker::initialized, this, &SessionThread::onSessionInitialized);
+    connect(worker, &QObject::destroyed, this, &SessionThread::onSessionDestroyed);
+
+    connect(this, &SessionThread::addClientToWorker, worker, &Worker::addClient);
+    connect(this, &SessionThread::shutdownSession, worker, &Worker::shutdown);
+
+    // Defer thread start through the event loop, so the SessionThread instance is fully constructed before
+    QTimer::singleShot(0, &_sessionThread, SLOT(start()));
 }
 
-void SessionThread::addClient(QObject *peer) {
-  if(isSessionInitialized()) {
-    addClientToSession(peer);
-  } else {
-    clientQueue.append(peer);
-  }
+SessionThread::~SessionThread()
+{
+    // shut down thread gracefully
+    _sessionThread.quit();
+    _sessionThread.wait(30000);
 }
 
-void SessionThread::addClientToSession(QObject *peer) {
-  QIODevice *socket = qobject_cast<QIODevice *>(peer);
-  if(socket) {
-    addRemoteClientToSession(socket);
-    return;
-  }
-
-  SignalProxy *proxy = qobject_cast<SignalProxy *>(peer);
-  if(proxy) {
-    addInternalClientToSession(proxy);
-    return;
-  }
-
-  qWarning() << "SessionThread::addClient() received neither QIODevice nor SignalProxy as peer!" << peer;
+void SessionThread::shutdown()
+{
+    emit shutdownSession();
 }
 
-void SessionThread::addRemoteClientToSession(QIODevice *socket) {
-  socket->setParent(0);
-  socket->moveToThread(session()->thread());
-  emit addRemoteClient(socket);
+void SessionThread::onSessionInitialized()
+{
+    _sessionInitialized = true;
+    for (auto&& peer : _clientQueue) {
+        peer->setParent(nullptr);
+        peer->moveToThread(&_sessionThread);
+        emit addClientToWorker(peer);
+    }
+    _clientQueue.clear();
 }
 
-void SessionThread::addInternalClientToSession(SignalProxy *proxy) {
-  emit addInternalClient(proxy);
+void SessionThread::onSessionDestroyed()
+{
+    emit shutdownComplete(this);
 }
 
-void SessionThread::run() {
-  _session = new CoreSession(user(), _restoreState);
-  connect(this, SIGNAL(addRemoteClient(QIODevice *)), _session, SLOT(addClient(QIODevice *)));
-  connect(this, SIGNAL(addInternalClient(SignalProxy *)), _session, SLOT(addClient(SignalProxy *)));
-  connect(_session, SIGNAL(sessionState(const QVariant &)), Core::instance(), SIGNAL(sessionState(const QVariant &)));
-  emit initialized();
-  exec();
-  delete _session;
-  _session = 0;
+void SessionThread::addClient(Peer* peer)
+{
+    if (_sessionInitialized) {
+        peer->setParent(nullptr);
+        peer->moveToThread(&_sessionThread);
+        emit addClientToWorker(peer);
+    }
+    else {
+        _clientQueue.push_back(peer);
+    }
 }
 
-void SessionThread::stopSession() {
-  if(_session) {
-    connect(_session, SIGNAL(destroyed()), this, SLOT(quit()));
-    _session->deleteLater();
-    _session = 0;
-  }
-}
+#include "sessionthread.moc"