database interface separated from server, multiple concurrent database connections are now possible

This commit is contained in:
Max-Wilhelm Bruker 2012-05-28 16:32:45 +02:00
parent 2b89c353bf
commit b328c1ed4d
21 changed files with 347 additions and 310 deletions

View file

@ -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

View file

@ -32,10 +32,11 @@
#include "pb/session_event.pb.h"
#include "pb/isl_message.pb.h"
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
Server::Server(QObject *parent)
: QObject(parent), databaseInterface(0), clientsLock(QReadWriteLock::Recursive)
: QObject(parent), clientsLock(QReadWriteLock::Recursive)
{
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
qRegisterMetaType<ServerInfo_Room>("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;

View file

@ -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<int, Server_Room *> &getRooms() { return rooms; }
const QMap<QString, Server_ProtocolHandler *> &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<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &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<Server_ProtocolHandler *> clients;
QMap<qint64, Server_ProtocolHandler *> usersBySessionId;
QMap<QString, Server_ProtocolHandler *> users;
QMap<qint64, Server_AbstractUserInterface *> externalUsersBySessionId;
QMap<QString, Server_AbstractUserInterface *> externalUsers;
QMap<int, Server_Room *> rooms;
QMap<QThread *, Server_DatabaseInterface *> databaseInterfaces;
int getUsersCount() const;
int getGamesCount() const;

View file

@ -1,7 +0,0 @@
#include "server_database_interface.h"
Server_DatabaseInterface::Server_DatabaseInterface()
: nextGameId(0),
nextReplayId(0)
{
}

View file

@ -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<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &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() { }

View file

@ -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<int, Server_Player *> playerIterator(players);
while (playerIterator.hasNext())

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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();

View file

@ -67,7 +67,7 @@ public:
const QMap<QString, ServerInfo_User_Container> &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);