mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-10 03:53:26 -08:00
[Server] Create the worker database interfaces through the factory (#7860)
This commit is contained in:
parent
0caacb27c1
commit
c4ac80e282
5 changed files with 62 additions and 29 deletions
|
|
@ -833,6 +833,15 @@ public:
|
||||||
virtual void purgeExpiredLegacyBackups()
|
virtual void purgeExpiredLegacyBackups()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
/** @brief Creates the database interface a worker connection pool runs on; nullptr when unsupported. */
|
||||||
|
virtual Server_DatabaseInterface *createWorkerInterface(int /* instanceId */)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
/** @brief Opens a worker interface's connection on its own thread; a no-op when unsupported. */
|
||||||
|
virtual void initialiseWorkerDatabase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual void clearSessionTables()
|
virtual void clearSessionTables()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QSqlDatabase>
|
|
||||||
#include <QSsl>
|
#include <QSsl>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
@ -83,12 +82,16 @@ static constexpr qint64 kLegacyBackupSweepIntervalMs = 6 * 60 * 60 * 1000;
|
||||||
|
|
||||||
Servatrice_GameServer::Servatrice_GameServer(Servatrice *_server,
|
Servatrice_GameServer::Servatrice_GameServer(Servatrice *_server,
|
||||||
int _numberPools,
|
int _numberPools,
|
||||||
const QSqlDatabase &_sqlDatabase,
|
Server_DatabaseInterface *_databaseInterface,
|
||||||
QObject *parent)
|
QObject *parent)
|
||||||
: QTcpServer(parent), server(_server)
|
: QTcpServer(parent), server(_server)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _numberPools; ++i) {
|
for (int i = 0; i < _numberPools; ++i) {
|
||||||
auto newDatabaseInterface = new Servatrice_DatabaseInterface(i, server);
|
auto *newDatabaseInterface = _databaseInterface->createWorkerInterface(i);
|
||||||
|
if (!newDatabaseInterface) {
|
||||||
|
qCCritical(ServatriceLog) << "Cannot create the database interface for pool" << i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
auto newPool = new Servatrice_ConnectionPool(newDatabaseInterface);
|
auto newPool = new Servatrice_ConnectionPool(newDatabaseInterface);
|
||||||
|
|
||||||
auto newThread = new QThread;
|
auto newThread = new QThread;
|
||||||
|
|
@ -100,8 +103,7 @@ Servatrice_GameServer::Servatrice_GameServer(Servatrice *_server,
|
||||||
newThread->start();
|
newThread->start();
|
||||||
server->watchWorkerThread(newThread);
|
server->watchWorkerThread(newThread);
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
newDatabaseInterface,
|
newDatabaseInterface, [newDatabaseInterface] { newDatabaseInterface->initialiseWorkerDatabase(); },
|
||||||
[newDatabaseInterface, _sqlDatabase] { newDatabaseInterface->initDatabase(_sqlDatabase); },
|
|
||||||
Qt::BlockingQueuedConnection);
|
Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
connectionPools.append(newPool);
|
connectionPools.append(newPool);
|
||||||
|
|
@ -122,6 +124,10 @@ Servatrice_GameServer::~Servatrice_GameServer()
|
||||||
void Servatrice_GameServer::incomingConnection(qintptr socketDescriptor)
|
void Servatrice_GameServer::incomingConnection(qintptr socketDescriptor)
|
||||||
{
|
{
|
||||||
Servatrice_ConnectionPool *pool = findLeastUsedConnectionPool();
|
Servatrice_ConnectionPool *pool = findLeastUsedConnectionPool();
|
||||||
|
if (!pool) {
|
||||||
|
qCCritical(ServatriceLog) << "No database pool available; refusing connection";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto ssi = new TcpServerSocketInterface(server, pool->getDatabaseInterface());
|
auto ssi = new TcpServerSocketInterface(server, pool->getDatabaseInterface());
|
||||||
ssi->moveToThread(pool->thread());
|
ssi->moveToThread(pool->thread());
|
||||||
|
|
@ -134,6 +140,10 @@ void Servatrice_GameServer::incomingConnection(qintptr socketDescriptor)
|
||||||
|
|
||||||
Servatrice_ConnectionPool *Servatrice_GameServer::findLeastUsedConnectionPool()
|
Servatrice_ConnectionPool *Servatrice_GameServer::findLeastUsedConnectionPool()
|
||||||
{
|
{
|
||||||
|
if (connectionPools.isEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
int minClientCount = -1;
|
int minClientCount = -1;
|
||||||
int poolIndex = -1;
|
int poolIndex = -1;
|
||||||
QStringList debugStr;
|
QStringList debugStr;
|
||||||
|
|
@ -153,13 +163,17 @@ Servatrice_ConnectionPool *Servatrice_GameServer::findLeastUsedConnectionPool()
|
||||||
|
|
||||||
Servatrice_WebsocketGameServer::Servatrice_WebsocketGameServer(Servatrice *_server,
|
Servatrice_WebsocketGameServer::Servatrice_WebsocketGameServer(Servatrice *_server,
|
||||||
int _numberPools,
|
int _numberPools,
|
||||||
const QSqlDatabase &_sqlDatabase,
|
Server_DatabaseInterface *_databaseInterface,
|
||||||
QObject *parent)
|
QObject *parent)
|
||||||
: QWebSocketServer("Servatrice", QWebSocketServer::NonSecureMode, parent), server(_server)
|
: QWebSocketServer("Servatrice", QWebSocketServer::NonSecureMode, parent), server(_server)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _numberPools; ++i) {
|
for (int i = 0; i < _numberPools; ++i) {
|
||||||
int poolNumber = WEBSOCKET_POOL_NUMBER + i;
|
int poolNumber = WEBSOCKET_POOL_NUMBER + i;
|
||||||
auto newDatabaseInterface = new Servatrice_DatabaseInterface(poolNumber, server);
|
auto *newDatabaseInterface = _databaseInterface->createWorkerInterface(poolNumber);
|
||||||
|
if (!newDatabaseInterface) {
|
||||||
|
qCCritical(ServatriceLog) << "Cannot create the database interface for pool" << poolNumber;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
auto newPool = new Servatrice_ConnectionPool(newDatabaseInterface);
|
auto newPool = new Servatrice_ConnectionPool(newDatabaseInterface);
|
||||||
|
|
||||||
auto newThread = new QThread;
|
auto newThread = new QThread;
|
||||||
|
|
@ -171,8 +185,7 @@ Servatrice_WebsocketGameServer::Servatrice_WebsocketGameServer(Servatrice *_serv
|
||||||
newThread->start();
|
newThread->start();
|
||||||
server->watchWorkerThread(newThread);
|
server->watchWorkerThread(newThread);
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
newDatabaseInterface,
|
newDatabaseInterface, [newDatabaseInterface] { newDatabaseInterface->initialiseWorkerDatabase(); },
|
||||||
[newDatabaseInterface, _sqlDatabase] { newDatabaseInterface->initDatabase(_sqlDatabase); },
|
|
||||||
Qt::BlockingQueuedConnection);
|
Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
connectionPools.append(newPool);
|
connectionPools.append(newPool);
|
||||||
|
|
@ -195,6 +208,10 @@ Servatrice_WebsocketGameServer::~Servatrice_WebsocketGameServer()
|
||||||
void Servatrice_WebsocketGameServer::onNewConnection()
|
void Servatrice_WebsocketGameServer::onNewConnection()
|
||||||
{
|
{
|
||||||
Servatrice_ConnectionPool *pool = findLeastUsedConnectionPool();
|
Servatrice_ConnectionPool *pool = findLeastUsedConnectionPool();
|
||||||
|
if (!pool) {
|
||||||
|
qCCritical(ServatriceLog) << "No database pool available; refusing connection";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto ssi = new WebsocketServerSocketInterface(server, pool->getDatabaseInterface());
|
auto ssi = new WebsocketServerSocketInterface(server, pool->getDatabaseInterface());
|
||||||
/*
|
/*
|
||||||
|
|
@ -211,6 +228,10 @@ void Servatrice_WebsocketGameServer::onNewConnection()
|
||||||
|
|
||||||
Servatrice_ConnectionPool *Servatrice_WebsocketGameServer::findLeastUsedConnectionPool()
|
Servatrice_ConnectionPool *Servatrice_WebsocketGameServer::findLeastUsedConnectionPool()
|
||||||
{
|
{
|
||||||
|
if (connectionPools.isEmpty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
int minClientCount = -1;
|
int minClientCount = -1;
|
||||||
int poolIndex = -1;
|
int poolIndex = -1;
|
||||||
QStringList debugStr;
|
QStringList debugStr;
|
||||||
|
|
@ -243,7 +264,6 @@ Servatrice::Servatrice(QObject *parent)
|
||||||
: Server(parent), authenticationMethod(AuthenticationNone), uptime(0), txBytes(0), rxBytes(0),
|
: Server(parent), authenticationMethod(AuthenticationNone), uptime(0), txBytes(0), rxBytes(0),
|
||||||
shutdownTimer(nullptr)
|
shutdownTimer(nullptr)
|
||||||
{
|
{
|
||||||
qRegisterMetaType<QSqlDatabase>("QSqlDatabase");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Servatrice::~Servatrice()
|
Servatrice::~Servatrice()
|
||||||
|
|
@ -618,8 +638,7 @@ bool Servatrice::initServer()
|
||||||
|
|
||||||
// SOCKET SERVER
|
// SOCKET SERVER
|
||||||
if (getNumberOfTCPPools() > 0) {
|
if (getNumberOfTCPPools() > 0) {
|
||||||
gameServer =
|
gameServer = new Servatrice_GameServer(this, getNumberOfTCPPools(), servatriceDatabaseInterface, this);
|
||||||
new Servatrice_GameServer(this, getNumberOfTCPPools(), servatriceDatabaseInterface->getDatabase(), this);
|
|
||||||
gameServer->setMaxPendingConnections(1000);
|
gameServer->setMaxPendingConnections(1000);
|
||||||
QHostAddress tcpHost = getServerTCPHost();
|
QHostAddress tcpHost = getServerTCPHost();
|
||||||
qDebug() << "Starting server on host" << tcpHost.toString() << "port" << getServerTCPPort();
|
qDebug() << "Starting server on host" << tcpHost.toString() << "port" << getServerTCPPort();
|
||||||
|
|
@ -633,8 +652,8 @@ bool Servatrice::initServer()
|
||||||
|
|
||||||
// WEBSOCKET SERVER
|
// WEBSOCKET SERVER
|
||||||
if (getNumberOfWebSocketPools() > 0) {
|
if (getNumberOfWebSocketPools() > 0) {
|
||||||
websocketGameServer = new Servatrice_WebsocketGameServer(this, getNumberOfWebSocketPools(),
|
websocketGameServer =
|
||||||
servatriceDatabaseInterface->getDatabase(), this);
|
new Servatrice_WebsocketGameServer(this, getNumberOfWebSocketPools(), servatriceDatabaseInterface, this);
|
||||||
websocketGameServer->setMaxPendingConnections(1000);
|
websocketGameServer->setMaxPendingConnections(1000);
|
||||||
QHostAddress webSocketHost = getServerWebSocketHost();
|
QHostAddress webSocketHost = getServerWebSocketHost();
|
||||||
qDebug() << "Starting websocket server on host" << webSocketHost.toString() << "port"
|
qDebug() << "Starting websocket server on host" << webSocketHost.toString() << "port"
|
||||||
|
|
@ -708,7 +727,7 @@ qint64 Servatrice::getCardsInGamesTotal() const
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Servatrice::addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface)
|
void Servatrice::addDatabaseInterface(QThread *thread, Server_DatabaseInterface *databaseInterface)
|
||||||
{
|
{
|
||||||
databaseInterfaces.insert(thread, databaseInterface);
|
databaseInterfaces.insert(thread, databaseInterface);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,6 @@
|
||||||
#include <QSslCertificate>
|
#include <QSslCertificate>
|
||||||
#include <QSslKey>
|
#include <QSslKey>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
// IWYU pragma: keep
|
|
||||||
// Q_DECLARE_METATYPE below needs the complete type.
|
|
||||||
#include <QSqlDatabase>
|
|
||||||
#include <QTcpServer>
|
#include <QTcpServer>
|
||||||
#include <QWebSocketServer>
|
#include <QWebSocketServer>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
@ -54,8 +50,6 @@ class QObject;
|
||||||
class QThread;
|
class QThread;
|
||||||
class SessionEvent;
|
class SessionEvent;
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QSqlDatabase)
|
|
||||||
|
|
||||||
class QTimer;
|
class QTimer;
|
||||||
class Servatrice;
|
class Servatrice;
|
||||||
class Servatrice_ConnectionPool;
|
class Servatrice_ConnectionPool;
|
||||||
|
|
@ -73,7 +67,7 @@ private:
|
||||||
public:
|
public:
|
||||||
Servatrice_GameServer(Servatrice *_server,
|
Servatrice_GameServer(Servatrice *_server,
|
||||||
int _numberPools,
|
int _numberPools,
|
||||||
const QSqlDatabase &_sqlDatabase,
|
Server_DatabaseInterface *_databaseInterface,
|
||||||
QObject *parent = nullptr);
|
QObject *parent = nullptr);
|
||||||
~Servatrice_GameServer() override;
|
~Servatrice_GameServer() override;
|
||||||
|
|
||||||
|
|
@ -92,7 +86,7 @@ private:
|
||||||
public:
|
public:
|
||||||
Servatrice_WebsocketGameServer(Servatrice *_server,
|
Servatrice_WebsocketGameServer(Servatrice *_server,
|
||||||
int _numberPools,
|
int _numberPools,
|
||||||
const QSqlDatabase &_sqlDatabase,
|
Server_DatabaseInterface *_databaseInterface,
|
||||||
QObject *parent = nullptr);
|
QObject *parent = nullptr);
|
||||||
~Servatrice_WebsocketGameServer() override;
|
~Servatrice_WebsocketGameServer() override;
|
||||||
|
|
||||||
|
|
@ -190,7 +184,7 @@ private:
|
||||||
QString dbPrefix;
|
QString dbPrefix;
|
||||||
QMap<QString, bool> serverRequiredFeatureList;
|
QMap<QString, bool> serverRequiredFeatureList;
|
||||||
QString officialWarnings;
|
QString officialWarnings;
|
||||||
Servatrice_DatabaseInterface *servatriceDatabaseInterface;
|
Server_DatabaseInterface *servatriceDatabaseInterface;
|
||||||
bool cleanupDatabaseForEmail(const QString &userName, EmailType type, const QString &token, qint64 rowId);
|
bool cleanupDatabaseForEmail(const QString &userName, EmailType type, const QString &token, qint64 rowId);
|
||||||
int serverId;
|
int serverId;
|
||||||
int uptime;
|
int uptime;
|
||||||
|
|
@ -339,7 +333,7 @@ public:
|
||||||
QList<AbstractServerSocketInterface *> getUsersWithAddressAsList(const QHostAddress &address) const;
|
QList<AbstractServerSocketInterface *> getUsersWithAddressAsList(const QHostAddress &address) const;
|
||||||
void incTxBytes(quint64 num);
|
void incTxBytes(quint64 num);
|
||||||
void incRxBytes(quint64 num);
|
void incRxBytes(quint64 num);
|
||||||
void addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface);
|
void addDatabaseInterface(QThread *thread, Server_DatabaseInterface *databaseInterface);
|
||||||
|
|
||||||
// Metrics (see [metrics] section in servatrice.ini.example)
|
// Metrics (see [metrics] section in servatrice.ini.example)
|
||||||
MetricsRegistry &getMetricsRegistry()
|
MetricsRegistry &getMetricsRegistry()
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,18 @@ void Servatrice_DatabaseInterface::initDatabase(const QSqlDatabase &_sqlDatabase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Server_DatabaseInterface *Servatrice_DatabaseInterface::createWorkerInterface(int instanceId)
|
||||||
|
{
|
||||||
|
auto *worker = new Servatrice_DatabaseInterface(instanceId, server);
|
||||||
|
worker->inheritedDatabase = sqlDatabase;
|
||||||
|
return worker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Servatrice_DatabaseInterface::initialiseWorkerDatabase()
|
||||||
|
{
|
||||||
|
initDatabase(inheritedDatabase);
|
||||||
|
}
|
||||||
|
|
||||||
bool Servatrice_DatabaseInterface::openDatabase(const QString &type,
|
bool Servatrice_DatabaseInterface::openDatabase(const QString &type,
|
||||||
const QString &hostName,
|
const QString &hostName,
|
||||||
const QString &databaseName,
|
const QString &databaseName,
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ class Servatrice_DatabaseInterface : public Server_DatabaseInterface
|
||||||
private:
|
private:
|
||||||
int instanceId;
|
int instanceId;
|
||||||
QSqlDatabase sqlDatabase;
|
QSqlDatabase sqlDatabase;
|
||||||
|
QSqlDatabase inheritedDatabase;
|
||||||
QHash<QString, QSqlQuery *> preparedStatements;
|
QHash<QString, QSqlQuery *> preparedStatements;
|
||||||
Servatrice *server;
|
Servatrice *server;
|
||||||
ServerInfo_User evalUserQueryResult(const QSqlQuery *query, bool complete, bool withId = false);
|
ServerInfo_User evalUserQueryResult(const QSqlQuery *query, bool complete, bool withId = false);
|
||||||
|
|
@ -72,13 +73,11 @@ public:
|
||||||
const QString &userName,
|
const QString &userName,
|
||||||
const QString &password) override;
|
const QString &password) override;
|
||||||
bool openDatabase();
|
bool openDatabase();
|
||||||
|
Server_DatabaseInterface *createWorkerInterface(int instanceId) override;
|
||||||
|
void initialiseWorkerDatabase() override;
|
||||||
bool checkSql() override;
|
bool checkSql() override;
|
||||||
QSqlQuery *prepareQuery(const QString &queryText);
|
QSqlQuery *prepareQuery(const QString &queryText);
|
||||||
bool execSqlQuery(QSqlQuery *query);
|
bool execSqlQuery(QSqlQuery *query);
|
||||||
const QSqlDatabase &getDatabase()
|
|
||||||
{
|
|
||||||
return sqlDatabase;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool activeUserExists(const QString &user) override;
|
bool activeUserExists(const QString &user) override;
|
||||||
bool userExists(const QString &user) override;
|
bool userExists(const QString &user) override;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue