Skip to content
This repository was archived by the owner on Mar 4, 2023. It is now read-only.

Commit f19a40e

Browse files
committed
implemented reloading for qdsapp daemon
1 parent f4b881e commit f19a40e

File tree

9 files changed

+130
-56
lines changed

9 files changed

+130
-56
lines changed

src/datasync/datastoremodel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace QtDataSync {
1010

1111
class DataStoreModelPrivate;
1212
//! A passive item model for a datasync data store
13-
class Q_DATASYNC_EXPORT DataStoreModel : public QAbstractTableModel //TODO test if breaks binary compat
13+
class Q_DATASYNC_EXPORT DataStoreModel : public QAbstractTableModel
1414
{
1515
Q_OBJECT
1616
friend class DataStoreModelPrivate;

tools/appserver/clientconnector.cpp

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,40 @@
66
#include "datasyncservice.h"
77

88
ClientConnector::ClientConnector(DatabaseController *database, QObject *parent) :
9-
QObject(parent),
10-
database(database),
11-
server(nullptr),
12-
secret(),
13-
clients()
9+
QObject{parent},
10+
database{database}
1411
{
15-
auto name = qService->configuration()->value(QStringLiteral("server/name"), QCoreApplication::applicationName()).toString();
16-
auto mode = qService->configuration()->value(QStringLiteral("server/wss"), false).toBool() ? QWebSocketServer::SecureMode : QWebSocketServer::NonSecureMode;
12+
recreateServer();
13+
connect(database, &DatabaseController::notifyChanged,
14+
this, &ClientConnector::notifyChanged,
15+
Qt::QueuedConnection);
16+
}
17+
18+
void ClientConnector::recreateServer()
19+
{
20+
//stuff that always needs to be done
21+
emit disconnectAll();
1722
secret = qService->configuration()->value(QStringLiteral("server/secret")).toString();
1823

19-
server = new QWebSocketServer(name, mode, this);
24+
// stop here if activated
25+
if(isActivated) {
26+
qWarning() << "An activated service cannot restart the websocket server."
27+
<< "Reloading will continue with the running instance (changes to \"server/name\" and \"server/wss\" will be ignored";
28+
return;
29+
}
30+
31+
// (re)create the server
32+
if(server) {
33+
server->close();
34+
server->deleteLater();
35+
server = nullptr;
36+
}
37+
38+
server = new QWebSocketServer{
39+
qService->configuration()->value(QStringLiteral("server/name"), QCoreApplication::applicationName()).toString(),
40+
qService->configuration()->value(QStringLiteral("server/wss"), false).toBool() ? QWebSocketServer::SecureMode : QWebSocketServer::NonSecureMode,
41+
this
42+
};
2043
connect(server, &QWebSocketServer::newConnection,
2144
this, &ClientConnector::newConnection);
2245
connect(server, &QWebSocketServer::serverError,
@@ -27,10 +50,6 @@ ClientConnector::ClientConnector(DatabaseController *database, QObject *parent)
2750
connect(server, &QWebSocketServer::originAuthenticationRequired,
2851
this, &ClientConnector::verifySecret);
2952
}
30-
31-
connect(database, &DatabaseController::notifyChanged,
32-
this, &ClientConnector::notifyChanged,
33-
Qt::QueuedConnection);
3453
}
3554

3655
bool ClientConnector::setupWss()
@@ -61,7 +80,7 @@ bool ClientConnector::setupWss()
6180
&localCert,
6281
&caCerts,
6382
qService->configuration()->value(QStringLiteral("server/wss/pass")).toString().toUtf8())) {
64-
auto conf = server->sslConfiguration();
83+
auto conf = QSslConfiguration::defaultConfiguration();
6584
conf.setLocalCertificate(localCert);
6685
conf.setPrivateKey(privateKey);
6786
caCerts.append(conf.caCertificates());
@@ -80,6 +99,11 @@ bool ClientConnector::setupWss()
8099

81100
bool ClientConnector::listen()
82101
{
102+
if(isActivated) {
103+
qDebug() << "Still listening on port" << server->serverPort();
104+
return true;
105+
}
106+
83107
quint16 port = 0;
84108
auto dSocket = qService->getSocket();
85109
if(dSocket != -1) {
@@ -89,6 +113,8 @@ bool ClientConnector::listen()
89113
<< "with error:" << server->errorString();
90114
return false;
91115
}
116+
// mark as activated server
117+
isActivated = true;
92118
} else {
93119
QHostAddress host {
94120
qService->configuration()->value(QStringLiteral("server/host"),

tools/appserver/clientconnector.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class ClientConnector : public QObject
1313
public:
1414
explicit ClientConnector(DatabaseController *database, QObject *parent = nullptr);
1515

16+
void recreateServer();
1617
bool setupWss();
1718
bool listen();
1819
void close();
@@ -37,8 +38,9 @@ private Q_SLOTS:
3738

3839
private:
3940
DatabaseController *database;
40-
QWebSocketServer *server;
41+
QWebSocketServer *server = nullptr;
4142
QString secret;
43+
bool isActivated = false;
4244

4345
QHash<QUuid, Client*> clients;
4446
};

tools/appserver/databasecontroller.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ void DatabaseController::initialize()
4848
quota, force);
4949
}
5050

51+
void DatabaseController::reload()
52+
{
53+
auto quota = qService->configuration()->value(QStringLiteral("quota/limit"), 10485760).toULongLong(); //10MB
54+
auto force = qService->configuration()->value(QStringLiteral("quota/force"), false).toBool();
55+
QtConcurrent::run(qService->threadPool(), this, &DatabaseController::updateQuotaLimit,
56+
quota, force);
57+
}
58+
5159
void DatabaseController::cleanupDevices()
5260
{
5361
auto offlineSinceDays = qService->configuration()->value(QStringLiteral("cleanup/interval"),

tools/appserver/databasecontroller.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class DatabaseController : public QObject
4444
explicit DatabaseController(QObject *parent = nullptr);
4545

4646
void initialize();
47+
void reload();
4748

4849
void cleanupDevices();
4950

tools/appserver/datasyncservice.cpp

Lines changed: 74 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -64,45 +64,12 @@ QtService::Service::CommandMode DatasyncService::onStart()
6464
return Synchronous;
6565
}
6666

67-
//before anything else: read log level
68-
//NOTE move to service lib
69-
auto logLevel = _config->value(QStringLiteral("loglevel"),
70-
#ifndef QT_NO_DEBUG
71-
4
72-
#else
73-
3
74-
#endif
75-
).toInt();
76-
QString logStr;
77-
switch (logLevel) {
78-
case 0: //log nothing
79-
logStr.prepend(QStringLiteral("\n*.critical=false"));
80-
Q_FALLTHROUGH();
81-
case 1: //log critical
82-
logStr.prepend(QStringLiteral("\n*.warning=false"));
83-
Q_FALLTHROUGH();
84-
case 2: //log warn
85-
logStr.prepend(QStringLiteral("\n*.info=false"));
86-
Q_FALLTHROUGH();
87-
case 3: //log info
88-
logStr.prepend(QStringLiteral("*.debug=false"));
89-
QLoggingCategory::setFilterRules(logStr);
90-
break;
91-
case 4: //log any
92-
default:
93-
break;
94-
}
95-
67+
//before anything else: set the log level
68+
setLogLevel();
9669
qDebug() << "Using configuration:" << _config->fileName();
9770

9871
_mainPool = new QThreadPool(this);
99-
_mainPool->setMaxThreadCount(_config->value(QStringLiteral("threads/count"),
100-
QThread::idealThreadCount()).toInt());
101-
auto timeoutMin = _config->value(QStringLiteral("threads/expire"), 10).toInt(); //in minutes
102-
_mainPool->setExpiryTimeout(static_cast<int>(duration_cast<milliseconds>(minutes(timeoutMin)).count()));
103-
qDebug() << "Running with max" << _mainPool->maxThreadCount()
104-
<< "threads and an expiry timeout of" << timeoutMin
105-
<< "minutes";
72+
setupThreadPool();
10673

10774
_database = new DatabaseController(this);
10875
_connector = new ClientConnector(_database, this);
@@ -124,7 +91,7 @@ QtService::Service::CommandMode DatasyncService::onStart()
12491
QtService::Service::CommandMode DatasyncService::onStop(int &exitCode)
12592
{
12693
qDebug() << "Stopping server...";
127-
_connector->disconnectAll();
94+
emit _connector->disconnectAll();
12895
_mainPool->clear();
12996
_mainPool->waitForDone();
13097
exitCode = EXIT_SUCCESS;
@@ -134,8 +101,33 @@ QtService::Service::CommandMode DatasyncService::onStop(int &exitCode)
134101

135102
QtService::Service::CommandMode DatasyncService::onReload()
136103
{
137-
//TODO implement
138-
Q_UNIMPLEMENTED();
104+
// cast is ok here as I own the settings - they are only const to prevent accidental writes
105+
const_cast<QSettings*>(_config)->sync();
106+
if(_config->status() != QSettings::NoError) {
107+
qCritical() << "Failed reload configuration file"
108+
<< _config->fileName()
109+
<< "with error:"
110+
<< (_config->status() == QSettings::AccessError ? "Access denied" : "Invalid format");
111+
qCritical() << "Reload failed. Configuration has not been reloaded!";
112+
return Synchronous;
113+
}
114+
115+
// before anything else: set the log level
116+
setLogLevel();
117+
// adjust threadpool parameters
118+
setupThreadPool();
119+
120+
// update the database
121+
_database->reload();
122+
// recreate and connect the server
123+
_connector->recreateServer();
124+
if(!_connector->setupWss() ||
125+
!_connector->listen()) {
126+
qApp->exit(EXIT_FAILURE);
127+
return Synchronous;
128+
}
129+
130+
qDebug() << QCoreApplication::applicationName() << "completed reloading";
139131
return Synchronous;
140132
}
141133

@@ -219,6 +211,49 @@ void DatasyncService::command(int cmd)
219211
}
220212
}
221213

214+
void DatasyncService::setLogLevel()
215+
{
216+
auto logLevel = _config->value(QStringLiteral("loglevel"),
217+
#ifndef QT_NO_DEBUG
218+
4
219+
#else
220+
3
221+
#endif
222+
).toInt();
223+
QString logStr;
224+
switch (logLevel) {
225+
case 0: //log nothing
226+
logStr.prepend(QStringLiteral("\n*.critical=false"));
227+
Q_FALLTHROUGH();
228+
case 1: //log critical
229+
logStr.prepend(QStringLiteral("\n*.warning=false"));
230+
Q_FALLTHROUGH();
231+
case 2: //log warn
232+
logStr.prepend(QStringLiteral("\n*.info=false"));
233+
Q_FALLTHROUGH();
234+
case 3: //log info
235+
logStr.prepend(QStringLiteral("*.debug=false"));
236+
QLoggingCategory::setFilterRules(logStr);
237+
break;
238+
case 4: //log any
239+
QLoggingCategory::setFilterRules({});
240+
break;
241+
default:
242+
break;
243+
}
244+
}
245+
246+
void DatasyncService::setupThreadPool()
247+
{
248+
_mainPool->setMaxThreadCount(_config->value(QStringLiteral("threads/count"),
249+
QThread::idealThreadCount()).toInt());
250+
auto timeoutMin = _config->value(QStringLiteral("threads/expire"), 10).toInt(); //in minutes
251+
_mainPool->setExpiryTimeout(static_cast<int>(duration_cast<milliseconds>(minutes(timeoutMin)).count()));
252+
qDebug() << "Running with max" << _mainPool->maxThreadCount()
253+
<< "threads and an expiry timeout of" << timeoutMin
254+
<< "minutes";
255+
}
256+
222257
int main(int argc, char *argv[])
223258
{
224259
// check if version

tools/appserver/datasyncservice.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ private Q_SLOTS:
4646

4747
void sigusr1();
4848
void command(int cmd);
49+
void setLogLevel();
50+
void setupThreadPool();
4951
};
5052

5153
#undef qService

tools/appserver/qdsapp-install.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
@echo off
2-
sc create qdsapp binPath= "\"%{QT_INSTALL_BINS}\qdsappsvc.exe\" --backend windows" start= demand displayname= "QDSApp Service" || exit /B 1
2+
sc create qdsapp binPath= "\"%{QT_INSTALL_BINS}\qdsappsvc.exe\" --backend windows" start= auto displayname= "QDSApp Service" || exit /B 1
33
sc description qdsapp "QtDataSync AppServer Service" || exit /B 1

tools/appserver/qdsapp.service

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ After=network-online.target qdsapp.socket
77
Type=notify
88
NotifyAccess=exec
99
ExecStart=%{QT_INSTALL_BINS}/qdsappd -platform minimal --backend systemd
10-
#ExecReload=%{QT_INSTALL_BINS}/qdsappd -platform minimal --backend systemd reload $MAINPID
10+
ExecReload=%{QT_INSTALL_BINS}/qdsappd -platform minimal --backend systemd reload $MAINPID
1111
ExecStop=%{QT_INSTALL_BINS}/qdsappd -platform minimal --backend systemd stop $MAINPID
1212
WatchdogSec=10
1313
Restart=on-abnormal

0 commit comments

Comments
 (0)