Add server stats table and writing handling

This commit is contained in:
Benau 2019-05-06 00:46:29 +08:00
parent f397064850
commit f6e8ff2936
6 changed files with 189 additions and 3 deletions

View File

@ -252,15 +252,148 @@ void ServerLobby::initDatabase()
#endif
} // initDatabase
//-----------------------------------------------------------------------------
void ServerLobby::initServerStatsTable()
{
#ifdef ENABLE_SQLITE3
if (!ServerConfig::m_sql_management || !m_db)
return;
std::string table_name = std::string("v") +
StringUtils::toString(ServerConfig::m_server_db_version) + "_" +
ServerConfig::m_server_uid + "_stats";
std::string query = StringUtils::insertValues(
"CREATE TABLE IF NOT EXISTS %s (\n"
" host_id INTEGER UNSIGNED NOT NULL PRIMARY KEY, -- Unique host id in STKHost of each connection session for a STKPeer\n"
" ip INTEGER UNSIGNED NOT NULL, -- IP decimal of host\n"
" port INTEGER UNSIGNED NOT NULL, -- Port of host\n"
" online_id INTEGER UNSIGNED NOT NULL, -- Online if of the host (0 for offline account)\n"
" username TEXT NOT NULL, -- First player name in the host (if the host has splitscreen player)\n"
" player_num INEGER UNSIGNED NOT NULL, -- Number of player(s) from the host, more than 1 if it has splitscreen player\n"
" country_id TEXT NULL DEFAULT NULL, -- Country id of the host\n"
" version TEXT NOT NULL, -- SuperTuxKart version of the host (with OS info)\n"
" connected_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Time when connected\n"
" disconnected_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Time when disconnected (saved when disconnected)\n"
" ping INEGER UNSIGNED NOT NULL DEFAULT 0 -- Ping of the host\n"
") WITHOUT ROWID;", table_name.c_str());
sqlite3_stmt* stmt = NULL;
int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
if (ret == SQLITE_OK)
{
ret = sqlite3_step(stmt);
ret = sqlite3_finalize(stmt);
if (ret == SQLITE_OK)
m_server_stats_table = table_name;
else
{
Log::error("ServerLobby", "Error finalize database: %s",
sqlite3_errmsg(m_db));
}
}
else
{
Log::error("ServerLobby", "Error preparing database: %s",
sqlite3_errmsg(m_db));
}
if (m_server_stats_table.empty())
return;
uint32_t last_host_id = 0;
query = StringUtils::insertValues("SELECT MAX(host_id) FROM %s;",
m_server_stats_table.c_str());
ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
if (ret == SQLITE_OK)
{
ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW && sqlite3_column_type(stmt, 0) != SQLITE_NULL)
{
last_host_id = (unsigned)sqlite3_column_int64(stmt, 0);
Log::info("ServerLobby", "%u was last server session max host id.",
last_host_id);
}
ret = sqlite3_finalize(stmt);
if (ret != SQLITE_OK)
{
Log::error("ServerLobby", "Error finalize database: %s",
sqlite3_errmsg(m_db));
m_server_stats_table = "";
}
}
else
{
Log::error("ServerLobby", "Error preparing database: %s",
sqlite3_errmsg(m_db));
m_server_stats_table = "";
}
STKHost::get()->setNextHostId(last_host_id);
// Update disconnected time (if stk crashed it will not be written)
query = StringUtils::insertValues(
"UPDATE %s SET disconnected_time = datetime('now')"
"WHERE connected_time = disconnected_time;",
m_server_stats_table.c_str());
ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
if (ret == SQLITE_OK)
{
ret = sqlite3_step(stmt);
ret = sqlite3_finalize(stmt);
if (ret != SQLITE_OK)
{
Log::error("ServerLobby", "Error finalize database: %s",
sqlite3_errmsg(m_db));
}
}
else
{
Log::error("ServerLobby", "Error preparing database: %s",
sqlite3_errmsg(m_db));
}
#endif
} // initServerStatsTable
//-----------------------------------------------------------------------------
void ServerLobby::destroyDatabase()
{
#ifdef ENABLE_SQLITE3
auto peers = STKHost::get()->getPeers();
for (auto& peer : peers)
writeDisconnectInfoTable(peer.get());
if (m_db != NULL)
sqlite3_close(m_db);
#endif
} // destroyDatabase
//-----------------------------------------------------------------------------
void ServerLobby::writeDisconnectInfoTable(STKPeer* peer)
{
#ifdef ENABLE_SQLITE3
if (m_server_stats_table.empty())
return;
std::string query = StringUtils::insertValues(
"UPDATE %s SET disconnected_time = datetime('now'), ping = %d "
"WHERE host_id = %u;", m_server_stats_table.c_str(),
peer->getAveragePing(), peer->getHostId());
sqlite3_stmt* stmt = NULL;
int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
if (ret == SQLITE_OK)
{
ret = sqlite3_step(stmt);
ret = sqlite3_finalize(stmt);
if (ret != SQLITE_OK)
{
Log::error("ServerLobby", "Error finalize database: %s",
sqlite3_errmsg(m_db));
}
}
else
{
Log::error("ServerLobby", "Error preparing database: %s",
sqlite3_errmsg(m_db));
}
#endif
} // writeDisconnectInfoTable
//-----------------------------------------------------------------------------
/** Called whenever server is reset or game mode is changed.
*/
@ -2151,6 +2284,8 @@ void ServerLobby::clientDisconnected(Event* event)
}, msg);
updatePlayerList();
delete msg;
writeDisconnectInfoTable(event->getPeer());
} // clientDisconnected
//-----------------------------------------------------------------------------
@ -2235,7 +2370,7 @@ void ServerLobby::connectionRequested(Event* event)
NetworkString *message = getNetworkString(2);
message->setSynchronous(true);
message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(RR_BUSY);
// send only to the peer that made the request and disconect it now
// send only to the peer that made the request and disconnect it now
peer->sendPacket(message, true/*reliable*/, false/*encrypted*/);
peer->reset();
delete message;
@ -2553,6 +2688,37 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
getRankingForPlayer(peer->getPlayerProfiles()[0]);
}
}
#ifdef ENABLE_SQLITE3
if (m_server_stats_table.empty())
return;
std::string query = StringUtils::insertValues(
"INSERT INTO %s "
"(host_id, ip, port, online_id, username, player_num, version, ping) "
"VALUES (%u, %u, %u, %u, \"%s\", %u, \"%s\", %u);",
m_server_stats_table.c_str(), peer->getHostId(),
peer->getAddress().getIP(), peer->getAddress().getPort(), online_id,
StringUtils::wideToUtf8(
peer->getPlayerProfiles()[0]->getName()).c_str(), player_count,
peer->getUserVersion().c_str(), peer->getAveragePing());
sqlite3_stmt* stmt = NULL;
int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0);
if (ret == SQLITE_OK)
{
ret = sqlite3_step(stmt);
ret = sqlite3_finalize(stmt);
if (ret != SQLITE_OK)
{
Log::error("ServerLobby", "Error finalize database: %s",
sqlite3_errmsg(m_db));
}
}
else
{
Log::error("ServerLobby", "Error preparing database: %s",
sqlite3_errmsg(m_db));
}
#endif
} // handleUnencryptedConnection
//-----------------------------------------------------------------------------

