more ISL code, mutex fixes

This commit is contained in:
Max-Wilhelm Bruker 2012-03-12 00:36:44 +01:00
parent 0ae18d7b2e
commit 572e4eaafa
9 changed files with 107 additions and 48 deletions

View file

@ -34,6 +34,8 @@
Server::Server(QObject *parent) Server::Server(QObject *parent)
: QObject(parent), serverMutex(QMutex::Recursive), nextGameId(0), nextReplayId(0) : QObject(parent), serverMutex(QMutex::Recursive), nextGameId(0), nextReplayId(0)
{ {
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room");
} }
Server::~Server() Server::~Server()
@ -170,22 +172,22 @@ void Server::externalUserLeft(QString userName)
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
} }
void Server::broadcastRoomUpdate() void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl)
{ {
QMutexLocker locker(&serverMutex);
Server_Room *room = static_cast<Server_Room *>(sender());
Event_ListRooms event; Event_ListRooms event;
event.add_room_list()->CopyFrom(roomInfo);
ServerInfo_Room *roomInfo = event.add_room_list();
room->roomMutex.lock();
roomInfo->CopyFrom(room->getInfo(false, false, true));
room->roomMutex.unlock();
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
serverMutex.lock();
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsRoomListChanges()) if (clients[i]->getAcceptsRoomListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
serverMutex.unlock();
if (sendToIsl)
sendIslMessage(*se);
delete se; delete se;
} }
@ -193,7 +195,7 @@ void Server::addRoom(Server_Room *newRoom)
{ {
QMutexLocker locker(&serverMutex); QMutexLocker locker(&serverMutex);
rooms.insert(newRoom->getId(), newRoom); rooms.insert(newRoom->getId(), newRoom);
connect(newRoom, SIGNAL(roomInfoChanged()), this, SLOT(broadcastRoomUpdate())); connect(newRoom, SIGNAL(roomInfoChanged(ServerInfo_Room)), this, SLOT(broadcastRoomUpdate(const ServerInfo_Room &)), Qt::QueuedConnection);
} }
int Server::getUsersCount() const int Server::getUsersCount() const

View file

@ -6,6 +6,7 @@
#include <QMap> #include <QMap>
#include <QMutex> #include <QMutex>
#include "pb/serverinfo_user.pb.h" #include "pb/serverinfo_user.pb.h"
#include "pb/serverinfo_room.pb.h"
class Server_Game; class Server_Game;
class Server_Room; class Server_Room;
@ -26,7 +27,7 @@ class Server : public QObject
signals: signals:
void pingClockTimeout(); void pingClockTimeout();
private slots: private slots:
void broadcastRoomUpdate(); void broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl = false);
public: public:
mutable QMutex serverMutex; mutable QMutex serverMutex;
Server(QObject *parent = 0); Server(QObject *parent = 0);
@ -68,6 +69,7 @@ public:
protected slots: protected slots:
void externalUserJoined(ServerInfo_User userInfo); void externalUserJoined(ServerInfo_User userInfo);
void externalUserLeft(QString userName); void externalUserLeft(QString userName);
void externalRoomUpdated(ServerInfo_Room roomInfo);
protected: protected:
void prepareDestroy(); void prepareDestroy();
QList<Server_ProtocolHandler *> clients; QList<Server_ProtocolHandler *> clients;

View file

@ -271,7 +271,7 @@ void Server_Game::doStartGameIfReady()
nextTurn(); nextTurn();
locker.unlock(); locker.unlock();
room->broadcastGameListUpdate(this); emit gameInfoChanged(getInfo());
} }
void Server_Game::startGameIfReady() void Server_Game::startGameIfReady()
@ -364,7 +364,7 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec
} }
if (broadcastUpdate) if (broadcastUpdate)
room->broadcastGameListUpdate(this); emit gameInfoChanged(getInfo());
return newPlayer; return newPlayer;
} }
@ -409,7 +409,7 @@ void Server_Game::removePlayer(Server_Player *player)
if (gameStarted && playerActive) if (gameStarted && playerActive)
nextTurn(); nextTurn();
} }
room->broadcastGameListUpdate(this); emit gameInfoChanged(getInfo());
} }
void Server_Game::removeArrowsToPlayer(GameEventStorage &ges, Server_Player *player) void Server_Game::removeArrowsToPlayer(GameEventStorage &ges, Server_Player *player)

View file

@ -67,6 +67,7 @@ private:
GameReplay *currentReplay; GameReplay *currentReplay;
signals: signals:
void sigStartGameIfReady(); void sigStartGameIfReady();
void gameInfoChanged(ServerInfo_Game gameInfo);
private slots: private slots:
void pingClockTimeout(); void pingClockTimeout();
void doStartGameIfReady(); void doStartGameIfReady();

View file

@ -695,11 +695,16 @@ Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_Creat
QString description = QString::fromStdString(cmd.description()); QString description = QString::fromStdString(cmd.description());
if (description.size() > 60) if (description.size() > 60)
description = description.left(60); description = description.left(60);
Server_Game *game = room->createGame(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(), this);
Server_Game *game = new Server_Game(this, 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);
game->moveToThread(room->thread());
QMutexLocker gameListLocker(&gameListMutex);
game->gameMutex.lock();
room->addGame(game);
Server_Player *creator = game->getPlayers().values().first(); Server_Player *creator = game->getPlayers().values().first();
QMutexLocker gameListLocker(&gameListMutex);
games.insert(game->getGameId(), QPair<Server_Game *, Server_Player *>(game, creator)); games.insert(game->getGameId(), QPair<Server_Game *, Server_Player *>(game, creator));
Event_GameJoined event1; Event_GameJoined event1;

View file

@ -12,6 +12,7 @@
Server_Room::Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent) Server_Room::Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent)
: QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage), gameTypes(_gameTypes), roomMutex(QMutex::Recursive) : QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage), gameTypes(_gameTypes), roomMutex(QMutex::Recursive)
{ {
connect(this, SIGNAL(gameListChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)), Qt::QueuedConnection);
} }
Server_Room::~Server_Room() Server_Room::~Server_Room()
@ -32,14 +33,14 @@ Server *Server_Room::getServer() const
return static_cast<Server *>(parent()); return static_cast<Server *>(parent());
} }
ServerInfo_Room Server_Room::getInfo(bool complete, bool showGameTypes, bool updating) const ServerInfo_Room Server_Room::getInfo(bool complete, bool showGameTypes, bool updating, bool includeExternalData) const
{ {
QMutexLocker locker(&roomMutex); QMutexLocker locker(&roomMutex);
ServerInfo_Room result; ServerInfo_Room result;
result.set_room_id(id); result.set_room_id(id);
result.set_game_count(games.size()); result.set_game_count(games.size() + externalGames.size());
result.set_player_count(userList.size()); result.set_player_count(userList.size() + externalUsers.size());
if (!updating) { if (!updating) {
result.set_name(name.toStdString()); result.set_name(name.toStdString());
@ -51,9 +52,19 @@ ServerInfo_Room Server_Room::getInfo(bool complete, bool showGameTypes, bool upd
QMapIterator<int, Server_Game *> gameIterator(games); QMapIterator<int, Server_Game *> gameIterator(games);
while (gameIterator.hasNext()) while (gameIterator.hasNext())
result.add_game_list()->CopyFrom(gameIterator.next().value()->getInfo()); result.add_game_list()->CopyFrom(gameIterator.next().value()->getInfo());
if (includeExternalData) {
QMapIterator<int, ServerInfo_Game> externalGameIterator(externalGames);
while (externalGameIterator.hasNext())
result.add_game_list()->CopyFrom(externalGameIterator.next().value());
}
for (int i = 0; i < userList.size(); ++i) for (int i = 0; i < userList.size(); ++i)
result.add_user_list()->CopyFrom(userList[i]->copyUserInfo(false)); result.add_user_list()->CopyFrom(userList[i]->copyUserInfo(false));
if (includeExternalData) {
QMapIterator<QString, ServerInfo_User_Container> externalUserIterator(externalUsers);
while (externalUserIterator.hasNext())
result.add_user_list()->CopyFrom(externalUserIterator.next().value().copyUserInfo(false));
}
} }
if (complete || showGameTypes) if (complete || showGameTypes)
for (int i = 0; i < gameTypes.size(); ++i) { for (int i = 0; i < gameTypes.size(); ++i) {
@ -83,7 +94,7 @@ void Server_Room::addClient(Server_ProtocolHandler *client)
userList.append(client); userList.append(client);
roomMutex.unlock(); roomMutex.unlock();
emit roomInfoChanged(); emit roomInfoChanged(getInfo(false, false, true));
} }
void Server_Room::removeClient(Server_ProtocolHandler *client) void Server_Room::removeClient(Server_ProtocolHandler *client)
@ -96,7 +107,34 @@ void Server_Room::removeClient(Server_ProtocolHandler *client)
event.set_name(client->getUserInfo()->name()); event.set_name(client->getUserInfo()->name());
sendRoomEvent(prepareRoomEvent(event)); sendRoomEvent(prepareRoomEvent(event));
emit roomInfoChanged(); emit roomInfoChanged(getInfo(false, false, true));
}
void Server_Room::addExternalUser(const ServerInfo_User &userInfo)
{
ServerInfo_User_Container userInfoContainer(userInfo);
Event_JoinRoom event;
event.mutable_user_info()->CopyFrom(userInfoContainer.copyUserInfo(false));
sendRoomEvent(prepareRoomEvent(event), false);
roomMutex.lock();
externalUsers.insert(QString::fromStdString(userInfo.name()), userInfoContainer);
roomMutex.unlock();
emit roomInfoChanged(getInfo(false, false, true));
}
void Server_Room::removeExternalUser(const QString &name)
{
roomMutex.lock();
externalUsers.remove(name);
roomMutex.unlock();
Event_LeaveRoom event;
event.set_name(name.toStdString());
sendRoomEvent(prepareRoomEvent(event), false);
emit roomInfoChanged(getInfo(false, false, true));
} }
void Server_Room::say(Server_ProtocolHandler *client, const QString &s) void Server_Room::say(Server_ProtocolHandler *client, const QString &s)
@ -107,39 +145,34 @@ void Server_Room::say(Server_ProtocolHandler *client, const QString &s)
sendRoomEvent(prepareRoomEvent(event)); sendRoomEvent(prepareRoomEvent(event));
} }
void Server_Room::sendRoomEvent(RoomEvent *event) void Server_Room::sendRoomEvent(RoomEvent *event, bool sendToIsl)
{ {
QMutexLocker locker(&roomMutex); roomMutex.lock();
for (int i = 0; i < userList.size(); ++i) for (int i = 0; i < userList.size(); ++i)
userList[i]->sendProtocolItem(*event); userList[i]->sendProtocolItem(*event);
roomMutex.unlock();
if (sendToIsl)
static_cast<Server *>(parent())->sendIslMessage(*event);
delete event; delete event;
} }
void Server_Room::broadcastGameListUpdate(Server_Game *game) void Server_Room::broadcastGameListUpdate(ServerInfo_Game gameInfo)
{ {
QMutexLocker locker(&roomMutex);
Event_ListGames event; Event_ListGames event;
event.add_game_list()->CopyFrom(game->getInfo()); event.add_game_list()->CopyFrom(gameInfo);
sendRoomEvent(prepareRoomEvent(event)); sendRoomEvent(prepareRoomEvent(event));
} }
Server_Game *Server_Room::createGame(const QString &description, const QString &password, int maxPlayers, const QList<int> &gameTypes, bool onlyBuddies, bool onlyRegistered, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator) void Server_Room::addGame(Server_Game *game)
{ {
QMutexLocker locker(&roomMutex); // Lock roomMutex and gameMutex before calling this
Server_Game *newGame = new Server_Game(creator, static_cast<Server *>(parent())->getNextGameId(), description, password, maxPlayers, gameTypes, onlyBuddies, onlyRegistered, spectatorsAllowed, spectatorsNeedPassword, spectatorsCanTalk, spectatorsSeeEverything, this); connect(game, SIGNAL(gameInfoChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)));
newGame->moveToThread(thread()); games.insert(game->getGameId(), game);
// This mutex needs to be unlocked by the caller. emit gameListChanged(game->getInfo());
newGame->gameMutex.lock(); emit roomInfoChanged(getInfo(false, false, true));
games.insert(newGame->getGameId(), newGame);
broadcastGameListUpdate(newGame);
emit roomInfoChanged();
return newGame;
} }
void Server_Room::removeGame(Server_Game *game) void Server_Room::removeGame(Server_Game *game)
@ -147,10 +180,11 @@ void Server_Room::removeGame(Server_Game *game)
// No need to lock roomMutex or gameMutex. This method is only // No need to lock roomMutex or gameMutex. This method is only
// called from ~Server_Game, which locks both mutexes anyway beforehand. // called from ~Server_Game, which locks both mutexes anyway beforehand.
broadcastGameListUpdate(game); disconnect(game, 0, this, 0);
emit gameListChanged(game->getInfo());
games.remove(game->getGameId()); games.remove(game->getGameId());
emit roomInfoChanged(); emit roomInfoChanged(getInfo(false, false, true));
} }
int Server_Room::getGamesCreatedByUser(const QString &userName) const int Server_Room::getGamesCreatedByUser(const QString &userName) const

