1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Send error messages if operation fails

This commit is contained in:
Ivan Savenko
2024-02-02 00:12:30 +02:00
parent c5c46a7c9a
commit c9ebf32efd
8 changed files with 77 additions and 48 deletions

View File

@ -45,8 +45,8 @@ void GlobalLobbyClient::onPacketReceived(const std::shared_ptr<INetworkConnectio
if(json["type"].String() == "accountCreated") if(json["type"].String() == "accountCreated")
return receiveAccountCreated(json); return receiveAccountCreated(json);
if(json["type"].String() == "loginFailed") if(json["type"].String() == "operationFailed")
return receiveLoginFailed(json); return receiveOperationFailed(json);
if(json["type"].String() == "loginSuccess") if(json["type"].String() == "loginSuccess")
return receiveLoginSuccess(json); return receiveLoginSuccess(json);
@ -90,7 +90,7 @@ void GlobalLobbyClient::receiveAccountCreated(const JsonNode & json)
sendClientLogin(); sendClientLogin();
} }
void GlobalLobbyClient::receiveLoginFailed(const JsonNode & json) void GlobalLobbyClient::receiveOperationFailed(const JsonNode & json)
{ {
auto loginWindowPtr = loginWindow.lock(); auto loginWindowPtr = loginWindow.lock();

View File

@ -39,7 +39,7 @@ class GlobalLobbyClient final : public INetworkClientListener, boost::noncopyabl
void sendClientLogin(); void sendClientLogin();
void receiveAccountCreated(const JsonNode & json); void receiveAccountCreated(const JsonNode & json);
void receiveLoginFailed(const JsonNode & json); void receiveOperationFailed(const JsonNode & json);
void receiveLoginSuccess(const JsonNode & json); void receiveLoginSuccess(const JsonNode & json);
void receiveChatHistory(const JsonNode & json); void receiveChatHistory(const JsonNode & json);
void receiveChatMessage(const JsonNode & json); void receiveChatMessage(const JsonNode & json);

View File

@ -79,6 +79,24 @@ void LobbyDatabase::createTables()
database->prepare(createTableGameRoomInvites)->execute(); database->prepare(createTableGameRoomInvites)->execute();
} }
void LobbyDatabase::clearOldData()
{
static const std::string removeActiveAccounts = R"(
UPDATE accounts
SET online = 0
WHERE online <> 0
)";
static const std::string removeActiveRooms = R"(
UPDATE gameRooms
SET status = 5
WHERE status <> 5
)";
database->prepare(removeActiveAccounts)->execute();
database->prepare(removeActiveRooms)->execute();
}
void LobbyDatabase::prepareStatements() void LobbyDatabase::prepareStatements()
{ {
// INSERT INTO // INSERT INTO
@ -276,6 +294,7 @@ LobbyDatabase::LobbyDatabase(const boost::filesystem::path & databasePath)
{ {
database = SQLiteInstance::open(databasePath, true); database = SQLiteInstance::open(databasePath, true);
createTables(); createTables();
clearOldData();
prepareStatements(); prepareStatements();
} }

View File

@ -54,6 +54,7 @@ class LobbyDatabase
void prepareStatements(); void prepareStatements();
void createTables(); void createTables();
void clearOldData();
public: public:
explicit LobbyDatabase(const boost::filesystem::path & databasePath); explicit LobbyDatabase(const boost::filesystem::path & databasePath);

View File

@ -90,10 +90,10 @@ void LobbyServer::sendInviteReceived(const NetworkConnectionPtr & target, const
sendMessage(target, reply); sendMessage(target, reply);
} }
void LobbyServer::sendLoginFailed(const NetworkConnectionPtr & target, const std::string & reason) void LobbyServer::sendOperationFailed(const NetworkConnectionPtr & target, const std::string & reason)
{ {
JsonNode reply; JsonNode reply;
reply["type"].String() = "loginFailed"; reply["type"].String() = "operationFailed";
reply["reason"].String() = reason; reply["reason"].String() = reason;
sendMessage(target, reply); sendMessage(target, reply);
} }
@ -161,7 +161,6 @@ JsonNode LobbyServer::prepareActiveGameRooms()
jsonEntry["hostAccountID"].String() = gameRoom.hostAccountID; jsonEntry["hostAccountID"].String() = gameRoom.hostAccountID;
jsonEntry["hostAccountDisplayName"].String() = gameRoom.hostAccountDisplayName; jsonEntry["hostAccountDisplayName"].String() = gameRoom.hostAccountDisplayName;
jsonEntry["description"].String() = "TODO: ROOM DESCRIPTION"; jsonEntry["description"].String() = "TODO: ROOM DESCRIPTION";
// jsonEntry["status"].String() = gameRoom.roomStatus;
jsonEntry["playersCount"].Integer() = gameRoom.playersCount; jsonEntry["playersCount"].Integer() = gameRoom.playersCount;
jsonEntry["playersLimit"].Integer() = gameRoom.playersLimit; jsonEntry["playersLimit"].Integer() = gameRoom.playersLimit;
reply["gameRooms"].Vector().push_back(jsonEntry); reply["gameRooms"].Vector().push_back(jsonEntry);
@ -240,7 +239,7 @@ void LobbyServer::onPacketReceived(const NetworkConnectionPtr & connection, cons
if(lockedPtr) if(lockedPtr)
return lockedPtr->sendPacket(message); return lockedPtr->sendPacket(message);
throw std::runtime_error("Received unexpected message for inactive proxy!"); logGlobal->info("Received unexpected message for inactive proxy!");
} }
JsonNode json(message.data(), message.size()); JsonNode json(message.data(), message.size());
@ -248,56 +247,60 @@ void LobbyServer::onPacketReceived(const NetworkConnectionPtr & connection, cons
// TODO: check for json parsing errors // TODO: check for json parsing errors
// TODO: validate json based on received message type // TODO: validate json based on received message type
std::string messageType = json["type"].String();
// communication messages from vcmiclient // communication messages from vcmiclient
if(activeAccounts.count(connection)) if(activeAccounts.count(connection))
{ {
if(json["type"].String() == "sendChatMessage") if(messageType == "sendChatMessage")
return receiveSendChatMessage(connection, json); return receiveSendChatMessage(connection, json);
if(json["type"].String() == "openGameRoom") if(messageType == "openGameRoom")
return receiveOpenGameRoom(connection, json); return receiveOpenGameRoom(connection, json);
if(json["type"].String() == "joinGameRoom") if(messageType == "joinGameRoom")
return receiveJoinGameRoom(connection, json); return receiveJoinGameRoom(connection, json);
if(json["type"].String() == "sendInvite") if(messageType == "sendInvite")
return receiveSendInvite(connection, json); return receiveSendInvite(connection, json);
if(json["type"].String() == "declineInvite") if(messageType == "declineInvite")
return receiveDeclineInvite(connection, json); return receiveDeclineInvite(connection, json);
throw std::runtime_error("Received unexpected message of type " + json["type"].String()); logGlobal->info("Received unexpected message of type %s from account %s", messageType, activeAccounts.at(connection).accountID);
return;
} }
// communication messages from vcmiserver // communication messages from vcmiserver
if(activeGameRooms.count(connection)) if(activeGameRooms.count(connection))
{ {
if(json["type"].String() == "leaveGameRoom") if(messageType == "leaveGameRoom")
return receiveLeaveGameRoom(connection, json); return receiveLeaveGameRoom(connection, json);
throw std::runtime_error("Received unexpected message of type " + json["type"].String()); logGlobal->info("Received unexpected message of type %s from game room %s", messageType, activeGameRooms.at(connection).roomID);
return;
} }
// unauthorized connections - permit only login or register attempts // unauthorized connections - permit only login or register attempts
if(json["type"].String() == "clientLogin") if(messageType == "clientLogin")
return receiveClientLogin(connection, json); return receiveClientLogin(connection, json);
if(json["type"].String() == "clientRegister") if(messageType == "clientRegister")
return receiveClientRegister(connection, json); return receiveClientRegister(connection, json);
if(json["type"].String() == "serverLogin") if(messageType == "serverLogin")
return receiveServerLogin(connection, json); return receiveServerLogin(connection, json);
if(json["type"].String() == "clientProxyLogin") if(messageType == "clientProxyLogin")
return receiveClientProxyLogin(connection, json); return receiveClientProxyLogin(connection, json);
if(json["type"].String() == "serverProxyLogin") if(messageType == "serverProxyLogin")
return receiveServerProxyLogin(connection, json); return receiveServerProxyLogin(connection, json);
// TODO: add logging of suspicious connections. // TODO: add logging of suspicious connections.
networkServer->closeConnection(connection); networkServer->closeConnection(connection);
throw std::runtime_error("Received unexpected message of type " + json["type"].String()); logGlobal->info("Received unexpected message of type %s from not authorised account!", messageType);
} }
void LobbyServer::receiveSendChatMessage(const NetworkConnectionPtr & connection, const JsonNode & json) void LobbyServer::receiveSendChatMessage(const NetworkConnectionPtr & connection, const JsonNode & json)
@ -308,7 +311,7 @@ void LobbyServer::receiveSendChatMessage(const NetworkConnectionPtr & connection
std::string displayName = database->getAccountDisplayName(accountID); std::string displayName = database->getAccountDisplayName(accountID);
if(messageTextClean.empty()) if(messageTextClean.empty())
return; return sendOperationFailed(connection, "No printable characters in sent message!");
database->insertChatMessage(accountID, "global", "english", messageText); database->insertChatMessage(accountID, "global", "english", messageText);
@ -322,10 +325,10 @@ void LobbyServer::receiveClientRegister(const NetworkConnectionPtr & connection,
std::string language = json["language"].String(); std::string language = json["language"].String();
if(isAccountNameValid(displayName)) if(isAccountNameValid(displayName))
return sendLoginFailed(connection, "Illegal account name"); return sendOperationFailed(connection, "Illegal account name");
if(database->isAccountNameExists(displayName)) if(database->isAccountNameExists(displayName))
return sendLoginFailed(connection, "Account name already in use"); return sendOperationFailed(connection, "Account name already in use");
std::string accountCookie = boost::uuids::to_string(boost::uuids::random_generator()()); std::string accountCookie = boost::uuids::to_string(boost::uuids::random_generator()());
std::string accountID = boost::uuids::to_string(boost::uuids::random_generator()()); std::string accountID = boost::uuids::to_string(boost::uuids::random_generator()());
@ -344,12 +347,12 @@ void LobbyServer::receiveClientLogin(const NetworkConnectionPtr & connection, co
std::string version = json["version"].String(); std::string version = json["version"].String();
if(!database->isAccountIDExists(accountID)) if(!database->isAccountIDExists(accountID))
return sendLoginFailed(connection, "Account not found"); return sendOperationFailed(connection, "Account not found");
auto clientCookieStatus = database->getAccountCookieStatus(accountID, accountCookie, accountCookieLifetime); auto clientCookieStatus = database->getAccountCookieStatus(accountID, accountCookie, accountCookieLifetime);
if(clientCookieStatus == LobbyCookieStatus::INVALID) if(clientCookieStatus == LobbyCookieStatus::INVALID)
return sendLoginFailed(connection, "Authentification failure"); return sendOperationFailed(connection, "Authentification failure");
// prolong existing cookie // prolong existing cookie
database->updateAccessCookie(accountID, accountCookie); database->updateAccessCookie(accountID, accountCookie);
@ -383,16 +386,15 @@ void LobbyServer::receiveServerLogin(const NetworkConnectionPtr & connection, co
if(clientCookieStatus == LobbyCookieStatus::INVALID) if(clientCookieStatus == LobbyCookieStatus::INVALID)
{ {
sendLoginFailed(connection, "Invalid credentials"); sendOperationFailed(connection, "Invalid credentials");
} }
else else
{ {
database->insertGameRoom(gameRoomID, accountID); database->insertGameRoom(gameRoomID, accountID);
activeGameRooms[connection].roomID = gameRoomID; activeGameRooms[connection].roomID = gameRoomID;
sendLoginSuccess(connection, accountCookie, {}); sendLoginSuccess(connection, accountCookie, {});
}
broadcastActiveGameRooms(); broadcastActiveGameRooms();
}
} }
void LobbyServer::receiveClientProxyLogin(const NetworkConnectionPtr & connection, const JsonNode & json) void LobbyServer::receiveClientProxyLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
@ -425,6 +427,7 @@ void LobbyServer::receiveClientProxyLogin(const NetworkConnectionPtr & connectio
} }
} }
sendOperationFailed(connection, "Invalid credentials");
networkServer->closeConnection(connection); networkServer->closeConnection(connection);
} }
@ -442,7 +445,10 @@ void LobbyServer::receiveServerProxyLogin(const NetworkConnectionPtr & connectio
NetworkConnectionPtr targetAccount = findAccount(guestAccountID); NetworkConnectionPtr targetAccount = findAccount(guestAccountID);
if(targetAccount == nullptr) if(targetAccount == nullptr)
{
sendOperationFailed(connection, "Invalid credentials");
return; // unknown / disconnected account return; // unknown / disconnected account
}
sendJoinRoomSuccess(targetAccount, gameRoomID, true); sendJoinRoomSuccess(targetAccount, gameRoomID, true);
@ -463,13 +469,16 @@ void LobbyServer::receiveOpenGameRoom(const NetworkConnectionPtr & connection, c
std::string accountID = activeAccounts[connection].accountID; std::string accountID = activeAccounts[connection].accountID;
if(database->isPlayerInGameRoom(accountID)) if(database->isPlayerInGameRoom(accountID))
return; // only 1 room per player allowed return sendOperationFailed(connection, "Player already in the room!");
std::string gameRoomID = database->getIdleGameRoom(hostAccountID); std::string gameRoomID = database->getIdleGameRoom(hostAccountID);
if(gameRoomID.empty()) if(gameRoomID.empty())
return; return sendOperationFailed(connection, "Failed to find idle server to join!");
std::string roomType = json["roomType"].String(); std::string roomType = json["roomType"].String();
if(roomType != "public" && roomType != "private")
return sendOperationFailed(connection, "Invalid room type!");
if(roomType == "public") if(roomType == "public")
database->setGameRoomStatus(gameRoomID, LobbyRoomState::PUBLIC); database->setGameRoomStatus(gameRoomID, LobbyRoomState::PUBLIC);
if(roomType == "private") if(roomType == "private")
@ -489,26 +498,26 @@ void LobbyServer::receiveJoinGameRoom(const NetworkConnectionPtr & connection, c
std::string accountID = activeAccounts[connection].accountID; std::string accountID = activeAccounts[connection].accountID;
if(database->isPlayerInGameRoom(accountID)) if(database->isPlayerInGameRoom(accountID))
return; // only 1 room per player allowed return sendOperationFailed(connection, "Player already in the room!");
NetworkConnectionPtr targetRoom = findGameRoom(gameRoomID); NetworkConnectionPtr targetRoom = findGameRoom(gameRoomID);
if(targetRoom == nullptr) if(targetRoom == nullptr)
return; // unknown / disconnected room return sendOperationFailed(connection, "Failed to find game room to join!");
auto roomStatus = database->getGameRoomStatus(gameRoomID); auto roomStatus = database->getGameRoomStatus(gameRoomID);
if(roomStatus != LobbyRoomState::PRIVATE && roomStatus != LobbyRoomState::PUBLIC) if(roomStatus != LobbyRoomState::PRIVATE && roomStatus != LobbyRoomState::PUBLIC)
return; return sendOperationFailed(connection, "Room does not accepts new players!");
if(roomStatus == LobbyRoomState::PRIVATE) if(roomStatus == LobbyRoomState::PRIVATE)
{ {
if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::INVITED) if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::INVITED)
return; return sendOperationFailed(connection, "You are not permitted to join private room without invite!");
} }
if(database->getGameRoomFreeSlots(gameRoomID) == 0) if(database->getGameRoomFreeSlots(gameRoomID) == 0)
return; return sendOperationFailed(connection, "Room is already full!");
database->insertPlayerIntoGameRoom(accountID, gameRoomID); database->insertPlayerIntoGameRoom(accountID, gameRoomID);
sendAccountJoinsRoom(targetRoom, accountID); sendAccountJoinsRoom(targetRoom, accountID);
@ -523,7 +532,7 @@ void LobbyServer::receiveLeaveGameRoom(const NetworkConnectionPtr & connection,
std::string senderName = activeAccounts[connection].accountID; std::string senderName = activeAccounts[connection].accountID;
if(!database->isPlayerInGameRoom(senderName, gameRoomID)) if(!database->isPlayerInGameRoom(senderName, gameRoomID))
return; return sendOperationFailed(connection, "You are not in the room!");
broadcastActiveGameRooms(); broadcastActiveGameRooms();
} }
@ -537,16 +546,16 @@ void LobbyServer::receiveSendInvite(const NetworkConnectionPtr & connection, con
auto targetAccount = findAccount(accountID); auto targetAccount = findAccount(accountID);
if(!targetAccount) if(!targetAccount)
return; // target player does not exists or offline return sendOperationFailed(connection, "Invalid account to invite!");
if(!database->isPlayerInGameRoom(senderName)) if(!database->isPlayerInGameRoom(senderName))
return; // current player is not in room return sendOperationFailed(connection, "You are not in the room!");
if(database->isPlayerInGameRoom(accountID)) if(database->isPlayerInGameRoom(accountID))
return; // target player is busy return sendOperationFailed(connection, "This player is already in a room!");
if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::NOT_INVITED) if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::NOT_INVITED)
return; // already has invite return sendOperationFailed(connection, "This player is already invited!");
database->insertGameRoomInvite(accountID, gameRoomID); database->insertGameRoomInvite(accountID, gameRoomID);
sendInviteReceived(targetAccount, senderName, gameRoomID); sendInviteReceived(targetAccount, senderName, gameRoomID);
@ -558,7 +567,7 @@ void LobbyServer::receiveDeclineInvite(const NetworkConnectionPtr & connection,
std::string gameRoomID = json["gameRoomID"].String(); std::string gameRoomID = json["gameRoomID"].String();
if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::INVITED) if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::INVITED)
return; // already has invite return sendOperationFailed(connection, "No active invite found!");
database->deleteGameRoomInvite(accountID, gameRoomID); database->deleteGameRoomInvite(accountID, gameRoomID);
} }

