Add server stats table and writing handling
This commit is contained in:
parent
f397064850
commit
f6e8ff2936
@ -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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user