mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-26 22:57:00 +02:00
541 lines
16 KiB
C++
541 lines
16 KiB
C++
/*
|
|
* LobbyServer.cpp, part of VCMI engine
|
|
*
|
|
* Authors: listed in file AUTHORS in main folder
|
|
*
|
|
* License: GNU General Public License v2.0 or later
|
|
* Full text of license available in license.txt file, in main folder
|
|
*
|
|
*/
|
|
#include "StdInc.h"
|
|
#include "LobbyDatabase.h"
|
|
|
|
#include "SQLiteConnection.h"
|
|
|
|
void LobbyDatabase::createTables()
|
|
{
|
|
static const std::string createChatMessages = R"(
|
|
CREATE TABLE IF NOT EXISTS chatMessages (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
senderName TEXT,
|
|
roomType TEXT,
|
|
messageText TEXT,
|
|
creationTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
|
);
|
|
)";
|
|
|
|
static const std::string createTableGameRooms = R"(
|
|
CREATE TABLE IF NOT EXISTS gameRooms (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
roomID TEXT,
|
|
hostAccountID TEXT,
|
|
status INTEGER NOT NULL DEFAULT 0,
|
|
playerLimit INTEGER NOT NULL,
|
|
creationTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
|
);
|
|
)";
|
|
|
|
static const std::string createTableGameRoomPlayers = R"(
|
|
CREATE TABLE IF NOT EXISTS gameRoomPlayers (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
roomID TEXT,
|
|
accountID TEXT
|
|
);
|
|
)";
|
|
|
|
static const std::string createTableAccounts = R"(
|
|
CREATE TABLE IF NOT EXISTS accounts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
accountID TEXT,
|
|
displayName TEXT,
|
|
online INTEGER NOT NULL,
|
|
lastLoginTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
creationTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
|
);
|
|
)";
|
|
|
|
static const std::string createTableAccountCookies = R"(
|
|
CREATE TABLE IF NOT EXISTS accountCookies (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
accountID TEXT,
|
|
cookieUUID TEXT,
|
|
creationTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
|
);
|
|
)";
|
|
|
|
static const std::string createTableGameRoomInvites = R"(
|
|
CREATE TABLE IF NOT EXISTS gameRoomInvites (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
roomID TEXT,
|
|
accountID TEXT
|
|
);
|
|
)";
|
|
|
|
database->prepare(createChatMessages)->execute();
|
|
database->prepare(createTableGameRoomPlayers)->execute();
|
|
database->prepare(createTableGameRooms)->execute();
|
|
database->prepare(createTableAccounts)->execute();
|
|
database->prepare(createTableAccountCookies)->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()
|
|
{
|
|
// INSERT INTO
|
|
|
|
static const std::string insertChatMessageText = R"(
|
|
INSERT INTO chatMessages(senderName, messageText) VALUES( ?, ?);
|
|
)";
|
|
|
|
static const std::string insertAccountText = R"(
|
|
INSERT INTO accounts(accountID, displayName, online) VALUES(?,?,0);
|
|
)";
|
|
|
|
static const std::string insertAccessCookieText = R"(
|
|
INSERT INTO accountCookies(accountID, cookieUUID) VALUES(?,?);
|
|
)";
|
|
|
|
static const std::string insertGameRoomText = R"(
|
|
INSERT INTO gameRooms(roomID, hostAccountID, status, playerLimit) VALUES(?, ?, 0, 8);
|
|
)";
|
|
|
|
static const std::string insertGameRoomPlayersText = R"(
|
|
INSERT INTO gameRoomPlayers(roomID, accountID) VALUES(?,?);
|
|
)";
|
|
|
|
static const std::string insertGameRoomInvitesText = R"(
|
|
INSERT INTO gameRoomInvites(roomID, accountID) VALUES(?,?);
|
|
)";
|
|
|
|
// DELETE FROM
|
|
|
|
static const std::string deleteGameRoomPlayersText = R"(
|
|
DELETE FROM gameRoomPlayers WHERE roomID = ? AND accountID = ?
|
|
)";
|
|
|
|
static const std::string deleteGameRoomInvitesText = R"(
|
|
DELETE FROM gameRoomInvites WHERE roomID = ? AND accountID = ?
|
|
)";
|
|
|
|
// UPDATE
|
|
|
|
static const std::string setAccountOnlineText = R"(
|
|
UPDATE accounts
|
|
SET online = ?
|
|
WHERE accountID = ?
|
|
)";
|
|
|
|
static const std::string setGameRoomStatusText = R"(
|
|
UPDATE gameRooms
|
|
SET status = ?
|
|
WHERE roomID = ?
|
|
)";
|
|
|
|
static const std::string updateAccountLoginTimeText = R"(
|
|
UPDATE accounts
|
|
SET lastLoginTime = CURRENT_TIMESTAMP
|
|
WHERE accountID = ?
|
|
)";
|
|
|
|
// SELECT FROM
|
|
|
|
static const std::string getRecentMessageHistoryText = R"(
|
|
SELECT senderName, displayName, messageText, strftime('%s',CURRENT_TIMESTAMP)- strftime('%s',cm.creationTime) AS secondsElapsed
|
|
FROM chatMessages cm
|
|
LEFT JOIN accounts on accountID = senderName
|
|
WHERE secondsElapsed < 60*60*18
|
|
ORDER BY cm.creationTime DESC
|
|
LIMIT 100
|
|
)";
|
|
|
|
static const std::string getIdleGameRoomText = R"(
|
|
SELECT roomID
|
|
FROM gameRooms
|
|
WHERE hostAccountID = ? AND status = 0
|
|
LIMIT 1
|
|
)";
|
|
|
|
static const std::string getGameRoomStatusText = R"(
|
|
SELECT status
|
|
FROM gameRooms
|
|
WHERE roomID = ?
|
|
)";
|
|
|
|
static const std::string getAccountGameRoomText = R"(
|
|
SELECT grp.roomID
|
|
FROM gameRoomPlayers grp
|
|
LEFT JOIN gameRooms gr ON gr.roomID = grp.roomID
|
|
WHERE accountID = ? AND status IN (1, 2)
|
|
LIMIT 1
|
|
)";
|
|
|
|
static const std::string getActiveAccountsText = R"(
|
|
SELECT accountID, displayName
|
|
FROM accounts
|
|
WHERE online = 1
|
|
)";
|
|
|
|
static const std::string getActiveGameRoomsText = R"(
|
|
SELECT roomID, hostAccountID, displayName, status, playerLimit
|
|
FROM gameRooms
|
|
LEFT JOIN accounts ON hostAccountID = accountID
|
|
WHERE status = 1
|
|
)";
|
|
|
|
static const std::string countRoomUsedSlotsText = R"(
|
|
SELECT COUNT(accountID)
|
|
FROM gameRoomPlayers
|
|
WHERE roomID = ?
|
|
)";
|
|
|
|
static const std::string countRoomTotalSlotsText = R"(
|
|
SELECT playerLimit
|
|
FROM gameRooms
|
|
WHERE roomID = ?
|
|
)";
|
|
|
|
static const std::string getAccountDisplayNameText = R"(
|
|
SELECT displayName
|
|
FROM accounts
|
|
WHERE accountID = ?
|
|
)";
|
|
|
|
static const std::string isAccountCookieValidText = R"(
|
|
SELECT COUNT(accountID)
|
|
FROM accountCookies
|
|
WHERE accountID = ? AND cookieUUID = ?
|
|
)";
|
|
|
|
static const std::string isGameRoomCookieValidText = R"(
|
|
SELECT COUNT(roomID)
|
|
FROM gameRooms
|
|
LEFT JOIN accountCookies ON accountCookies.accountID = gameRooms.hostAccountID
|
|
WHERE roomID = ? AND cookieUUID = ? AND strftime('%s',CURRENT_TIMESTAMP)- strftime('%s',creationTime) < ?
|
|
)";
|
|
|
|
static const std::string isPlayerInGameRoomText = R"(
|
|
SELECT COUNT(accountID)
|
|
FROM gameRoomPlayers grp
|
|
LEFT JOIN gameRooms gr ON gr.roomID = grp.roomID
|
|
WHERE accountID = ? AND grp.roomID = ? AND status IN (1, 2)
|
|
)";
|
|
|
|
static const std::string isPlayerInAnyGameRoomText = R"(
|
|
SELECT COUNT(accountID)
|
|
FROM gameRoomPlayers grp
|
|
LEFT JOIN gameRooms gr ON gr.roomID = grp.roomID
|
|
WHERE accountID = ? AND status IN (1, 2)
|
|
)";
|
|
|
|
static const std::string isAccountIDExistsText = R"(
|
|
SELECT COUNT(accountID)
|
|
FROM accounts
|
|
WHERE accountID = ?
|
|
)";
|
|
|
|
static const std::string isAccountNameExistsText = R"(
|
|
SELECT COUNT(displayName)
|
|
FROM accounts
|
|
WHERE displayName = ?
|
|
)";
|
|
|
|
insertChatMessageStatement = database->prepare(insertChatMessageText);
|
|
insertAccountStatement = database->prepare(insertAccountText);
|
|
insertAccessCookieStatement = database->prepare(insertAccessCookieText);
|
|
insertGameRoomStatement = database->prepare(insertGameRoomText);
|
|
insertGameRoomPlayersStatement = database->prepare(insertGameRoomPlayersText);
|
|
insertGameRoomInvitesStatement = database->prepare(insertGameRoomInvitesText);
|
|
|
|
deleteGameRoomPlayersStatement = database->prepare(deleteGameRoomPlayersText);
|
|
deleteGameRoomInvitesStatement = database->prepare(deleteGameRoomInvitesText);
|
|
|
|
setAccountOnlineStatement = database->prepare(setAccountOnlineText);
|
|
setGameRoomStatusStatement = database->prepare(setGameRoomStatusText);
|
|
updateAccountLoginTimeStatement = database->prepare(updateAccountLoginTimeText);
|
|
|
|
getRecentMessageHistoryStatement = database->prepare(getRecentMessageHistoryText);
|
|
getIdleGameRoomStatement = database->prepare(getIdleGameRoomText);
|
|
getGameRoomStatusStatement = database->prepare(getGameRoomStatusText);
|
|
getAccountGameRoomStatement = database->prepare(getAccountGameRoomText);
|
|
getActiveAccountsStatement = database->prepare(getActiveAccountsText);
|
|
getActiveGameRoomsStatement = database->prepare(getActiveGameRoomsText);
|
|
getAccountDisplayNameStatement = database->prepare(getAccountDisplayNameText);
|
|
countRoomUsedSlotsStatement = database->prepare(countRoomUsedSlotsText);
|
|
countRoomTotalSlotsStatement = database->prepare(countRoomTotalSlotsText);
|
|
|
|
isAccountCookieValidStatement = database->prepare(isAccountCookieValidText);
|
|
isPlayerInGameRoomStatement = database->prepare(isPlayerInGameRoomText);
|
|
isPlayerInAnyGameRoomStatement = database->prepare(isPlayerInAnyGameRoomText);
|
|
isAccountIDExistsStatement = database->prepare(isAccountIDExistsText);
|
|
isAccountNameExistsStatement = database->prepare(isAccountNameExistsText);
|
|
}
|
|
|
|
LobbyDatabase::~LobbyDatabase() = default;
|
|
|
|
LobbyDatabase::LobbyDatabase(const boost::filesystem::path & databasePath)
|
|
{
|
|
database = SQLiteInstance::open(databasePath, true);
|
|
createTables();
|
|
clearOldData();
|
|
prepareStatements();
|
|
}
|
|
|
|
void LobbyDatabase::insertChatMessage(const std::string & sender, const std::string & roomType, const std::string & roomName, const std::string & messageText)
|
|
{
|
|
insertChatMessageStatement->executeOnce(sender, messageText);
|
|
}
|
|
|
|
bool LobbyDatabase::isPlayerInGameRoom(const std::string & accountID)
|
|
{
|
|
bool result = false;
|
|
|
|
isPlayerInAnyGameRoomStatement->setBinds(accountID);
|
|
if(isPlayerInAnyGameRoomStatement->execute())
|
|
isPlayerInAnyGameRoomStatement->getColumns(result);
|
|
isPlayerInAnyGameRoomStatement->reset();
|
|
|
|
return result;
|
|
}
|
|
|
|
bool LobbyDatabase::isPlayerInGameRoom(const std::string & accountID, const std::string & roomID)
|
|
{
|
|
bool result = false;
|
|
|
|
isPlayerInGameRoomStatement->setBinds(accountID, roomID);
|
|
if(isPlayerInGameRoomStatement->execute())
|
|
isPlayerInGameRoomStatement->getColumns(result);
|
|
isPlayerInGameRoomStatement->reset();
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<LobbyChatMessage> LobbyDatabase::getRecentMessageHistory()
|
|
{
|
|
std::vector<LobbyChatMessage> result;
|
|
|
|
while(getRecentMessageHistoryStatement->execute())
|
|
{
|
|
LobbyChatMessage message;
|
|
getRecentMessageHistoryStatement->getColumns(message.accountID, message.displayName, message.messageText, message.age);
|
|
result.push_back(message);
|
|
}
|
|
getRecentMessageHistoryStatement->reset();
|
|
|
|
return result;
|
|
}
|
|
|
|
void LobbyDatabase::setAccountOnline(const std::string & accountID, bool isOnline)
|
|
{
|
|
setAccountOnlineStatement->executeOnce(isOnline ? 1 : 0, accountID);
|
|
}
|
|
|
|
void LobbyDatabase::setGameRoomStatus(const std::string & roomID, LobbyRoomState roomStatus)
|
|
{
|
|
setGameRoomStatusStatement->executeOnce(vstd::to_underlying(roomStatus), roomID);
|
|
}
|
|
|
|
void LobbyDatabase::insertPlayerIntoGameRoom(const std::string & accountID, const std::string & roomID)
|
|
{
|
|
insertGameRoomPlayersStatement->executeOnce(roomID, accountID);
|
|
}
|
|
|
|
void LobbyDatabase::deletePlayerFromGameRoom(const std::string & accountID, const std::string & roomID)
|
|
{
|
|
deleteGameRoomPlayersStatement->executeOnce(roomID, accountID);
|
|
}
|
|
|
|
void LobbyDatabase::deleteGameRoomInvite(const std::string & targetAccountID, const std::string & roomID)
|
|
{
|
|
deleteGameRoomInvitesStatement->executeOnce(roomID, targetAccountID);
|
|
}
|
|
|
|
void LobbyDatabase::insertGameRoomInvite(const std::string & targetAccountID, const std::string & roomID)
|
|
{
|
|
insertGameRoomInvitesStatement->executeOnce(roomID, targetAccountID);
|
|
}
|
|
|
|
void LobbyDatabase::insertGameRoom(const std::string & roomID, const std::string & hostAccountID)
|
|
{
|
|
insertGameRoomStatement->executeOnce(roomID, hostAccountID);
|
|
}
|
|
|
|
void LobbyDatabase::insertAccount(const std::string & accountID, const std::string & displayName)
|
|
{
|
|
insertAccountStatement->executeOnce(accountID, displayName);
|
|
}
|
|
|
|
void LobbyDatabase::insertAccessCookie(const std::string & accountID, const std::string & accessCookieUUID)
|
|
{
|
|
insertAccessCookieStatement->executeOnce(accountID, accessCookieUUID);
|
|
}
|
|
|
|
void LobbyDatabase::updateAccountLoginTime(const std::string & accountID)
|
|
{
|
|
updateAccountLoginTimeStatement->executeOnce(accountID);
|
|
}
|
|
|
|
std::string LobbyDatabase::getAccountDisplayName(const std::string & accountID)
|
|
{
|
|
std::string result;
|
|
|
|
getAccountDisplayNameStatement->setBinds(accountID);
|
|
if(getAccountDisplayNameStatement->execute())
|
|
getAccountDisplayNameStatement->getColumns(result);
|
|
getAccountDisplayNameStatement->reset();
|
|
|
|
return result;
|
|
}
|
|
|
|
LobbyCookieStatus LobbyDatabase::getAccountCookieStatus(const std::string & accountID, const std::string & accessCookieUUID)
|
|
{
|
|
bool result = false;
|
|
|
|
isAccountCookieValidStatement->setBinds(accountID, accessCookieUUID);
|
|
if(isAccountCookieValidStatement->execute())
|
|
isAccountCookieValidStatement->getColumns(result);
|
|
isAccountCookieValidStatement->reset();
|
|
|
|
return result ? LobbyCookieStatus::VALID : LobbyCookieStatus::INVALID;
|
|
}
|
|
|
|
LobbyInviteStatus LobbyDatabase::getAccountInviteStatus(const std::string & accountID, const std::string & roomID)
|
|
{
|
|
assert(0);
|
|
return {};
|
|
}
|
|
|
|
LobbyRoomState LobbyDatabase::getGameRoomStatus(const std::string & roomID)
|
|
{
|
|
int result = -1;
|
|
|
|
getGameRoomStatusStatement->setBinds(roomID);
|
|
if(getGameRoomStatusStatement->execute())
|
|
getGameRoomStatusStatement->getColumns(result);
|
|
getGameRoomStatusStatement->reset();
|
|
|
|
if (result != -1)
|
|
return static_cast<LobbyRoomState>(result);
|
|
return LobbyRoomState::CLOSED;
|
|
}
|
|
|
|
uint32_t LobbyDatabase::getGameRoomFreeSlots(const std::string & roomID)
|
|
{
|
|
uint32_t usedSlots = 0;
|
|
uint32_t totalSlots = 0;
|
|
|
|
countRoomUsedSlotsStatement->setBinds(roomID);
|
|
if(countRoomUsedSlotsStatement->execute())
|
|
countRoomUsedSlotsStatement->getColumns(usedSlots);
|
|
countRoomUsedSlotsStatement->reset();
|
|
|
|
countRoomTotalSlotsStatement->setBinds(roomID);
|
|
if(countRoomTotalSlotsStatement->execute())
|
|
countRoomTotalSlotsStatement->getColumns(totalSlots);
|
|
countRoomTotalSlotsStatement->reset();
|
|
|
|
|
|
if (totalSlots > usedSlots)
|
|
return totalSlots - usedSlots;
|
|
return 0;
|
|
}
|
|
|
|
bool LobbyDatabase::isAccountNameExists(const std::string & displayName)
|
|
{
|
|
bool result = false;
|
|
|
|
isAccountNameExistsStatement->setBinds(displayName);
|
|
if(isAccountNameExistsStatement->execute())
|
|
isAccountNameExistsStatement->getColumns(result);
|
|
isAccountNameExistsStatement->reset();
|
|
return result;
|
|
}
|
|
|
|
bool LobbyDatabase::isAccountIDExists(const std::string & accountID)
|
|
{
|
|
bool result = false;
|
|
|
|
isAccountIDExistsStatement->setBinds(accountID);
|
|
if(isAccountIDExistsStatement->execute())
|
|
isAccountIDExistsStatement->getColumns(result);
|
|
isAccountIDExistsStatement->reset();
|
|
return result;
|
|
}
|
|
|
|
std::vector<LobbyGameRoom> LobbyDatabase::getActiveGameRooms()
|
|
{
|
|
std::vector<LobbyGameRoom> result;
|
|
|
|
while(getActiveGameRoomsStatement->execute())
|
|
{
|
|
LobbyGameRoom entry;
|
|
getActiveGameRoomsStatement->getColumns(entry.roomID, entry.hostAccountID, entry.hostAccountDisplayName, entry.roomStatus, entry.playersLimit);
|
|
result.push_back(entry);
|
|
}
|
|
getActiveGameRoomsStatement->reset();
|
|
|
|
for (auto & room : result)
|
|
{
|
|
countRoomUsedSlotsStatement->setBinds(room.roomID);
|
|
if(countRoomUsedSlotsStatement->execute())
|
|
countRoomUsedSlotsStatement->getColumns(room.playersCount);
|
|
countRoomUsedSlotsStatement->reset();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::vector<LobbyAccount> LobbyDatabase::getActiveAccounts()
|
|
{
|
|
std::vector<LobbyAccount> result;
|
|
|
|
while(getActiveAccountsStatement->execute())
|
|
{
|
|
LobbyAccount entry;
|
|
getActiveAccountsStatement->getColumns(entry.accountID, entry.displayName);
|
|
result.push_back(entry);
|
|
}
|
|
getActiveAccountsStatement->reset();
|
|
return result;
|
|
}
|
|
|
|
std::string LobbyDatabase::getIdleGameRoom(const std::string & hostAccountID)
|
|
{
|
|
std::string result;
|
|
|
|
getIdleGameRoomStatement->setBinds(hostAccountID);
|
|
if(getIdleGameRoomStatement->execute())
|
|
getIdleGameRoomStatement->getColumns(result);
|
|
|
|
getIdleGameRoomStatement->reset();
|
|
return result;
|
|
}
|
|
|
|
std::string LobbyDatabase::getAccountGameRoom(const std::string & accountID)
|
|
{
|
|
std::string result;
|
|
|
|
getAccountGameRoomStatement->setBinds(accountID);
|
|
if(getAccountGameRoomStatement->execute())
|
|
getAccountGameRoomStatement->getColumns(result);
|
|
|
|
getAccountGameRoomStatement->reset();
|
|
return result;
|
|
}
|