View File

@ -74,7 +74,7 @@ class LobbyServer : public INetworkServerListener
void sendChatMessage(const NetworkConnectionPtr & target, const std::string & roomMode, const std::string & roomName, const std::string & accountID, const std::string & displayName, const std::string & messageText); void sendChatMessage(const NetworkConnectionPtr & target, const std::string & roomMode, const std::string & roomName, const std::string & accountID, const std::string & displayName, const std::string & messageText);
void sendAccountCreated(const NetworkConnectionPtr & target, const std::string & accountID, const std::string & accountCookie); void sendAccountCreated(const NetworkConnectionPtr & target, const std::string & accountID, const std::string & accountCookie);
void sendLoginFailed(const NetworkConnectionPtr & target, const std::string & reason); void sendOperationFailed(const NetworkConnectionPtr & target, const std::string & reason);
void sendLoginSuccess(const NetworkConnectionPtr & target, const std::string & accountCookie, const std::string & displayName); void sendLoginSuccess(const NetworkConnectionPtr & target, const std::string & accountCookie, const std::string & displayName);
void sendChatHistory(const NetworkConnectionPtr & target, const std::vector<LobbyChatMessage> &); void sendChatHistory(const NetworkConnectionPtr & target, const std::vector<LobbyChatMessage> &);
void sendAccountJoinsRoom(const NetworkConnectionPtr & target, const std::string & accountID); void sendAccountJoinsRoom(const NetworkConnectionPtr & target, const std::string & accountID);