View file

@ -6,7 +6,9 @@
#include <QObject> #include <QObject>
#include <QStringList> #include <QStringList>
#include <QMutex> #include <QMutex>
#include <QMetaType>
#include "pb/serverinfo_room.pb.h" #include "pb/serverinfo_room.pb.h"
#include "serverinfo_user_container.h"
class Server_ProtocolHandler; class Server_ProtocolHandler;
class RoomEvent; class RoomEvent;
@ -19,7 +21,8 @@ class Server;
class Server_Room : public QObject { class Server_Room : public QObject {
Q_OBJECT Q_OBJECT
signals: signals:
void roomInfoChanged(); void roomInfoChanged(ServerInfo_Room roomInfo);
void gameListChanged(ServerInfo_Game gameInfo);
private: private:
int id; int id;
QString name; QString name;
@ -28,7 +31,11 @@ private:
QString joinMessage; QString joinMessage;
QStringList gameTypes; QStringList gameTypes;
QMap<int, Server_Game *> games; QMap<int, Server_Game *> games;
QMap<int, ServerInfo_Game> externalGames;
QList<Server_ProtocolHandler *> userList; QList<Server_ProtocolHandler *> userList;
QMap<QString, ServerInfo_User_Container> externalUsers;
private slots:
void broadcastGameListUpdate(ServerInfo_Game gameInfo);
public: public:
mutable QMutex roomMutex; mutable QMutex roomMutex;
Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent); Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent);
@ -41,19 +48,26 @@ public:
const QStringList &getGameTypes() const { return gameTypes; } const QStringList &getGameTypes() const { return gameTypes; }
const QMap<int, Server_Game *> &getGames() const { return games; } const QMap<int, Server_Game *> &getGames() const { return games; }
Server *getServer() const; Server *getServer() const;
ServerInfo_Room getInfo(bool complete, bool showGameTypes = false, bool updating = false) const; ServerInfo_Room getInfo(bool complete, bool showGameTypes = false, bool updating = false, bool includeExternalData = true) const;
int getGamesCreatedByUser(const QString &name) const; int getGamesCreatedByUser(const QString &name) const;
QList<ServerInfo_Game> getGamesOfUser(const QString &name) const; QList<ServerInfo_Game> getGamesOfUser(const QString &name) const;
void addClient(Server_ProtocolHandler *client); void addClient(Server_ProtocolHandler *client);
void removeClient(Server_ProtocolHandler *client); void removeClient(Server_ProtocolHandler *client);
void addExternalUser(const ServerInfo_User &userInfo);
void removeExternalUser(const QString &name);
void say(Server_ProtocolHandler *client, const QString &s); void say(Server_ProtocolHandler *client, const QString &s);
void broadcastGameListUpdate(Server_Game *game);
Server_Game *createGame(const QString &description, const QString &password, int maxPlayers, const QList<int> &_gameTypes, bool onlyBuddies, bool onlyRegistered, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator); void addGame(Server_Game *game);
void removeGame(Server_Game *game); void removeGame(Server_Game *game);
void sendRoomEvent(RoomEvent *event); void sendRoomEvent(RoomEvent *event, bool sendToIsl = true);
RoomEvent *prepareRoomEvent(const ::google::protobuf::Message &roomEvent); RoomEvent *prepareRoomEvent(const ::google::protobuf::Message &roomEvent);
}; };
Q_DECLARE_METATYPE(ServerInfo_Game)
Q_DECLARE_METATYPE(ServerInfo_Room)
#endif #endif

