diff --git a/cockatrice/src/localserver.cpp b/cockatrice/src/localserver.cpp index c4d67227..e8722fb3 100644 --- a/cockatrice/src/localserver.cpp +++ b/cockatrice/src/localserver.cpp @@ -5,6 +5,7 @@ LocalServer::LocalServer(QObject *parent) : Server(parent) { + setDatabaseInterface(new LocalServer_DatabaseInterface(this)); addRoom(new Server_Room(0, QString(), QString(), false, QString(), QStringList(), this)); } @@ -15,14 +16,26 @@ LocalServer::~LocalServer() LocalServerInterface *LocalServer::newConnection() { - LocalServerInterface *lsi = new LocalServerInterface(this); + LocalServerInterface *lsi = new LocalServerInterface(this, getDatabaseInterface()); addClient(lsi); return lsi; } -ServerInfo_User LocalServer::getUserData(const QString &name, bool /*withId*/) +LocalServer_DatabaseInterface::LocalServer_DatabaseInterface(LocalServer *_localServer) + : Server_DatabaseInterface(_localServer), + nextGameId(0), + nextReplayId(0) +{ +} + +ServerInfo_User LocalServer_DatabaseInterface::getUserData(const QString &name, bool /*withId*/) { ServerInfo_User result; result.set_name(name.toStdString()); return result; } + +AuthenticationResult LocalServer_DatabaseInterface::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) +{ + return UnknownUser; +} diff --git a/cockatrice/src/localserver.h b/cockatrice/src/localserver.h index c4fa3d65..ac6a8475 100644 --- a/cockatrice/src/localserver.h +++ b/cockatrice/src/localserver.h @@ -2,6 +2,7 @@ #define LOCALSERVER_H #include "server.h" +#include "server_database_interface.h" class LocalServerInterface; @@ -13,8 +14,20 @@ public: ~LocalServer(); LocalServerInterface *newConnection(); +}; + +class LocalServer_DatabaseInterface : public Server_DatabaseInterface { + Q_OBJECT +private: + LocalServer *localServer; + int nextGameId, nextReplayId; protected: ServerInfo_User getUserData(const QString &name, bool withId = false); +public: + LocalServer_DatabaseInterface(LocalServer *_localServer); + AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft); + int getNextGameId() { return ++nextGameId; } + int getNextReplayId() { return ++nextReplayId; } }; #endif \ No newline at end of file diff --git a/cockatrice/src/localserverinterface.cpp b/cockatrice/src/localserverinterface.cpp index 5495fa09..ebf873b8 100644 --- a/cockatrice/src/localserverinterface.cpp +++ b/cockatrice/src/localserverinterface.cpp @@ -2,8 +2,8 @@ #include "localserver.h" #include -LocalServerInterface::LocalServerInterface(LocalServer *_server) - : Server_ProtocolHandler(_server, _server) +LocalServerInterface::LocalServerInterface(LocalServer *_server, Server_DatabaseInterface *_databaseInterface) + : Server_ProtocolHandler(_server, _databaseInterface, _server) { } diff --git a/cockatrice/src/localserverinterface.h b/cockatrice/src/localserverinterface.h index 90e86754..0b4eb227 100644 --- a/cockatrice/src/localserverinterface.h +++ b/cockatrice/src/localserverinterface.h @@ -9,7 +9,7 @@ class LocalServerInterface : public Server_ProtocolHandler { Q_OBJECT public: - LocalServerInterface(LocalServer *_server); + LocalServerInterface(LocalServer *_server, Server_DatabaseInterface *_databaseInterface); ~LocalServerInterface(); QString getAddress() const { return QString(); } diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 83f185e1..51ce1650 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -13,7 +13,6 @@ SET(common_SOURCES server_card.cpp server_cardzone.cpp server_counter.cpp - server_database_interface.cpp server_game.cpp server_player.cpp server_protocolhandler.cpp diff --git a/common/server.cpp b/common/server.cpp index a318e24d..9ecf196f 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -32,10 +32,11 @@ #include "pb/session_event.pb.h" #include "pb/isl_message.pb.h" #include +#include #include Server::Server(QObject *parent) - : QObject(parent), databaseInterface(0), clientsLock(QReadWriteLock::Recursive) + : QObject(parent), clientsLock(QReadWriteLock::Recursive) { qRegisterMetaType("ServerInfo_Game"); qRegisterMetaType("ServerInfo_Room"); @@ -70,31 +71,38 @@ void Server::prepareDestroy() void Server::setDatabaseInterface(Server_DatabaseInterface *_databaseInterface) { - databaseInterface = _databaseInterface; - connect(this, SIGNAL(endSession(qint64)), databaseInterface, SLOT(endSession(qint64))); + connect(this, SIGNAL(endSession(qint64)), _databaseInterface, SLOT(endSession(qint64))); + databaseInterfaces.insert(QThread::currentThread(), _databaseInterface); } -AuthenticationResult Server::loginUser(Server_DatabaseInterface *sessionDatabaseInterface, Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft) +Server_DatabaseInterface *Server::getDatabaseInterface() const +{ + return databaseInterfaces.value(QThread::currentThread()); +} + +AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft) { if (name.size() > 35) name = name.left(35); + Server_DatabaseInterface *databaseInterface = getDatabaseInterface(); + QWriteLocker locker(&clientsLock); - AuthenticationResult authState = sessionDatabaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft); + AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft); if ((authState == NotLoggedIn) || (authState == UserIsBanned)) return authState; - ServerInfo_User data = sessionDatabaseInterface->getUserData(name, true); + ServerInfo_User data = databaseInterface->getUserData(name, true); data.set_address(session->getAddress().toStdString()); name = QString::fromStdString(data.name()); // Compensate for case indifference - sessionDatabaseInterface->lockSessionTables(); + databaseInterface->lockSessionTables(); if (authState == PasswordRight) { - if (users.contains(name) || sessionDatabaseInterface->userSessionExists(name)) { + if (users.contains(name) || databaseInterface->userSessionExists(name)) { qDebug("Login denied: would overwrite old session"); - sessionDatabaseInterface->unlockSessionTables(); + databaseInterface->unlockSessionTables(); return WouldOverwriteOldSession; } } else if (authState == UnknownUser) { @@ -102,7 +110,7 @@ AuthenticationResult Server::loginUser(Server_DatabaseInterface *sessionDatabase // don't interfere with registered user names though. QString tempName = name; int i = 0; - while (users.contains(tempName) || sessionDatabaseInterface->userExists(tempName) || sessionDatabaseInterface->userSessionExists(tempName)) + while (users.contains(tempName) || databaseInterface->userExists(tempName) || databaseInterface->userSessionExists(tempName)) tempName = name + "_" + QString::number(++i); name = tempName; data.set_name(name.toStdString()); @@ -111,8 +119,8 @@ AuthenticationResult Server::loginUser(Server_DatabaseInterface *sessionDatabase users.insert(name, session); qDebug() << "Server::loginUser: name=" << name; - data.set_session_id(sessionDatabaseInterface->startSession(name, session->getAddress())); - sessionDatabaseInterface->unlockSessionTables(); + data.set_session_id(databaseInterface->startSession(name, session->getAddress())); + databaseInterface->unlockSessionTables(); usersBySessionId.insert(data.session_id(), session); @@ -332,7 +340,7 @@ void Server::externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cm } ResponseContainer responseContainer(cmdId); - Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface, databaseInterface); + Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface); userInterface->sendResponseContainer(responseContainer, responseCode); } catch (Response::ResponseCode code) { Response response; diff --git a/common/server.h b/common/server.h index 92440561..ac7bb6d6 100644 --- a/common/server.h +++ b/common/server.h @@ -43,7 +43,7 @@ public: mutable QReadWriteLock clientsLock, roomsLock; // locking order: roomsLock before clientsLock Server(QObject *parent = 0); ~Server(); - AuthenticationResult loginUser(Server_DatabaseInterface *sessionDatabaseInterface, Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason, int &secondsLeft); + AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason, int &secondsLeft); const QMap &getRooms() { return rooms; } const QMap &getUsers() const { return users; } @@ -61,9 +61,9 @@ public: virtual int getMaxGamesPerUser() const { return 0; } virtual bool getThreaded() const { return false; } + Server_DatabaseInterface *getDatabaseInterface() const; virtual void storeGameInformation(int secondsElapsed, const QSet &allPlayersEver, const QSet &allSpectatorsEver, const QList &replays) { } - virtual DeckList *getDeckFromDatabase(int deckId, const QString &userName) { return 0; } - + void sendIsl_Response(const Response &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_SessionEvent(const SessionEvent &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_GameEventContainer(const GameEventContainer &item, int serverId = -1, qint64 sessionId = -1); @@ -97,13 +97,13 @@ protected slots: protected: void prepareDestroy(); void setDatabaseInterface(Server_DatabaseInterface *_databaseInterface); - Server_DatabaseInterface *databaseInterface; QList clients; QMap usersBySessionId; QMap users; QMap externalUsersBySessionId; QMap externalUsers; QMap rooms; + QMap databaseInterfaces; int getUsersCount() const; int getGamesCount() const; diff --git a/common/server_database_interface.cpp b/common/server_database_interface.cpp deleted file mode 100644 index e8388198..00000000 --- a/common/server_database_interface.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "server_database_interface.h" - -Server_DatabaseInterface::Server_DatabaseInterface() - : nextGameId(0), - nextReplayId(0) -{ -} diff --git a/common/server_database_interface.h b/common/server_database_interface.h index 36709b0d..c12d69f0 100644 --- a/common/server_database_interface.h +++ b/common/server_database_interface.h @@ -7,10 +7,9 @@ class Server_DatabaseInterface : public QObject { Q_OBJECT -private: - int nextGameId, nextReplayId; public: - Server_DatabaseInterface(); + Server_DatabaseInterface(QObject *parent = 0) + : QObject(parent) { } virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) = 0; virtual bool userExists(const QString &user) { return false; } @@ -19,13 +18,15 @@ public: virtual bool isInBuddyList(const QString &whoseList, const QString &who) { return false; } virtual bool isInIgnoreList(const QString &whoseList, const QString &who) { return false; } virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0; + virtual void storeGameInformation(const QString &roomName, const QStringList &roomGameTypes, const ServerInfo_Game &gameInfo, const QSet &allPlayersEver, const QSet &allSpectatorsEver, const QList &replayList) { } + virtual DeckList *getDeckFromDatabase(int deckId, const QString &userName) { return 0; } virtual qint64 startSession(const QString &userName, const QString &address) { return 0; } public slots: virtual void endSession(qint64 sessionId) { } public: - virtual int getNextGameId() { return nextGameId++; } - virtual int getNextReplayId() { return nextReplayId++; } + virtual int getNextGameId() = 0; + virtual int getNextReplayId() = 0; virtual void clearSessionTables() { } virtual void lockSessionTables() { } diff --git a/common/server_game.cpp b/common/server_game.cpp index 669cdf60..d19cdf1b 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -74,7 +74,7 @@ Server_Game::Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, const gameMutex(QMutex::Recursive) { currentReplay = new GameReplay; - currentReplay->set_replay_id(room->getServer()->getNextReplayId()); + currentReplay->set_replay_id(room->getServer()->getDatabaseInterface()->getNextReplayId()); connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection); @@ -242,6 +242,7 @@ void Server_Game::sendGameStateToPlayers() void Server_Game::doStartGameIfReady() { + Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface(); QMutexLocker locker(&gameMutex); if (getPlayerCount() < maxPlayers) @@ -271,7 +272,7 @@ void Server_Game::doStartGameIfReady() currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame); replayList.append(currentReplay); currentReplay = new GameReplay; - currentReplay->set_replay_id(room->getServer()->getNextReplayId()); + currentReplay->set_replay_id(databaseInterface->getNextReplayId()); getInfo(*currentReplay->mutable_game_info()); Event_GameStateChanged omniscientEvent; @@ -340,8 +341,9 @@ void Server_Game::stopGameIfFinished() emit gameInfoChanged(gameInfo); } -Response::ResponseCode Server_Game::checkJoin(Server_DatabaseInterface *databaseInterface, ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions) +Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions) { + Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface(); { QMapIterator playerIterator(players); while (playerIterator.hasNext()) diff --git a/common/server_game.h b/common/server_game.h index a179581c..3992d55c 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -39,7 +39,6 @@ class ServerInfo_User; class ServerInfo_Player; class ServerInfo_Game; class Server_AbstractUserInterface; -class Server_DatabaseInterface; class Event_GameStateChanged; class Server_Game : public QObject { @@ -99,7 +98,7 @@ public: bool getSpectatorsNeedPassword() const { return spectatorsNeedPassword; } bool getSpectatorsCanTalk() const { return spectatorsCanTalk; } bool getSpectatorsSeeEverything() const { return spectatorsSeeEverything; } - Response::ResponseCode checkJoin(Server_DatabaseInterface *databaseInterface, ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions); + Response::ResponseCode checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions); bool containsUser(const QString &userName) const; void addPlayer(Server_AbstractUserInterface *userInterface, ResponseContainer &rc, bool spectator, bool broadcastUpdate = true); void removePlayer(Server_Player *player); diff --git a/common/server_player.cpp b/common/server_player.cpp index cc5c79ec..330d7ddb 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -7,6 +7,7 @@ #include "server_game.h" #include "server_room.h" #include "server_abstractuserinterface.h" +#include "server_database_interface.h" #include "decklist.h" #include "color.h" #include "rng_abstract.h" @@ -626,7 +627,7 @@ Response::ResponseCode Server_Player::cmdDeckSelect(const Command_DeckSelect &cm DeckList *newDeck; if (cmd.has_deck_id()) { try { - newDeck = game->getRoom()->getServer()->getDeckFromDatabase(cmd.deck_id(), QString::fromStdString(userInfo->name())); + newDeck = game->getRoom()->getServer()->getDatabaseInterface()->getDeckFromDatabase(cmd.deck_id(), QString::fromStdString(userInfo->name())); } catch(Response::ResponseCode r) { return r; } diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index c55c8742..707a861a 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -317,7 +317,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd return Response::RespContextError; QString reasonStr; int banSecondsLeft = 0; - AuthenticationResult res = server->loginUser(databaseInterface, this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft); + AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft); switch (res) { case UserIsBanned: { Response_Login *re = new Response_Login; @@ -542,6 +542,9 @@ Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_Creat { if (authState == NotLoggedIn) return Response::RespLoginNeeded; + const int gameId = databaseInterface->getNextGameId(); + if (gameId == -1) + return Response::RespInternalError; QMutexLocker roomLocker(&room->gamesMutex); @@ -557,7 +560,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_Creat if (description.size() > 60) description = description.left(60); - Server_Game *game = new Server_Game(copyUserInfo(false), server->getNextGameId(), description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, cmd.only_buddies(), cmd.only_registered(), cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(), cmd.spectators_see_everything(), room); + Server_Game *game = new Server_Game(copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, cmd.only_buddies(), cmd.only_registered(), cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(), cmd.spectators_see_everything(), room); game->addPlayer(this, rc, false, false); room->addGame(game); @@ -569,5 +572,5 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam if (authState == NotLoggedIn) return Response::RespLoginNeeded; - return room->processJoinGameCommand(cmd, rc, this, databaseInterface); + return room->processJoinGameCommand(cmd, rc, this); } diff --git a/common/server_room.cpp b/common/server_room.cpp index 4114d30a..5538a121 100644 --- a/common/server_room.cpp +++ b/common/server_room.cpp @@ -169,7 +169,7 @@ void Server_Room::updateExternalGameList(const ServerInfo_Game &gameInfo) emit roomInfoChanged(getInfo(roomInfo, false, false, true)); } -Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface, Server_DatabaseInterface *databaseInterface) +Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface) { // This function is called from the Server thread and from the S_PH thread. // server->roomsMutex is always locked. @@ -191,7 +191,7 @@ Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGam QMutexLocker gameLocker(&g->gameMutex); - Response::ResponseCode result = g->checkJoin(databaseInterface, userInterface->getUserInfo(), QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions()); + Response::ResponseCode result = g->checkJoin(userInterface->getUserInfo(), QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions()); if (result == Response::RespOk) g->addPlayer(userInterface, rc, cmd.spectator()); @@ -231,7 +231,6 @@ void Server_Room::addGame(Server_Game *game) { // Lock gamesMutex before calling this - game->moveToThread(thread()); connect(game, SIGNAL(gameInfoChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game))); game->gameMutex.lock(); diff --git a/common/server_room.h b/common/server_room.h index a62b0f32..421a9836 100644 --- a/common/server_room.h +++ b/common/server_room.h @@ -67,7 +67,7 @@ public: const QMap &getExternalUsers() const { return externalUsers; } void updateExternalGameList(const ServerInfo_Game &gameInfo); - Response::ResponseCode processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface, Server_DatabaseInterface *databaseInterface); + Response::ResponseCode processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface); void say(const QString &userName, const QString &s, bool sendToIsl = true); diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index cf4f5b01..94a7f14f 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -117,25 +117,36 @@ bool Servatrice::initServer() databaseType = DatabaseMySql; else databaseType = DatabaseNone; - dbPrefix = settings->value("database/prefix").toString(); + + servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this); + setDatabaseInterface(servatriceDatabaseInterface); + if (databaseType != DatabaseNone) { - openDatabase(); + settings->beginGroup("database"); + dbPrefix = settings->value("prefix").toString(); + servatriceDatabaseInterface->initDatabase("QMYSQL", + settings->value("hostname").toString(), + settings->value("database").toString(), + settings->value("user").toString(), + settings->value("password").toString()); + settings->endGroup(); + updateServerList(); qDebug() << "Clearing previous sessions..."; - databaseInterface->clearSessionTables(); + servatriceDatabaseInterface->clearSessionTables(); } const QString roomMethod = settings->value("rooms/method").toString(); if (roomMethod == "sql") { - QSqlQuery query(sqlDatabase); + QSqlQuery query(servatriceDatabaseInterface->getDatabase()); query.prepare("select id, name, descr, auto_join, join_message from " + dbPrefix + "_rooms order by id asc"); - execSqlQuery(query); + servatriceDatabaseInterface->execSqlQuery(query); while (query.next()) { - QSqlQuery query2(sqlDatabase); + QSqlQuery query2(servatriceDatabaseInterface->getDatabase()); query2.prepare("select name from " + dbPrefix + "_rooms_gametypes where id_room = :id_room"); query2.bindValue(":id_room", query.value(0).toInt()); - execSqlQuery(query2); + servatriceDatabaseInterface->execSqlQuery(query2); QStringList gameTypes; while (query2.next()) gameTypes.append(query2.value(0).toString()); @@ -252,7 +263,7 @@ bool Servatrice::initServer() threaded = settings->value("server/threaded", false).toInt(); const int numberPools = settings->value("server/number_pools", 1).toInt(); - gameServer = new Servatrice_GameServer(this, threaded, numberPools, sqlDatabase, this); + gameServer = new Servatrice_GameServer(this, threaded, numberPools, servatriceDatabaseInterface->getDatabase(), this); const int gamePort = settings->value("server/port", 4747).toInt(); qDebug() << "Starting server on port" << gamePort; if (gameServer->listen(QHostAddress::Any, gamePort)) @@ -264,46 +275,6 @@ bool Servatrice::initServer() return true; } -bool Servatrice::openDatabase() -{ - if (!sqlDatabase.isValid()) { - settings->beginGroup("database"); - sqlDatabase = QSqlDatabase::addDatabase("QMYSQL"); - sqlDatabase.setHostName(settings->value("hostname").toString()); - sqlDatabase.setDatabaseName(settings->value("database").toString()); - sqlDatabase.setUserName(settings->value("user").toString()); - sqlDatabase.setPassword(settings->value("password").toString()); - settings->endGroup(); - } else if (sqlDatabase.isOpen()) - sqlDatabase.close(); - - qDebug() << QString("[main] Opening database..."); - if (!sqlDatabase.open()) { - qDebug() << QString("[main] Error opening database: %1").arg(sqlDatabase.lastError().text()); - return false; - } - - return true; -} - -bool Servatrice::checkSql() -{ - if (databaseType == DatabaseNone) - return false; - - if (!sqlDatabase.exec("select 1").isActive()) - return openDatabase(); - return true; -} - -bool Servatrice::execSqlQuery(QSqlQuery &query) -{ - if (query.exec()) - return true; - qCritical() << QString("[main] Error executing query: %1").arg(query.lastError().text()); - return false; -} - void Servatrice::updateServerList() { qDebug() << "Updating server list..."; @@ -311,9 +282,9 @@ void Servatrice::updateServerList() serverListMutex.lock(); serverList.clear(); - QSqlQuery query(sqlDatabase); + QSqlQuery query(servatriceDatabaseInterface->getDatabase()); query.prepare("select id, ssl_cert, hostname, address, game_port, control_port from " + dbPrefix + "_servers order by id asc"); - execSqlQuery(query); + servatriceDatabaseInterface->execSqlQuery(query); while (query.next()) { ServerProperties prop(query.value(0).toInt(), QSslCertificate(query.value(1).toString().toAscii()), query.value(2).toString(), QHostAddress(query.value(3).toString()), query.value(4).toInt(), query.value(5).toInt()); serverList.append(prop); @@ -352,20 +323,73 @@ QList Servatrice::getUsersWithAddressAsList(const QHost return result; } +void Servatrice::storeGameInformation(int secondsElapsed, const QSet &allPlayersEver, const QSet &allSpectatorsEver, const QList &replayList) +{ + const ServerInfo_Game &gameInfo = replayList.first()->game_info(); + + Server_Room *room = rooms.value(gameInfo.room_id()); + + Event_ReplayAdded replayEvent; + ServerInfo_ReplayMatch *replayMatchInfo = replayEvent.mutable_match_info(); + replayMatchInfo->set_game_id(gameInfo.game_id()); + replayMatchInfo->set_room_name(room->getName().toStdString()); + replayMatchInfo->set_time_started(QDateTime::currentDateTime().addSecs(-secondsElapsed).toTime_t()); + replayMatchInfo->set_length(secondsElapsed); + replayMatchInfo->set_game_name(gameInfo.description()); + + const QStringList &allGameTypes = room->getGameTypes(); + QStringList gameTypes; + for (int i = gameInfo.game_types_size() - 1; i >= 0; --i) + gameTypes.append(allGameTypes[gameInfo.game_types(i)]); + + QSetIterator playerIterator(allPlayersEver); + while (playerIterator.hasNext()) + replayMatchInfo->add_player_names(playerIterator.next().toStdString()); + + for (int i = 0; i < replayList.size(); ++i) { + ServerInfo_Replay *replayInfo = replayMatchInfo->add_replay_list(); + replayInfo->set_replay_id(replayList[i]->replay_id()); + replayInfo->set_replay_name(gameInfo.description()); + replayInfo->set_duration(replayList[i]->duration_seconds()); + } + + QSet allUsersInGame = allPlayersEver + allSpectatorsEver; + QSetIterator allUsersIterator(allUsersInGame); + + SessionEvent *sessionEvent = Server_ProtocolHandler::prepareSessionEvent(replayEvent); + clientsLock.lockForRead(); + while (allUsersIterator.hasNext()) { + const QString userName = allUsersIterator.next(); + Server_AbstractUserInterface *userHandler = users.value(userName); + if (!userHandler) + userHandler = externalUsers.value(userName); + if (userHandler) + userHandler->sendProtocolItem(*sessionEvent); + } + clientsLock.unlock(); + delete sessionEvent; + + getDatabaseInterface()->storeGameInformation(room->getName(), gameTypes, gameInfo, allPlayersEver, allSpectatorsEver, replayList); +} + void Servatrice::updateLoginMessage() { - if (!checkSql()) + if (!servatriceDatabaseInterface->checkSql()) return; - QSqlQuery query; + QSqlQuery query(servatriceDatabaseInterface->getDatabase()); query.prepare("select message from " + dbPrefix + "_servermessages where id_server = :id_server order by timest desc limit 1"); query.bindValue(":id_server", serverId); - if (execSqlQuery(query)) + if (servatriceDatabaseInterface->execSqlQuery(query)) if (query.next()) { - loginMessage = query.value(0).toString(); + const QString newLoginMessage = query.value(0).toString(); + + loginMessageMutex.lock(); + loginMessage = newLoginMessage; + loginMessageMutex.unlock(); Event_ServerMessage event; - event.set_message(loginMessage.toStdString()); + event.set_message(newLoginMessage.toStdString()); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); QMapIterator usersIterator(users); while (usersIterator.hasNext()) @@ -376,6 +400,9 @@ void Servatrice::updateLoginMessage() void Servatrice::statusUpdate() { + if (!servatriceDatabaseInterface->checkSql()) + return; + const int uc = getUsersCount(); // for correct mutex locking order const int gc = getGamesCount(); @@ -390,10 +417,7 @@ void Servatrice::statusUpdate() rxBytes = 0; rxBytesMutex.unlock(); - if (!checkSql()) - return; - - QSqlQuery query; + QSqlQuery query(servatriceDatabaseInterface->getDatabase()); query.prepare("insert into " + dbPrefix + "_uptime (id_server, timest, uptime, users_count, games_count, tx_bytes, rx_bytes) values(:id, NOW(), :uptime, :users_count, :games_count, :tx, :rx)"); query.bindValue(":id", serverId); query.bindValue(":uptime", uptime); @@ -401,7 +425,7 @@ void Servatrice::statusUpdate() query.bindValue(":games_count", gc); query.bindValue(":tx", tx); query.bindValue(":rx", rx); - execSqlQuery(query); + servatriceDatabaseInterface->execSqlQuery(query); } void Servatrice::scheduleShutdown(const QString &reason, int minutes) diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index afb256eb..32dd53e5 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -26,7 +26,6 @@ #include #include #include -#include #include "server.h" class QSqlDatabase; @@ -37,6 +36,7 @@ class QTimer; class GameReplay; class Servatrice; class Servatrice_ConnectionPool; +class Servatrice_DatabaseInterface; class ServerSocketInterface; class IslInterface; @@ -92,14 +92,15 @@ private: enum DatabaseType { DatabaseNone, DatabaseMySql }; AuthenticationMethod authenticationMethod; DatabaseType databaseType; - QSqlDatabase sqlDatabase; QTimer *pingClock, *statusUpdateClock; Servatrice_GameServer *gameServer; Servatrice_IslServer *islServer; QString serverName; + mutable QMutex loginMessageMutex; QString loginMessage; QString dbPrefix; QSettings *settings; + Servatrice_DatabaseInterface *servatriceDatabaseInterface; int serverId; bool threaded; int uptime; @@ -123,11 +124,8 @@ public: Servatrice(QSettings *_settings, QObject *parent = 0); ~Servatrice(); bool initServer(); - bool openDatabase(); - bool checkSql(); - bool execSqlQuery(QSqlQuery &query); QString getServerName() const { return serverName; } - QString getLoginMessage() const { return loginMessage; } + QString getLoginMessage() const { QMutexLocker locker(&loginMessageMutex); return loginMessage; } bool getGameShouldPing() const { return true; } int getMaxGameInactivityTime() const { return maxGameInactivityTime; } int getMaxPlayerInactivityTime() const { return maxPlayerInactivityTime; } @@ -146,7 +144,6 @@ public: void incTxBytes(quint64 num); void incRxBytes(quint64 num); void storeGameInformation(int secondsElapsed, const QSet &allPlayersEver, const QSet &allSpectatorsEver, const QList &replays); - DeckList *getDeckFromDatabase(int deckId, const QString &userName); bool islConnectionExists(int serverId) const; void addIslInterface(int serverId, IslInterface *interface); diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index 235deac3..24302d6a 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -2,6 +2,8 @@ #include "servatrice_database_interface.h" #include "passwordhasher.h" #include "serversocketinterface.h" +#include "decklist.h" +#include "pb/game_replay.pb.h" #include #include #include @@ -19,14 +21,26 @@ void Servatrice_DatabaseInterface::initDatabase(const QSqlDatabase &_sqlDatabase openDatabase(); } +void Servatrice_DatabaseInterface::initDatabase(const QString &type, const QString &hostName, const QString &databaseName, const QString &userName, const QString &password) +{ + sqlDatabase = QSqlDatabase::addDatabase(type, "main"); + sqlDatabase.setHostName(hostName); + sqlDatabase.setDatabaseName(databaseName); + sqlDatabase.setUserName(userName); + sqlDatabase.setPassword(password); + + openDatabase(); +} + bool Servatrice_DatabaseInterface::openDatabase() { if (sqlDatabase.isOpen()) sqlDatabase.close(); - qDebug() << QString("[pool %1] Opening database...").arg(instanceId); + const QString poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId); + qDebug() << QString("[%1] Opening database...").arg(poolStr); if (!sqlDatabase.open()) { - qCritical() << QString("[pool %1] Error opening database: %2").arg(instanceId).arg(sqlDatabase.lastError().text()); + qCritical() << QString("[%1] Error opening database: %2").arg(poolStr).arg(sqlDatabase.lastError().text()); return false; } @@ -47,7 +61,8 @@ bool Servatrice_DatabaseInterface::execSqlQuery(QSqlQuery &query) { if (query.exec()) return true; - qCritical() << QString("[pool %1] Error executing query: %2").arg(instanceId).arg(query.lastError().text()); + const QString poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId); + qCritical() << QString("[%1] Error executing query: %2").arg(poolStr).arg(query.lastError().text()); return false; } @@ -130,7 +145,7 @@ bool Servatrice_DatabaseInterface::userExists(const QString &user) if (server->getAuthenticationMethod() == Servatrice::AuthenticationSql) { checkSql(); - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("select 1 from " + server->getDbPrefix() + "_users where name = :name and active = 1"); query.bindValue(":name", user); if (!execSqlQuery(query)) @@ -143,7 +158,7 @@ bool Servatrice_DatabaseInterface::userExists(const QString &user) int Servatrice_DatabaseInterface::getUserIdInDB(const QString &name) { if (server->getAuthenticationMethod() == Servatrice::AuthenticationSql) { - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("select id from " + server->getDbPrefix() + "_users where name = :name and active = 1"); query.bindValue(":name", name); if (!execSqlQuery(query)) @@ -166,7 +181,7 @@ bool Servatrice_DatabaseInterface::isInBuddyList(const QString &whoseList, const int id1 = getUserIdInDB(whoseList); int id2 = getUserIdInDB(who); - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("select 1 from " + server->getDbPrefix() + "_buddylist where id_user1 = :id_user1 and id_user2 = :id_user2"); query.bindValue(":id_user1", id1); query.bindValue(":id_user2", id2); @@ -186,7 +201,7 @@ bool Servatrice_DatabaseInterface::isInIgnoreList(const QString &whoseList, cons int id1 = getUserIdInDB(whoseList); int id2 = getUserIdInDB(who); - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("select 1 from " + server->getDbPrefix() + "_ignorelist where id_user1 = :id_user1 and id_user2 = :id_user2"); query.bindValue(":id_user1", id1); query.bindValue(":id_user2", id2); @@ -244,7 +259,7 @@ ServerInfo_User Servatrice_DatabaseInterface::getUserData(const QString &name, b if (!checkSql()) return result; - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("select id, name, admin, realname, gender, country, avatar_bmp from " + server->getDbPrefix() + "_users where name = :name and active = 1"); query.bindValue(":name", name); if (!execSqlQuery(query)) @@ -261,7 +276,7 @@ ServerInfo_User Servatrice_DatabaseInterface::getUserData(const QString &name, b void Servatrice_DatabaseInterface::clearSessionTables() { lockSessionTables(); - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("update " + server->getDbPrefix() + "_sessions set end_time=now() where end_time is null and id_server = :id_server"); query.bindValue(":id_server", server->getServerId()); query.exec(); @@ -270,19 +285,19 @@ void Servatrice_DatabaseInterface::clearSessionTables() void Servatrice_DatabaseInterface::lockSessionTables() { - QSqlQuery("lock tables " + server->getDbPrefix() + "_sessions write, " + server->getDbPrefix() + "_users read").exec(); + QSqlQuery("lock tables " + server->getDbPrefix() + "_sessions write, " + server->getDbPrefix() + "_users read", sqlDatabase).exec(); } void Servatrice_DatabaseInterface::unlockSessionTables() { - QSqlQuery("unlock tables").exec(); + QSqlQuery("unlock tables", sqlDatabase).exec(); } bool Servatrice_DatabaseInterface::userSessionExists(const QString &userName) { // Call only after lockSessionTables(). - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("select 1 from " + server->getDbPrefix() + "_sessions where user_name = :user_name and end_time is null"); query.bindValue(":user_name", userName); query.exec(); @@ -297,7 +312,7 @@ qint64 Servatrice_DatabaseInterface::startSession(const QString &userName, const if (!checkSql()) return -1; - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("insert into " + server->getDbPrefix() + "_sessions (user_name, id_server, ip_address, start_time) values(:user_name, :id_server, :ip_address, NOW())"); query.bindValue(":user_name", userName); query.bindValue(":id_server", server->getServerId()); @@ -315,7 +330,7 @@ void Servatrice_DatabaseInterface::endSession(qint64 sessionId) if (!checkSql()) return; - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.exec("lock tables " + server->getDbPrefix() + "_sessions write"); query.prepare("update " + server->getDbPrefix() + "_sessions set end_time=NOW() where id = :id_session"); query.bindValue(":id_session", sessionId); @@ -330,7 +345,7 @@ QMap Servatrice_DatabaseInterface::getBuddyList(const if (server->getAuthenticationMethod() == Servatrice::AuthenticationSql) { checkSql(); - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("select a.id, a.name, a.admin, a.realname, a.gender, a.country from " + server->getDbPrefix() + "_users a left join " + server->getDbPrefix() + "_buddylist b on a.id = b.id_user2 left join " + server->getDbPrefix() + "_users c on b.id_user1 = c.id where c.name = :name"); query.bindValue(":name", name); if (!execSqlQuery(query)) @@ -351,7 +366,7 @@ QMap Servatrice_DatabaseInterface::getIgnoreList(const if (server->getAuthenticationMethod() == Servatrice::AuthenticationSql) { checkSql(); - QSqlQuery query; + QSqlQuery query(sqlDatabase); query.prepare("select a.id, a.name, a.admin, a.realname, a.gender, a.country from " + server->getDbPrefix() + "_users a left join " + server->getDbPrefix() + "_ignorelist b on a.id = b.id_user2 left join " + server->getDbPrefix() + "_users c on b.id_user1 = c.id where c.name = :name"); query.bindValue(":name", name); if (!execSqlQuery(query)) @@ -368,10 +383,10 @@ QMap Servatrice_DatabaseInterface::getIgnoreList(const int Servatrice_DatabaseInterface::getNextGameId() { if (!checkSql()) - return Server_DatabaseInterface::getNextGameId(); + return -1; - QSqlQuery query; - query.prepare("insert into " + dbPrefix + "_games (time_started) values (now())"); + QSqlQuery query(sqlDatabase); + query.prepare("insert into " + server->getDbPrefix() + "_games (time_started) values (now())"); execSqlQuery(query); return query.lastInsertId().toInt(); @@ -380,33 +395,19 @@ int Servatrice_DatabaseInterface::getNextGameId() int Servatrice_DatabaseInterface::getNextReplayId() { if (!checkSql()) - return Server_DatabaseInterface::getNextReplayId(); + return -1; - QSqlQuery query; - query.prepare("insert into " + dbPrefix + "_replays () values ()"); + QSqlQuery query(sqlDatabase); + query.prepare("insert into " + server->getDbPrefix() + "_replays () values ()"); execSqlQuery(query); return query.lastInsertId().toInt(); } -void Servatrice_DatabaseInterface::storeGameInformation(int secondsElapsed, const QSet &allPlayersEver, const QSet &allSpectatorsEver, const QList &replayList) +void Servatrice_DatabaseInterface::storeGameInformation(const QString &roomName, const QStringList &roomGameTypes, const ServerInfo_Game &gameInfo, const QSet &allPlayersEver, const QSet &allSpectatorsEver, const QList &replayList) { - const ServerInfo_Game &gameInfo = replayList.first()->game_info(); - - Server_Room *room = rooms.value(gameInfo.room_id()); - - Event_ReplayAdded replayEvent; - ServerInfo_ReplayMatch *replayMatchInfo = replayEvent.mutable_match_info(); - replayMatchInfo->set_game_id(gameInfo.game_id()); - replayMatchInfo->set_room_name(room->getName().toStdString()); - replayMatchInfo->set_time_started(QDateTime::currentDateTime().addSecs(-secondsElapsed).toTime_t()); - replayMatchInfo->set_length(secondsElapsed); - replayMatchInfo->set_game_name(gameInfo.description()); - - const QStringList &allGameTypes = room->getGameTypes(); - QStringList gameTypes; - for (int i = gameInfo.game_types_size() - 1; i >= 0; --i) - gameTypes.append(allGameTypes[gameInfo.game_types(i)]); + if (!checkSql()) + return; QVariantList gameIds1, playerNames, gameIds2, userIds, replayNames; QSetIterator playerIterator(allPlayersEver); @@ -414,7 +415,6 @@ void Servatrice_DatabaseInterface::storeGameInformation(int secondsElapsed, cons gameIds1.append(gameInfo.game_id()); const QString &playerName = playerIterator.next(); playerNames.append(playerName); - replayMatchInfo->add_player_names(playerName.toStdString()); } QSet allUsersInGame = allPlayersEver + allSpectatorsEver; QSetIterator allUsersIterator(allUsersInGame); @@ -438,80 +438,62 @@ void Servatrice_DatabaseInterface::storeGameInformation(int secondsElapsed, cons replayGameIds.append(gameInfo.game_id()); replayDurations.append(replayList[i]->duration_seconds()); replayBlobs.append(blob); - - ServerInfo_Replay *replayInfo = replayMatchInfo->add_replay_list(); - replayInfo->set_replay_id(replayList[i]->replay_id()); - replayInfo->set_replay_name(gameInfo.description()); - replayInfo->set_duration(replayList[i]->duration_seconds()); } - SessionEvent *sessionEvent = Server_ProtocolHandler::prepareSessionEvent(replayEvent); - allUsersIterator.toFront(); - clientsLock.lockForRead(); - while (allUsersIterator.hasNext()) { - const QString userName = allUsersIterator.next(); - Server_AbstractUserInterface *userHandler = users.value(userName); - if (!userHandler) - userHandler = externalUsers.value(userName); - if (userHandler) - userHandler->sendProtocolItem(*sessionEvent); + { + QSqlQuery query(sqlDatabase); + query.prepare("update " + server->getDbPrefix() + "_games set room_name=:room_name, descr=:descr, creator_name=:creator_name, password=:password, game_types=:game_types, player_count=:player_count, time_finished=now() where id=:id_game"); + query.bindValue(":room_name", roomName); + query.bindValue(":id_game", gameInfo.game_id()); + query.bindValue(":descr", QString::fromStdString(gameInfo.description())); + query.bindValue(":creator_name", QString::fromStdString(gameInfo.creator_info().name())); + query.bindValue(":password", gameInfo.with_password() ? 1 : 0); + query.bindValue(":game_types", roomGameTypes.isEmpty() ? QString("") : roomGameTypes.join(", ")); + query.bindValue(":player_count", gameInfo.max_players()); + if (!execSqlQuery(query)) + return; + } + { + QSqlQuery query(sqlDatabase); + query.prepare("insert into " + server->getDbPrefix() + "_games_players (id_game, player_name) values (:id_game, :player_name)"); + query.bindValue(":id_game", gameIds1); + query.bindValue(":player_name", playerNames); + query.execBatch(); + } + { + QSqlQuery query(sqlDatabase); + query.prepare("update " + server->getDbPrefix() + "_replays set id_game=:id_game, duration=:duration, replay=:replay where id=:id_replay"); + query.bindValue(":id_replay", replayIds); + query.bindValue(":id_game", replayGameIds); + query.bindValue(":duration", replayDurations); + query.bindValue(":replay", replayBlobs); + query.execBatch(); + } + { + QSqlQuery query(sqlDatabase); + query.prepare("insert into " + server->getDbPrefix() + "_replays_access (id_game, id_player, replay_name) values (:id_game, :id_player, :replay_name)"); + query.bindValue(":id_game", gameIds2); + query.bindValue(":id_player", userIds); + query.bindValue(":replay_name", replayNames); + query.execBatch(); } - clientsLock.unlock(); - delete sessionEvent; - - if (!checkSql()) - return; - - QSqlQuery query1; - query1.prepare("update " + dbPrefix + "_games set room_name=:room_name, descr=:descr, creator_name=:creator_name, password=:password, game_types=:game_types, player_count=:player_count, time_finished=now() where id=:id_game"); - query1.bindValue(":room_name", room->getName()); - query1.bindValue(":id_game", gameInfo.game_id()); - query1.bindValue(":descr", QString::fromStdString(gameInfo.description())); - query1.bindValue(":creator_name", QString::fromStdString(gameInfo.creator_info().name())); - query1.bindValue(":password", gameInfo.with_password() ? 1 : 0); - query1.bindValue(":game_types", gameTypes.isEmpty() ? QString("") : gameTypes.join(", ")); - query1.bindValue(":player_count", gameInfo.max_players()); - if (!execSqlQuery(query1)) - return; - - QSqlQuery query2; - query2.prepare("insert into " + dbPrefix + "_games_players (id_game, player_name) values (:id_game, :player_name)"); - query2.bindValue(":id_game", gameIds1); - query2.bindValue(":player_name", playerNames); - query2.execBatch(); - - QSqlQuery replayQuery1; - replayQuery1.prepare("update " + dbPrefix + "_replays set id_game=:id_game, duration=:duration, replay=:replay where id=:id_replay"); - replayQuery1.bindValue(":id_replay", replayIds); - replayQuery1.bindValue(":id_game", replayGameIds); - replayQuery1.bindValue(":duration", replayDurations); - replayQuery1.bindValue(":replay", replayBlobs); - replayQuery1.execBatch(); - - QSqlQuery query3; - query3.prepare("insert into " + dbPrefix + "_replays_access (id_game, id_player, replay_name) values (:id_game, :id_player, :replay_name)"); - query3.bindValue(":id_game", gameIds2); - query3.bindValue(":id_player", userIds); - query3.bindValue(":replay_name", replayNames); - query3.execBatch(); } DeckList *Servatrice_DatabaseInterface::getDeckFromDatabase(int deckId, const QString &userName) { checkSql(); - QSqlQuery query; + QSqlQuery query(sqlDatabase); - query.prepare("select content from " + dbPrefix + "_decklist_files where id = :id and user = :user"); + query.prepare("select content from " + server->getDbPrefix() + "_decklist_files where id = :id and user = :user"); query.bindValue(":id", deckId); query.bindValue(":user", userName); execSqlQuery(query); if (!query.next()) throw Response::RespNameNotFound; - QXmlStreamReader deckReader(query.value(0).toString()); DeckList *deck = new DeckList; - deck->loadFromXml(&deckReader); + deck->loadFromString_Native(query.value(0).toString()); return deck; } diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index 59beddef..4f0d0910 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -21,9 +21,11 @@ protected: public: Servatrice_DatabaseInterface(int _instanceId, Servatrice *_server); void initDatabase(const QSqlDatabase &_sqlDatabase); + void initDatabase(const QString &type, const QString &hostName, const QString &databaseName, const QString &userName, const QString &password); bool openDatabase(); bool checkSql(); bool execSqlQuery(QSqlQuery &query); + const QSqlDatabase &getDatabase() { return sqlDatabase; } bool userExists(const QString &user); int getUserIdInDB(const QString &name); @@ -32,6 +34,8 @@ public: bool isInBuddyList(const QString &whoseList, const QString &who); bool isInIgnoreList(const QString &whoseList, const QString &who); ServerInfo_User getUserData(const QString &name, bool withId = false); + void storeGameInformation(const QString &roomName, const QStringList &roomGameTypes, const ServerInfo_Game &gameInfo, const QSet &allPlayersEver, const QSet &allSpectatorsEver, const QList &replayList); + DeckList *getDeckFromDatabase(int deckId, const QString &userName); int getNextGameId(); int getNextReplayId(); diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 43437db7..08fe0d1c 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -18,9 +18,10 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#include +#include #include #include +#include #include "serversocketinterface.h" #include "servatrice.h" #include "servatrice_database_interface.h" @@ -63,6 +64,7 @@ static const int protocolVersion = 14; ServerSocketInterface::ServerSocketInterface(Servatrice *_server, Servatrice_DatabaseInterface *_databaseInterface, QTcpSocket *_socket, QObject *parent) : Server_ProtocolHandler(_server, _databaseInterface, parent), servatrice(_server), + sqlInterface(reinterpret_cast(databaseInterface)), socket(_socket), messageInProgress(false), handshakeStarted(false) @@ -244,18 +246,17 @@ Response::ResponseCode ServerSocketInterface::cmdAddToList(const Command_AddToLi return Response::RespContextError; int id1 = userInfo->id(); - int id2 = static_cast(databaseInterface)->getUserIdInDB(user); + int id2 = sqlInterface->getUserIdInDB(user); if (id2 < 0) return Response::RespNameNotFound; if (id1 == id2) return Response::RespContextError; -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("insert into " + servatrice->getDbPrefix() + "_" + list + "list (id_user1, id_user2) values(:id1, :id2)"); query.bindValue(":id1", id1); query.bindValue(":id2", id2); - if (!servatrice->execSqlQuery(query)) + if (!sqlInterface->execSqlQuery(query)) return Response::RespInternalError; Event_AddToList event; @@ -285,16 +286,15 @@ Response::ResponseCode ServerSocketInterface::cmdRemoveFromList(const Command_Re return Response::RespContextError; int id1 = userInfo->id(); - int id2 = static_cast(databaseInterface)->getUserIdInDB(user); + int id2 = sqlInterface->getUserIdInDB(user); if (id2 < 0) return Response::RespNameNotFound; -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("delete from " + servatrice->getDbPrefix() + "_" + list + "list where id_user1 = :id1 and id_user2 = :id2"); query.bindValue(":id1", id1); query.bindValue(":id2", id2); - if (!servatrice->execSqlQuery(query)) + if (!sqlInterface->execSqlQuery(query)) return Response::RespInternalError; Event_RemoveFromList event; @@ -312,13 +312,12 @@ int ServerSocketInterface::getDeckPathId(int basePathId, QStringList path) if (path[0].isEmpty()) return 0; -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("select id from " + servatrice->getDbPrefix() + "_decklist_folders where id_parent = :id_parent and name = :name and user = :user"); query.bindValue(":id_parent", basePathId); query.bindValue(":name", path.takeFirst()); query.bindValue(":user", QString::fromStdString(userInfo->name())); - if (!servatrice->execSqlQuery(query)) + if (!sqlInterface->execSqlQuery(query)) return -1; if (!query.next()) return -1; @@ -336,12 +335,11 @@ int ServerSocketInterface::getDeckPathId(const QString &path) bool ServerSocketInterface::deckListHelper(int folderId, ServerInfo_DeckStorage_Folder *folder) { -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("select id, name from " + servatrice->getDbPrefix() + "_decklist_folders where id_parent = :id_parent and user = :user"); query.bindValue(":id_parent", folderId); query.bindValue(":user", QString::fromStdString(userInfo->name())); - if (!servatrice->execSqlQuery(query)) + if (!sqlInterface->execSqlQuery(query)) return false; while (query.next()) { @@ -356,7 +354,7 @@ bool ServerSocketInterface::deckListHelper(int folderId, ServerInfo_DeckStorage_ query.prepare("select id, name, upload_time from " + servatrice->getDbPrefix() + "_decklist_files where id_folder = :id_folder and user = :user"); query.bindValue(":id_folder", folderId); query.bindValue(":user", QString::fromStdString(userInfo->name())); - if (!servatrice->execSqlQuery(query)) + if (!sqlInterface->execSqlQuery(query)) return false; while (query.next()) { @@ -379,7 +377,7 @@ Response::ResponseCode ServerSocketInterface::cmdDeckList(const Command_DeckList if (authState != PasswordRight) return Response::RespFunctionNotAllowed; - servatrice->checkSql(); + sqlInterface->checkSql(); Response_DeckList *re = new Response_DeckList; ServerInfo_DeckStorage_Folder *root = re->mutable_root(); @@ -396,43 +394,40 @@ Response::ResponseCode ServerSocketInterface::cmdDeckNewDir(const Command_DeckNe if (authState != PasswordRight) return Response::RespFunctionNotAllowed; - servatrice->checkSql(); + sqlInterface->checkSql(); int folderId = getDeckPathId(QString::fromStdString(cmd.path())); if (folderId == -1) return Response::RespNameNotFound; -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("insert into " + servatrice->getDbPrefix() + "_decklist_folders (id_parent, user, name) values(:id_parent, :user, :name)"); query.bindValue(":id_parent", folderId); query.bindValue(":user", QString::fromStdString(userInfo->name())); query.bindValue(":name", QString::fromStdString(cmd.dir_name())); - if (!servatrice->execSqlQuery(query)) + if (!sqlInterface->execSqlQuery(query)) return Response::RespContextError; return Response::RespOk; } void ServerSocketInterface::deckDelDirHelper(int basePathId) { - servatrice->checkSql(); - -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + sqlInterface->checkSql(); + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("select id from " + servatrice->getDbPrefix() + "_decklist_folders where id_parent = :id_parent"); query.bindValue(":id_parent", basePathId); - servatrice->execSqlQuery(query); + sqlInterface->execSqlQuery(query); while (query.next()) deckDelDirHelper(query.value(0).toInt()); query.prepare("delete from " + servatrice->getDbPrefix() + "_decklist_files where id_folder = :id_folder"); query.bindValue(":id_folder", basePathId); - servatrice->execSqlQuery(query); + sqlInterface->execSqlQuery(query); query.prepare("delete from " + servatrice->getDbPrefix() + "_decklist_folders where id = :id"); query.bindValue(":id", basePathId); - servatrice->execSqlQuery(query); + sqlInterface->execSqlQuery(query); } Response::ResponseCode ServerSocketInterface::cmdDeckDelDir(const Command_DeckDelDir &cmd, ResponseContainer & /*rc*/) @@ -440,11 +435,11 @@ Response::ResponseCode ServerSocketInterface::cmdDeckDelDir(const Command_DeckDe if (authState != PasswordRight) return Response::RespFunctionNotAllowed; - servatrice->checkSql(); + sqlInterface->checkSql(); int basePathId = getDeckPathId(QString::fromStdString(cmd.path())); if ((basePathId == -1) || (basePathId == 0)) - return RespNameNotFound; + return Response::RespNameNotFound; deckDelDirHelper(basePathId); return Response::RespOk; } @@ -454,21 +449,19 @@ Response::ResponseCode ServerSocketInterface::cmdDeckDel(const Command_DeckDel & if (authState != PasswordRight) return Response::RespFunctionNotAllowed; - servatrice->checkSql(); - -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + sqlInterface->checkSql(); + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("select id from " + servatrice->getDbPrefix() + "_decklist_files where id = :id and user = :user"); query.bindValue(":id", cmd.deck_id()); query.bindValue(":user", QString::fromStdString(userInfo->name())); - servatrice->execSqlQuery(query); + sqlInterface->execSqlQuery(query); if (!query.next()) return Response::RespNameNotFound; query.prepare("delete from " + servatrice->getDbPrefix() + "_decklist_files where id = :id"); query.bindValue(":id", cmd.deck_id()); - servatrice->execSqlQuery(query); + sqlInterface->execSqlQuery(query); return Response::RespOk; } @@ -481,7 +474,7 @@ Response::ResponseCode ServerSocketInterface::cmdDeckUpload(const Command_DeckUp if (!cmd.has_deck_list()) return Response::RespInvalidData; - servatrice->checkSql(); + sqlInterface->checkSql(); QString deckStr = QString::fromStdString(cmd.deck_list()); DeckList deck(deckStr); @@ -495,14 +488,13 @@ Response::ResponseCode ServerSocketInterface::cmdDeckUpload(const Command_DeckUp if (folderId == -1) return Response::RespNameNotFound; -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("insert into " + servatrice->getDbPrefix() + "_decklist_files (id_folder, user, name, upload_time, content) values(:id_folder, :user, :name, NOW(), :content)"); query.bindValue(":id_folder", folderId); query.bindValue(":user", QString::fromStdString(userInfo->name())); query.bindValue(":name", deckName); query.bindValue(":content", deckStr); - servatrice->execSqlQuery(query); + sqlInterface->execSqlQuery(query); Response_DeckUpload *re = new Response_DeckUpload; ServerInfo_DeckStorage_TreeItem *fileInfo = re->mutable_new_file(); @@ -511,14 +503,13 @@ Response::ResponseCode ServerSocketInterface::cmdDeckUpload(const Command_DeckUp fileInfo->mutable_file()->set_creation_time(QDateTime::currentDateTime().toTime_t()); rc.setResponseExtension(re); } else if (cmd.has_deck_id()) { -// QMutexLocker locker(&servatrice->dbMutex); - QSqlQuery query; + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("update " + servatrice->getDbPrefix() + "_decklist_files set name=:name, upload_time=NOW(), content=:content where id = :id_deck and user = :user"); query.bindValue(":id_deck", cmd.deck_id()); query.bindValue(":user", QString::fromStdString(userInfo->name())); query.bindValue(":name", deckName); query.bindValue(":content", deckStr); - servatrice->execSqlQuery(query); + sqlInterface->execSqlQuery(query); if (query.numRowsAffected() == 0) return Response::RespNameNotFound; @@ -542,7 +533,7 @@ Response::ResponseCode ServerSocketInterface::cmdDeckDownload(const Command_Deck DeckList *deck; try { - deck = servatrice->getDeckFromDatabase(cmd.deck_id(), QString::fromStdString(userInfo->name())); + deck = sqlInterface->getDeckFromDatabase(cmd.deck_id(), QString::fromStdString(userInfo->name())); } catch(Response::ResponseCode r) { return r; } @@ -562,11 +553,10 @@ Response::ResponseCode ServerSocketInterface::cmdReplayList(const Command_Replay Response_ReplayList *re = new Response_ReplayList; -// servatrice->dbMutex.lock(); - QSqlQuery query1; + QSqlQuery query1(sqlInterface->getDatabase()); query1.prepare("select a.id_game, a.replay_name, b.room_name, b.time_started, b.time_finished, b.descr, a.do_not_hide from cockatrice_replays_access a left join cockatrice_games b on b.id = a.id_game where a.id_player = :id_player and (a.do_not_hide = 1 or date_add(b.time_started, interval 7 day) > now())"); query1.bindValue(":id_player", userInfo->id()); - servatrice->execSqlQuery(query1); + sqlInterface->execSqlQuery(query1); while (query1.next()) { ServerInfo_ReplayMatch *matchInfo = re->add_match_list(); @@ -581,25 +571,27 @@ Response::ResponseCode ServerSocketInterface::cmdReplayList(const Command_Replay const QString replayName = query1.value(1).toString(); matchInfo->set_do_not_hide(query1.value(6).toBool()); - QSqlQuery query2; - query2.prepare("select player_name from cockatrice_games_players where id_game = :id_game"); - query2.bindValue(":id_game", gameId); - servatrice->execSqlQuery(query2); - while (query2.next()) - matchInfo->add_player_names(query2.value(0).toString().toStdString()); - - QSqlQuery query3; - query3.prepare("select id, duration from " + servatrice->getDbPrefix() + "_replays where id_game = :id_game"); - query3.bindValue(":id_game", gameId); - servatrice->execSqlQuery(query3); - while (query3.next()) { - ServerInfo_Replay *replayInfo = matchInfo->add_replay_list(); - replayInfo->set_replay_id(query3.value(0).toInt()); - replayInfo->set_replay_name(replayName.toStdString()); - replayInfo->set_duration(query3.value(1).toInt()); + { + QSqlQuery query2(sqlInterface->getDatabase()); + query2.prepare("select player_name from cockatrice_games_players where id_game = :id_game"); + query2.bindValue(":id_game", gameId); + sqlInterface->execSqlQuery(query2); + while (query2.next()) + matchInfo->add_player_names(query2.value(0).toString().toStdString()); + } + { + QSqlQuery query3(sqlInterface->getDatabase()); + query3.prepare("select id, duration from " + servatrice->getDbPrefix() + "_replays where id_game = :id_game"); + query3.bindValue(":id_game", gameId); + sqlInterface->execSqlQuery(query3); + while (query3.next()) { + ServerInfo_Replay *replayInfo = matchInfo->add_replay_list(); + replayInfo->set_replay_id(query3.value(0).toInt()); + replayInfo->set_replay_name(replayName.toStdString()); + replayInfo->set_duration(query3.value(1).toInt()); + } } } -// servatrice->dbMutex.unlock(); rc.setResponseExtension(re); return Response::RespOk; @@ -610,26 +602,26 @@ Response::ResponseCode ServerSocketInterface::cmdReplayDownload(const Command_Re if (authState != PasswordRight) return Response::RespFunctionNotAllowed; -// QMutexLocker dbLocker(&servatrice->dbMutex); + { + QSqlQuery query(sqlInterface->getDatabase()); + query.prepare("select 1 from " + servatrice->getDbPrefix() + "_replays_access a left join " + servatrice->getDbPrefix() + "_replays b on a.id_game = b.id_game where b.id = :id_replay and a.id_player = :id_player"); + query.bindValue(":id_replay", cmd.replay_id()); + query.bindValue(":id_player", userInfo->id()); + if (!sqlInterface->execSqlQuery(query)) + return Response::RespInternalError; + if (!query.next()) + return Response::RespAccessDenied; + } - QSqlQuery query1; - query1.prepare("select 1 from " + servatrice->getDbPrefix() + "_replays_access a left join " + servatrice->getDbPrefix() + "_replays b on a.id_game = b.id_game where b.id = :id_replay and a.id_player = :id_player"); - query1.bindValue(":id_replay", cmd.replay_id()); - query1.bindValue(":id_player", userInfo->id()); - if (!servatrice->execSqlQuery(query1)) + QSqlQuery query(sqlInterface->getDatabase()); + query.prepare("select replay from " + servatrice->getDbPrefix() + "_replays where id = :id_replay"); + query.bindValue(":id_replay", cmd.replay_id()); + if (!sqlInterface->execSqlQuery(query)) return Response::RespInternalError; - if (!query1.next()) - return Response::RespAccessDenied; - - QSqlQuery query2; - query2.prepare("select replay from " + servatrice->getDbPrefix() + "_replays where id = :id_replay"); - query2.bindValue(":id_replay", cmd.replay_id()); - if (!servatrice->execSqlQuery(query2)) - return Response::RespInternalError; - if (!query2.next()) + if (!query.next()) return Response::RespNameNotFound; - QByteArray data = query2.value(0).toByteArray(); + QByteArray data = query.value(0).toByteArray(); Response_ReplayDownload *re = new Response_ReplayDownload; re->set_replay_data(data.data(), data.size()); @@ -643,15 +635,18 @@ Response::ResponseCode ServerSocketInterface::cmdReplayModifyMatch(const Command if (authState != PasswordRight) return Response::RespFunctionNotAllowed; -// QMutexLocker dbLocker(&servatrice->dbMutex); + if (!sqlInterface->checkSql()) + return Response::RespInternalError; - QSqlQuery query1; - query1.prepare("update " + servatrice->getDbPrefix() + "_replays_access set do_not_hide=:do_not_hide where id_player = :id_player and id_game = :id_game"); - query1.bindValue(":id_player", userInfo->id()); - query1.bindValue(":id_game", cmd.game_id()); - query1.bindValue(":do_not_hide", cmd.do_not_hide()); + QSqlQuery query(sqlInterface->getDatabase()); + query.prepare("update " + servatrice->getDbPrefix() + "_replays_access set do_not_hide=:do_not_hide where id_player = :id_player and id_game = :id_game"); + query.bindValue(":id_player", userInfo->id()); + query.bindValue(":id_game", cmd.game_id()); + query.bindValue(":do_not_hide", cmd.do_not_hide()); - return servatrice->execSqlQuery(query1) ? Response::RespOk : Response::RespNameNotFound; + if (!sqlInterface->execSqlQuery(query)) + return Response::RespInternalError; + return query.numRowsAffected() > 0 ? Response::RespOk : Response::RespNameNotFound; } Response::ResponseCode ServerSocketInterface::cmdReplayDeleteMatch(const Command_ReplayDeleteMatch &cmd, ResponseContainer & /*rc*/) @@ -659,15 +654,17 @@ Response::ResponseCode ServerSocketInterface::cmdReplayDeleteMatch(const Command if (authState != PasswordRight) return Response::RespFunctionNotAllowed; -// QMutexLocker dbLocker(&servatrice->dbMutex); + if (!sqlInterface->checkSql()) + return Response::RespInternalError; - QSqlQuery query1; - query1.prepare("delete from " + servatrice->getDbPrefix() + "_replays_access where id_player = :id_player and id_game = :id_game"); - query1.bindValue(":id_player", userInfo->id()); - query1.bindValue(":id_game", cmd.game_id()); + QSqlQuery query(sqlInterface->getDatabase()); + query.prepare("delete from " + servatrice->getDbPrefix() + "_replays_access where id_player = :id_player and id_game = :id_game"); + query.bindValue(":id_player", userInfo->id()); + query.bindValue(":id_game", cmd.game_id()); - servatrice->execSqlQuery(query1); - return query1.numRowsAffected() > 0 ? Response::RespOk: Response::RespNameNotFound; + if (!sqlInterface->execSqlQuery(query)) + return Response::RespInternalError; + return query.numRowsAffected() > 0 ? Response::RespOk : Response::RespNameNotFound; } @@ -676,12 +673,14 @@ Response::ResponseCode ServerSocketInterface::cmdReplayDeleteMatch(const Command Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_BanFromServer &cmd, ResponseContainer & /*rc*/) { + if (!sqlInterface->checkSql()) + return Response::RespInternalError; + QString userName = QString::fromStdString(cmd.user_name()); QString address = QString::fromStdString(cmd.address()); int minutes = cmd.minutes(); -// servatrice->dbMutex.lock(); - QSqlQuery query; + QSqlQuery query(sqlInterface->getDatabase()); query.prepare("insert into " + servatrice->getDbPrefix() + "_bans (user_name, ip_address, id_admin, time_from, minutes, reason, visible_reason) values(:user_name, :ip_address, :id_admin, NOW(), :minutes, :reason, :visible_reason)"); query.bindValue(":user_name", userName); query.bindValue(":ip_address", address); @@ -689,8 +688,7 @@ Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_Ban query.bindValue(":minutes", minutes); query.bindValue(":reason", QString::fromStdString(cmd.reason())); query.bindValue(":visible_reason", QString::fromStdString(cmd.visible_reason())); - servatrice->execSqlQuery(query); -// servatrice->dbMutex.unlock(); + sqlInterface->execSqlQuery(query); QList userList = servatrice->getUsersWithAddressAsList(QHostAddress(address)); ServerSocketInterface *user = static_cast(server->getUsers().value(userName)); diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index 86e063f8..adce9f23 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -60,6 +60,7 @@ signals: private: QMutex outputBufferMutex; Servatrice *servatrice; + Servatrice_DatabaseInterface *sqlInterface; QTcpSocket *socket; QByteArray inputBuffer, outputBuffer;