View File

@ -73,6 +73,8 @@ private:
#ifdef ENABLE_SQLITE3
sqlite3* m_db;
std::string m_server_stats_table;
bool m_ip_ban_table_exists;
bool m_online_id_ban_table_exists;
@ -315,6 +317,7 @@ private:
void kickPlayerWithReason(STKPeer* peer, const char* reason) const;
void testBannedForIP(STKPeer* peer) const;
void testBannedForOnlineId(STKPeer* peer, uint32_t online_id) const;
void writeDisconnectInfoTable(STKPeer* peer);
public:
ServerLobby();
virtual ~ServerLobby();
@ -344,6 +347,7 @@ public:
void saveInitialItems();
void saveIPBanTable(const TransportAddress& addr);
void listBanTable();
void initServerStatsTable();
}; // class ServerLobby
#endif // SERVER_LOBBY_HPP

View File

@ -46,6 +46,7 @@ namespace ServerConfig
{
// ============================================================================
std::string g_server_config_path;
std::string m_server_uid;
// ============================================================================
FloatServerConfigParam::FloatServerConfigParam(float default_value,
const char* param_name,
@ -121,6 +122,8 @@ void loadServerConfig(const std::string& path)
g_server_config_path = file_manager->getFileSystem()
->getAbsolutePath(path.c_str()).c_str();
}
m_server_uid = StringUtils::removeExtension(
StringUtils::getBasename(g_server_config_path));
const XMLNode* root = file_manager->createXMLTree(g_server_config_path);
loadServerConfigXML(root, default_config);
} // loadServerConfig

View File

@ -349,6 +349,13 @@ namespace ServerConfig
/** Server version, will be advanced if there are protocol changes. */
static const uint32_t m_server_version = 6;
// ========================================================================
/** Server database version, will be advanced if there are protocol
* changes. */
static const uint32_t m_server_db_version = 1;
// ========================================================================
/** Server uid, extracted from server_config.xml file with .xml removed. */
extern std::string m_server_uid;
// ========================================================================
void loadServerConfig(const std::string& path = "");
// ------------------------------------------------------------------------
void loadServerConfigXML(const XMLNode* root, bool default_config = false);

View File

@ -79,8 +79,11 @@ std::shared_ptr<LobbyProtocol> STKHost::create(SeparateProcess* p)
std::shared_ptr<LobbyProtocol> lp;
if (NetworkConfig::get()->isServer())
{
lp = LobbyProtocol::create<ServerLobby>();
std::shared_ptr<ServerLobby> sl =
LobbyProtocol::create<ServerLobby>();
m_stk_host = new STKHost(true/*server*/);
sl->initServerStatsTable();
lp = sl;
}
else
{
@ -929,8 +932,9 @@ void STKHost::mainLoop()
Event* stk_event = NULL;
if (event.type == ENET_EVENT_TYPE_CONNECT)
{
// ++m_next_unique_host_id for unique host id for database
auto stk_peer = std::make_shared<STKPeer>
(event.peer, this, m_next_unique_host_id++);
(event.peer, this, ++m_next_unique_host_id);
std::unique_lock<std::mutex> lock(m_peers_mutex);
m_peers[event.peer] = stk_peer;
lock.unlock();

View File

@ -315,6 +315,8 @@ public:
return m_next_unique_host_id;
}
// ------------------------------------------------------------------------
void setNextHostId(uint32_t id) { m_next_unique_host_id = id; }
// ------------------------------------------------------------------------
/** Returns the number of currently connected peers. */
unsigned int getPeerCount() const
{