LobbyServer.cpp 20 KB

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