View file

@ -107,7 +107,7 @@ void IslInterface::initServer()
while (roomIterator.hasNext()) { while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value(); Server_Room *room = roomIterator.next().value();
room->roomMutex.lock(); room->roomMutex.lock();
event.add_room_list()->CopyFrom(room->getInfo(true, true, false)); event.add_room_list()->CopyFrom(room->getInfo(true, true, false, false));
} }
IslMessage message; IslMessage message;

View file

@ -856,6 +856,7 @@ void Servatrice::addIslInterface(int serverId, IslInterface *interface)
islInterfaces.insert(serverId, interface); islInterfaces.insert(serverId, interface);
connect(interface, SIGNAL(externalUserJoined(ServerInfo_User)), this, SLOT(externalUserJoined(ServerInfo_User))); connect(interface, SIGNAL(externalUserJoined(ServerInfo_User)), this, SLOT(externalUserJoined(ServerInfo_User)));
connect(interface, SIGNAL(externalUserLeft(QString)), this, SLOT(externalUserLeft(QString))); connect(interface, SIGNAL(externalUserLeft(QString)), this, SLOT(externalUserLeft(QString)));
connect(interface, SIGNAL(externalRoomUpdated(ServerInfo_Room)), this, SLOT(externalRoomUpdated(const ServerInfo_Room &)));
} }
void Servatrice::removeIslInterface(int serverId) void Servatrice::removeIslInterface(int serverId)