View File

@ -38,8 +38,8 @@ void GlobalLobbyProcessor::onPacketReceived(const std::shared_ptr<INetworkConnec
{ {
JsonNode json(message.data(), message.size()); JsonNode json(message.data(), message.size());
if(json["type"].String() == "loginFailed") if(json["type"].String() == "operationFailed")
return receiveLoginFailed(json); return receiveOperationFailed(json);
if(json["type"].String() == "loginSuccess") if(json["type"].String() == "loginSuccess")
return receiveLoginSuccess(json); return receiveLoginSuccess(json);
@ -56,7 +56,7 @@ void GlobalLobbyProcessor::onPacketReceived(const std::shared_ptr<INetworkConnec
} }
} }
void GlobalLobbyProcessor::receiveLoginFailed(const JsonNode & json) void GlobalLobbyProcessor::receiveOperationFailed(const JsonNode & json)
{ {
logGlobal->info("Lobby: Failed to login into a lobby server!"); logGlobal->info("Lobby: Failed to login into a lobby server!");

View File

@ -31,7 +31,7 @@ class GlobalLobbyProcessor : public INetworkClientListener
void sendMessage(const NetworkConnectionPtr & target, const JsonNode & data); void sendMessage(const NetworkConnectionPtr & target, const JsonNode & data);
void receiveLoginFailed(const JsonNode & json); void receiveOperationFailed(const JsonNode & json);
void receiveLoginSuccess(const JsonNode & json); void receiveLoginSuccess(const JsonNode & json);
void receiveAccountJoinsRoom(const JsonNode & json); void receiveAccountJoinsRoom(const JsonNode & json);