LobbyServer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /*
  2. * LobbyServer.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "LobbyServer.h"
  12. #include "LobbyDatabase.h"
  13. #include "../lib/json/JsonFormatException.h"
  14. #include "../lib/json/JsonNode.h"
  15. #include "../lib/json/JsonUtils.h"
  16. #include <boost/uuid/uuid_generators.hpp>
  17. #include <boost/uuid/uuid_io.hpp>
  18. bool LobbyServer::isAccountNameValid(const std::string & accountName) const
  19. {
  20. if(accountName.size() < 4)
  21. return false;
  22. if(accountName.size() > 20)
  23. return false;
  24. for(const auto & c : accountName)
  25. if(!std::isalnum(c))
  26. return false;
  27. return true;
  28. }
  29. std::string LobbyServer::sanitizeChatMessage(const std::string & inputString) const
  30. {
  31. // TODO: sanitize message and remove any "weird" symbols from it
  32. return inputString;
  33. }
  34. NetworkConnectionPtr LobbyServer::findAccount(const std::string & accountID) const
  35. {
  36. for(const auto & account : activeAccounts)
  37. if(account.second == accountID)
  38. return account.first;
  39. return nullptr;
  40. }
  41. NetworkConnectionPtr LobbyServer::findGameRoom(const std::string & gameRoomID) const
  42. {
  43. for(const auto & account : activeGameRooms)
  44. if(account.second == gameRoomID)
  45. return account.first;
  46. return nullptr;
  47. }
  48. void LobbyServer::sendMessage(const NetworkConnectionPtr & target, const JsonNode & json)
  49. {
  50. logGlobal->info("Sending message of type %s", json["type"].String());
  51. assert(JsonUtils::validate(json, "vcmi:lobbyProtocol/" + json["type"].String(), json["type"].String() + " pack"));
  52. target->sendPacket(json.toBytes());
  53. }
  54. void LobbyServer::sendAccountCreated(const NetworkConnectionPtr & target, const std::string & accountID, const std::string & accountCookie)
  55. {
  56. JsonNode reply;
  57. reply["type"].String() = "accountCreated";
  58. reply["accountID"].String() = accountID;
  59. reply["accountCookie"].String() = accountCookie;
  60. sendMessage(target, reply);
  61. }
  62. void LobbyServer::sendInviteReceived(const NetworkConnectionPtr & target, const std::string & accountID, const std::string & gameRoomID)
  63. {
  64. JsonNode reply;
  65. reply["type"].String() = "inviteReceived";
  66. reply["accountID"].String() = accountID;
  67. reply["gameRoomID"].String() = gameRoomID;
  68. sendMessage(target, reply);
  69. }
  70. void LobbyServer::sendOperationFailed(const NetworkConnectionPtr & target, const std::string & reason)
  71. {
  72. JsonNode reply;
  73. reply["type"].String() = "operationFailed";
  74. reply["reason"].String() = reason;
  75. sendMessage(target, reply);
  76. }
  77. void LobbyServer::sendClientLoginSuccess(const NetworkConnectionPtr & target, const std::string & accountCookie, const std::string & displayName)
  78. {
  79. JsonNode reply;
  80. reply["type"].String() = "clientLoginSuccess";
  81. reply["accountCookie"].String() = accountCookie;
  82. reply["displayName"].String() = displayName;
  83. sendMessage(target, reply);
  84. }
  85. void LobbyServer::sendServerLoginSuccess(const NetworkConnectionPtr & target, const std::string & accountCookie)
  86. {
  87. JsonNode reply;
  88. reply["type"].String() = "serverLoginSuccess";
  89. reply["accountCookie"].String() = accountCookie;
  90. sendMessage(target, reply);
  91. }
  92. void LobbyServer::sendChatHistory(const NetworkConnectionPtr & target, const std::vector<LobbyChatMessage> & history)
  93. {
  94. JsonNode reply;
  95. reply["type"].String() = "chatHistory";
  96. reply["messages"].Vector(); // force creation of empty vector
  97. for(const auto & message : boost::adaptors::reverse(history))
  98. {
  99. JsonNode jsonEntry;
  100. jsonEntry["accountID"].String() = message.accountID;
  101. jsonEntry["displayName"].String() = message.displayName;
  102. jsonEntry["messageText"].String() = message.messageText;
  103. jsonEntry["ageSeconds"].Integer() = message.age.count();
  104. reply["messages"].Vector().push_back(jsonEntry);
  105. }
  106. sendMessage(target, reply);
  107. }
  108. void LobbyServer::broadcastActiveAccounts()
  109. {
  110. auto activeAccountsStats = database->getActiveAccounts();
  111. JsonNode reply;
  112. reply["type"].String() = "activeAccounts";
  113. reply["accounts"].Vector(); // force creation of empty vector
  114. for(const auto & account : activeAccountsStats)
  115. {
  116. JsonNode jsonEntry;
  117. jsonEntry["accountID"].String() = account.accountID;
  118. jsonEntry["displayName"].String() = account.displayName;
  119. jsonEntry["status"].String() = "In Lobby"; // TODO: in room status, in match status, offline status(?)
  120. reply["accounts"].Vector().push_back(jsonEntry);
  121. }
  122. for(const auto & connection : activeAccounts)
  123. sendMessage(connection.first, reply);
  124. }
  125. static constexpr std::array LOBBY_ROOM_STATE_NAMES = {
  126. "idle",
  127. "public",
  128. "private",
  129. "busy",
  130. "cancelled",
  131. "closed"
  132. };
  133. JsonNode LobbyServer::prepareActiveGameRooms()
  134. {
  135. auto activeGameRoomStats = database->getActiveGameRooms();
  136. JsonNode reply;
  137. reply["type"].String() = "activeGameRooms";
  138. reply["gameRooms"].Vector(); // force creation of empty vector
  139. for(const auto & gameRoom : activeGameRoomStats)
  140. {
  141. JsonNode jsonEntry;
  142. jsonEntry["gameRoomID"].String() = gameRoom.roomID;
  143. jsonEntry["hostAccountID"].String() = gameRoom.hostAccountID;
  144. jsonEntry["hostAccountDisplayName"].String() = gameRoom.hostAccountDisplayName;
  145. jsonEntry["description"].String() = gameRoom.description;
  146. jsonEntry["status"].String() = LOBBY_ROOM_STATE_NAMES[vstd::to_underlying(gameRoom.roomState)];
  147. jsonEntry["playersCount"].Integer() = gameRoom.playersCount;
  148. jsonEntry["playerLimit"].Integer() = gameRoom.playerLimit;
  149. reply["gameRooms"].Vector().push_back(jsonEntry);
  150. }
  151. return reply;
  152. }
  153. void LobbyServer::broadcastActiveGameRooms()
  154. {
  155. auto reply = prepareActiveGameRooms();
  156. for(const auto & connection : activeAccounts)
  157. sendMessage(connection.first, reply);
  158. }
  159. void LobbyServer::sendAccountJoinsRoom(const NetworkConnectionPtr & target, const std::string & accountID)
  160. {
  161. JsonNode reply;
  162. reply["type"].String() = "accountJoinsRoom";
  163. reply["accountID"].String() = accountID;
  164. sendMessage(target, reply);
  165. }
  166. void LobbyServer::sendJoinRoomSuccess(const NetworkConnectionPtr & target, const std::string & gameRoomID, bool proxyMode)
  167. {
  168. JsonNode reply;
  169. reply["type"].String() = "joinRoomSuccess";
  170. reply["gameRoomID"].String() = gameRoomID;
  171. reply["proxyMode"].Bool() = proxyMode;
  172. sendMessage(target, reply);
  173. }
  174. void LobbyServer::sendChatMessage(const NetworkConnectionPtr & target, const std::string & roomMode, const std::string & roomName, const std::string & accountID, const std::string & displayName, const std::string & messageText)
  175. {
  176. JsonNode reply;
  177. reply["type"].String() = "chatMessage";
  178. reply["messageText"].String() = messageText;
  179. reply["accountID"].String() = accountID;
  180. reply["displayName"].String() = displayName;
  181. reply["roomMode"].String() = roomMode;
  182. reply["roomName"].String() = roomName;
  183. sendMessage(target, reply);
  184. }
  185. void LobbyServer::onNewConnection(const NetworkConnectionPtr & connection)
  186. {
  187. // no-op - waiting for incoming data
  188. }
  189. void LobbyServer::onDisconnected(const NetworkConnectionPtr & connection, const std::string & errorMessage)
  190. {
  191. if(activeAccounts.count(connection))
  192. {
  193. database->setAccountOnline(activeAccounts.at(connection), false);
  194. activeAccounts.erase(connection);
  195. }
  196. if(activeGameRooms.count(connection))
  197. {
  198. database->setGameRoomStatus(activeGameRooms.at(connection), LobbyRoomState::CLOSED);
  199. activeGameRooms.erase(connection);
  200. }
  201. if(activeProxies.count(connection))
  202. {
  203. const auto & otherConnection = activeProxies.at(connection);
  204. if (otherConnection)
  205. otherConnection->close();
  206. activeProxies.erase(connection);
  207. activeProxies.erase(otherConnection);
  208. }
  209. broadcastActiveAccounts();
  210. broadcastActiveGameRooms();
  211. }
  212. JsonNode LobbyServer::parseAndValidateMessage(const std::vector<std::byte> & message) const
  213. {
  214. JsonParsingSettings parserSettings;
  215. parserSettings.mode = JsonParsingSettings::JsonFormatMode::JSON;
  216. parserSettings.maxDepth = 2;
  217. parserSettings.strict = true;
  218. JsonNode json;
  219. try
  220. {
  221. JsonNode jsonTemp(message.data(), message.size());
  222. json = std::move(jsonTemp);
  223. }
  224. catch (const JsonFormatException & e)
  225. {
  226. logGlobal->info(std::string("Json parsing error encountered: ") + e.what());
  227. return JsonNode();
  228. }
  229. std::string messageType = json["type"].String();
  230. if (messageType.empty())
  231. {
  232. logGlobal->info("Json parsing error encountered: Message type not set!");
  233. return JsonNode();
  234. }
  235. std::string schemaName = "vcmi:lobbyProtocol/" + messageType;
  236. if (!JsonUtils::validate(json, schemaName, messageType + " pack"))
  237. {
  238. logGlobal->info("Json validation error encountered!");
  239. assert(0);
  240. return JsonNode();
  241. }
  242. return json;
  243. }
  244. void LobbyServer::onPacketReceived(const NetworkConnectionPtr & connection, const std::vector<std::byte> & message)
  245. {
  246. // proxy connection - no processing, only redirect
  247. if(activeProxies.count(connection))
  248. {
  249. auto lockedPtr = activeProxies.at(connection);
  250. if(lockedPtr)
  251. return lockedPtr->sendPacket(message);
  252. logGlobal->info("Received unexpected message for inactive proxy!");
  253. }
  254. JsonNode json = parseAndValidateMessage(message);
  255. std::string messageType = json["type"].String();
  256. // communication messages from vcmiclient
  257. if(activeAccounts.count(connection))
  258. {
  259. std::string accountName = activeAccounts.at(connection);
  260. logGlobal->info("%s: Received message of type %s", accountName, messageType);
  261. if(messageType == "sendChatMessage")
  262. return receiveSendChatMessage(connection, json);
  263. if(messageType == "activateGameRoom")
  264. return receiveActivateGameRoom(connection, json);
  265. if(messageType == "joinGameRoom")
  266. return receiveJoinGameRoom(connection, json);
  267. if(messageType == "sendInvite")
  268. return receiveSendInvite(connection, json);
  269. if(messageType == "declineInvite")
  270. return receiveDeclineInvite(connection, json);
  271. logGlobal->warn("%s: Unknown message type: %s", accountName, messageType);
  272. return;
  273. }
  274. // communication messages from vcmiserver
  275. if(activeGameRooms.count(connection))
  276. {
  277. std::string roomName = activeGameRooms.at(connection);
  278. logGlobal->info("%s: Received message of type %s", roomName, messageType);
  279. if(messageType == "changeRoomDescription")
  280. return receiveChangeRoomDescription(connection, json);
  281. if(messageType == "gameStarted")
  282. return receiveGameStarted(connection, json);
  283. if(messageType == "leaveGameRoom")
  284. return receiveLeaveGameRoom(connection, json);
  285. logGlobal->warn("%s: Unknown message type: %s", roomName, messageType);
  286. return;
  287. }
  288. logGlobal->info("(unauthorised): Received message of type %s", messageType);
  289. // unauthorized connections - permit only login or register attempts
  290. if(messageType == "clientLogin")
  291. return receiveClientLogin(connection, json);
  292. if(messageType == "clientRegister")
  293. return receiveClientRegister(connection, json);
  294. if(messageType == "serverLogin")
  295. return receiveServerLogin(connection, json);
  296. if(messageType == "clientProxyLogin")
  297. return receiveClientProxyLogin(connection, json);
  298. if(messageType == "serverProxyLogin")
  299. return receiveServerProxyLogin(connection, json);
  300. connection->close();
  301. logGlobal->info("(unauthorised): Unknown message type %s", messageType);
  302. }
  303. void LobbyServer::receiveSendChatMessage(const NetworkConnectionPtr & connection, const JsonNode & json)
  304. {
  305. std::string accountID = activeAccounts[connection];
  306. std::string messageText = json["messageText"].String();
  307. std::string messageTextClean = sanitizeChatMessage(messageText);
  308. std::string displayName = database->getAccountDisplayName(accountID);
  309. if(messageTextClean.empty())
  310. return sendOperationFailed(connection, "No printable characters in sent message!");
  311. database->insertChatMessage(accountID, "global", "english", messageText);
  312. for(const auto & otherConnection : activeAccounts)
  313. sendChatMessage(otherConnection.first, "global", "english", accountID, displayName, messageText);
  314. }
  315. void LobbyServer::receiveClientRegister(const NetworkConnectionPtr & connection, const JsonNode & json)
  316. {
  317. std::string displayName = json["displayName"].String();
  318. std::string language = json["language"].String();
  319. if(!isAccountNameValid(displayName))
  320. return sendOperationFailed(connection, "Illegal account name");
  321. if(database->isAccountNameExists(displayName))
  322. return sendOperationFailed(connection, "Account name already in use");
  323. std::string accountCookie = boost::uuids::to_string(boost::uuids::random_generator()());
  324. std::string accountID = boost::uuids::to_string(boost::uuids::random_generator()());
  325. database->insertAccount(accountID, displayName);
  326. database->insertAccessCookie(accountID, accountCookie);
  327. sendAccountCreated(connection, accountID, accountCookie);
  328. }
  329. void LobbyServer::receiveClientLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
  330. {
  331. std::string accountID = json["accountID"].String();
  332. std::string accountCookie = json["accountCookie"].String();
  333. std::string language = json["language"].String();
  334. std::string version = json["version"].String();
  335. if(!database->isAccountIDExists(accountID))
  336. return sendOperationFailed(connection, "Account not found");
  337. auto clientCookieStatus = database->getAccountCookieStatus(accountID, accountCookie);
  338. if(clientCookieStatus == LobbyCookieStatus::INVALID)
  339. return sendOperationFailed(connection, "Authentification failure");
  340. database->updateAccountLoginTime(accountID);
  341. database->setAccountOnline(accountID, true);
  342. std::string displayName = database->getAccountDisplayName(accountID);
  343. activeAccounts[connection] = accountID;
  344. sendClientLoginSuccess(connection, accountCookie, displayName);
  345. sendChatHistory(connection, database->getRecentMessageHistory());
  346. // send active game rooms list to new account
  347. // and update acount list to everybody else including new account
  348. broadcastActiveAccounts();
  349. sendMessage(connection, prepareActiveGameRooms());
  350. }
  351. void LobbyServer::receiveServerLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
  352. {
  353. std::string gameRoomID = json["gameRoomID"].String();
  354. std::string accountID = json["accountID"].String();
  355. std::string accountCookie = json["accountCookie"].String();
  356. std::string version = json["version"].String();
  357. auto clientCookieStatus = database->getAccountCookieStatus(accountID, accountCookie);
  358. if(clientCookieStatus == LobbyCookieStatus::INVALID)
  359. {
  360. sendOperationFailed(connection, "Invalid credentials");
  361. }
  362. else
  363. {
  364. database->insertGameRoom(gameRoomID, accountID);
  365. activeGameRooms[connection] = gameRoomID;
  366. sendServerLoginSuccess(connection, accountCookie);
  367. broadcastActiveGameRooms();
  368. }
  369. }
  370. void LobbyServer::receiveClientProxyLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
  371. {
  372. std::string gameRoomID = json["gameRoomID"].String();
  373. std::string accountID = json["accountID"].String();
  374. std::string accountCookie = json["accountCookie"].String();
  375. auto clientCookieStatus = database->getAccountCookieStatus(accountID, accountCookie);
  376. if(clientCookieStatus != LobbyCookieStatus::INVALID)
  377. {
  378. for(auto & proxyEntry : awaitingProxies)
  379. {
  380. if(proxyEntry.accountID != accountID)
  381. continue;
  382. if(proxyEntry.roomID != gameRoomID)
  383. continue;
  384. proxyEntry.accountConnection = connection;
  385. auto gameRoomConnection = proxyEntry.roomConnection.lock();
  386. if(gameRoomConnection)
  387. {
  388. activeProxies[gameRoomConnection] = connection;
  389. activeProxies[connection] = gameRoomConnection;
  390. }
  391. return;
  392. }
  393. }
  394. sendOperationFailed(connection, "Invalid credentials");
  395. connection->close();
  396. }
  397. void LobbyServer::receiveServerProxyLogin(const NetworkConnectionPtr & connection, const JsonNode & json)
  398. {
  399. std::string gameRoomID = json["gameRoomID"].String();
  400. std::string guestAccountID = json["guestAccountID"].String();
  401. std::string accountCookie = json["accountCookie"].String();
  402. // FIXME: find host account ID and validate his cookie
  403. //auto clientCookieStatus = database->getAccountCookieStatus(hostAccountID, accountCookie, accountCookieLifetime);
  404. //if(clientCookieStatus != LobbyCookieStatus::INVALID)
  405. {
  406. NetworkConnectionPtr targetAccount = findAccount(guestAccountID);
  407. if(targetAccount == nullptr)
  408. {
  409. sendOperationFailed(connection, "Invalid credentials");
  410. return; // unknown / disconnected account
  411. }
  412. sendJoinRoomSuccess(targetAccount, gameRoomID, true);
  413. AwaitingProxyState proxy;
  414. proxy.accountID = guestAccountID;
  415. proxy.roomID = gameRoomID;
  416. proxy.roomConnection = connection;
  417. awaitingProxies.push_back(proxy);
  418. return;
  419. }
  420. //connection->close();
  421. }
  422. void LobbyServer::receiveActivateGameRoom(const NetworkConnectionPtr & connection, const JsonNode & json)
  423. {
  424. std::string hostAccountID = json["hostAccountID"].String();
  425. std::string accountID = activeAccounts[connection];
  426. int playerLimit = json["playerLimit"].Integer();
  427. if(database->isPlayerInGameRoom(accountID))
  428. return sendOperationFailed(connection, "Player already in the room!");
  429. std::string gameRoomID = database->getIdleGameRoom(hostAccountID);
  430. if(gameRoomID.empty())
  431. return sendOperationFailed(connection, "Failed to find idle server to join!");
  432. std::string roomType = json["roomType"].String();
  433. if(roomType != "public" && roomType != "private")
  434. return sendOperationFailed(connection, "Invalid room type!");
  435. if(roomType == "public")
  436. database->setGameRoomStatus(gameRoomID, LobbyRoomState::PUBLIC);
  437. if(roomType == "private")
  438. database->setGameRoomStatus(gameRoomID, LobbyRoomState::PRIVATE);
  439. database->updateRoomPlayerLimit(gameRoomID, playerLimit);
  440. database->insertPlayerIntoGameRoom(accountID, gameRoomID);
  441. broadcastActiveGameRooms();
  442. sendJoinRoomSuccess(connection, gameRoomID, false);
  443. }
  444. void LobbyServer::receiveJoinGameRoom(const NetworkConnectionPtr & connection, const JsonNode & json)
  445. {
  446. std::string gameRoomID = json["gameRoomID"].String();
  447. std::string accountID = activeAccounts[connection];
  448. if(database->isPlayerInGameRoom(accountID))
  449. return sendOperationFailed(connection, "Player already in the room!");
  450. NetworkConnectionPtr targetRoom = findGameRoom(gameRoomID);
  451. if(targetRoom == nullptr)
  452. return sendOperationFailed(connection, "Failed to find game room to join!");
  453. auto roomStatus = database->getGameRoomStatus(gameRoomID);
  454. if(roomStatus != LobbyRoomState::PRIVATE && roomStatus != LobbyRoomState::PUBLIC)
  455. return sendOperationFailed(connection, "Room does not accepts new players!");
  456. if(roomStatus == LobbyRoomState::PRIVATE)
  457. {
  458. if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::INVITED)
  459. return sendOperationFailed(connection, "You are not permitted to join private room without invite!");
  460. }
  461. if(database->getGameRoomFreeSlots(gameRoomID) == 0)
  462. return sendOperationFailed(connection, "Room is already full!");
  463. database->insertPlayerIntoGameRoom(accountID, gameRoomID);
  464. sendAccountJoinsRoom(targetRoom, accountID);
  465. //No reply to client - will be sent once match server establishes proxy connection with lobby
  466. broadcastActiveGameRooms();
  467. }
  468. void LobbyServer::receiveChangeRoomDescription(const NetworkConnectionPtr & connection, const JsonNode & json)
  469. {
  470. std::string gameRoomID = activeGameRooms[connection];
  471. std::string description = json["description"].String();
  472. database->updateRoomDescription(gameRoomID, description);
  473. broadcastActiveGameRooms();
  474. }
  475. void LobbyServer::receiveGameStarted(const NetworkConnectionPtr & connection, const JsonNode & json)
  476. {
  477. std::string gameRoomID = activeGameRooms[connection];
  478. database->setGameRoomStatus(gameRoomID, LobbyRoomState::BUSY);
  479. broadcastActiveGameRooms();
  480. }
  481. void LobbyServer::receiveLeaveGameRoom(const NetworkConnectionPtr & connection, const JsonNode & json)
  482. {
  483. std::string accountID = json["accountID"].String();
  484. std::string gameRoomID = activeGameRooms[connection];
  485. if(!database->isPlayerInGameRoom(accountID, gameRoomID))
  486. return sendOperationFailed(connection, "You are not in the room!");
  487. database->deletePlayerFromGameRoom(accountID, gameRoomID);
  488. broadcastActiveGameRooms();
  489. }
  490. void LobbyServer::receiveSendInvite(const NetworkConnectionPtr & connection, const JsonNode & json)
  491. {
  492. std::string senderName = activeAccounts[connection];
  493. std::string accountID = json["accountID"].String();
  494. std::string gameRoomID = database->getAccountGameRoom(senderName);
  495. auto targetAccount = findAccount(accountID);
  496. if(!targetAccount)
  497. return sendOperationFailed(connection, "Invalid account to invite!");
  498. if(!database->isPlayerInGameRoom(senderName))
  499. return sendOperationFailed(connection, "You are not in the room!");
  500. if(database->isPlayerInGameRoom(accountID))
  501. return sendOperationFailed(connection, "This player is already in a room!");
  502. if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::NOT_INVITED)
  503. return sendOperationFailed(connection, "This player is already invited!");
  504. database->insertGameRoomInvite(accountID, gameRoomID);
  505. sendInviteReceived(targetAccount, senderName, gameRoomID);
  506. }
  507. void LobbyServer::receiveDeclineInvite(const NetworkConnectionPtr & connection, const JsonNode & json)
  508. {
  509. std::string accountID = activeAccounts[connection];
  510. std::string gameRoomID = json["gameRoomID"].String();
  511. if(database->getAccountInviteStatus(accountID, gameRoomID) != LobbyInviteStatus::INVITED)
  512. return sendOperationFailed(connection, "No active invite found!");
  513. database->deleteGameRoomInvite(accountID, gameRoomID);
  514. }
  515. LobbyServer::~LobbyServer() = default;
  516. LobbyServer::LobbyServer(const boost::filesystem::path & databasePath)
  517. : database(std::make_unique<LobbyDatabase>(databasePath))
  518. , networkHandler(INetworkHandler::createHandler())
  519. , networkServer(networkHandler->createServerTCP(*this))
  520. {
  521. }
  522. void LobbyServer::start(uint16_t port)
  523. {
  524. networkServer->start(port);
  525. }
  526. void LobbyServer::run()
  527. {
  528. networkHandler->run();
  529. }