src: Yearly copyright bump
[quassel.git] / src / core / sessionthread.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2020 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "sessionthread.h"
22
23 #include <QPointer>
24 #include <QTimer>
25
26 #include "core.h"
27 #include "coresession.h"
28 #include "internalpeer.h"
29 #include "remotepeer.h"
30 #include "signalproxy.h"
31
32 namespace {
33
34 class Worker : public QObject
35 {
36     Q_OBJECT
37
38 public:
39     Worker(UserId userId, bool restoreState, bool strictIdentEnabled)
40         : _userId{userId}
41         , _restoreState{restoreState}
42         , _strictIdentEnabled{strictIdentEnabled}
43     {}
44
45 public slots:
46     void initialize()
47     {
48         _session = new CoreSession{_userId, _restoreState, _strictIdentEnabled, this};
49         connect(_session, &QObject::destroyed, QThread::currentThread(), &QThread::quit);
50         connect(_session, &CoreSession::sessionStateReceived, Core::instance(), &Core::sessionStateReceived);
51         emit initialized();
52     }
53
54     void shutdown()
55     {
56         if (_session) {
57             _session->shutdown();
58         }
59     }
60
61     void addClient(Peer* peer)
62     {
63         if (!_session) {
64             qWarning() << "Session not initialized!";
65             return;
66         }
67
68         auto remotePeer = qobject_cast<RemotePeer*>(peer);
69         if (remotePeer) {
70             _session->addClient(remotePeer);
71             return;
72         }
73         auto internalPeer = qobject_cast<InternalPeer*>(peer);
74         if (internalPeer) {
75             _session->addClient(internalPeer);
76             return;
77         }
78
79         qWarning() << "SessionThread::addClient() received invalid peer!" << peer;
80     }
81
82 signals:
83     void initialized();
84
85 private:
86     UserId _userId;
87     bool _restoreState;
88     bool _strictIdentEnabled;  ///< Whether or not strict ident mode is enabled, locking users' idents to Quassel username
89     QPointer<CoreSession> _session;
90 };
91
92 }  // namespace
93
94 SessionThread::SessionThread(UserId uid, bool restoreState, bool strictIdentEnabled, QObject* parent)
95     : QObject(parent)
96 {
97     auto worker = new Worker(uid, restoreState, strictIdentEnabled);
98     worker->moveToThread(&_sessionThread);
99     connect(&_sessionThread, &QThread::started, worker, &Worker::initialize);
100     connect(&_sessionThread, &QThread::finished, worker, &QObject::deleteLater);
101     connect(worker, &Worker::initialized, this, &SessionThread::onSessionInitialized);
102     connect(worker, &QObject::destroyed, this, &SessionThread::onSessionDestroyed);
103
104     connect(this, &SessionThread::addClientToWorker, worker, &Worker::addClient);
105     connect(this, &SessionThread::shutdownSession, worker, &Worker::shutdown);
106
107     // Defer thread start through the event loop, so the SessionThread instance is fully constructed before
108     QTimer::singleShot(0, &_sessionThread, SLOT(start()));
109 }
110
111 SessionThread::~SessionThread()
112 {
113     // shut down thread gracefully
114     _sessionThread.quit();
115     _sessionThread.wait(30000);
116 }
117
118 void SessionThread::shutdown()
119 {
120     emit shutdownSession();
121 }
122
123 void SessionThread::onSessionInitialized()
124 {
125     _sessionInitialized = true;
126     for (auto&& peer : _clientQueue) {
127         peer->setParent(nullptr);
128         peer->moveToThread(&_sessionThread);
129         emit addClientToWorker(peer);
130     }
131     _clientQueue.clear();
132 }
133
134 void SessionThread::onSessionDestroyed()
135 {
136     emit shutdownComplete(this);
137 }
138
139 void SessionThread::addClient(Peer* peer)
140 {
141     if (_sessionInitialized) {
142         peer->setParent(nullptr);
143         peer->moveToThread(&_sessionThread);
144         emit addClientToWorker(peer);
145     }
146     else {
147         _clientQueue.push_back(peer);
148     }
149 }
150
151 #include "sessionthread.moc"