feat(Core/Command): server debug (#6007)

* initial work

* fix query

* load

* clean up

* remove from startup

* ACE

* remove static

* Update MySQLThreading.cpp

* not used

* Update MySQLThreading.cpp

* unit testing

* Update WorldMock.h

* show Boost ver

* Update WorldMock.h

* include

* Now we have boost::filesystem woo

* fix build

* fix typo
This commit is contained in:
Kitzunu
2021-05-30 21:12:01 +02:00
committed by GitHub
parent e93159b408
commit ae665f7ec3
12 changed files with 226 additions and 34 deletions

View File

@@ -0,0 +1,5 @@
INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1621718778456057300');
DELETE FROM `command` WHERE `name` = 'server debug';
INSERT INTO `command` (`name`, `security`, `help`) VALUES
('server debug', 3, 'Syntax: .server debug\r\nShows detailed information about the server setup, useful when reporting a bug.');

View File

@@ -4,6 +4,8 @@
#define _HASH "@rev_hash@"
#define _DATE "@rev_date@"
#define _BRANCH "@rev_branch@"
#define _CMAKE_VERSION R"(@CMAKE_VERSION@)"
#define _CMAKE_HOST_SYSTEM R"(@CMAKE_HOST_SYSTEM_NAME@ @CMAKE_HOST_SYSTEM_VERSION@)"
#define VER_COMPANYNAME_STR "AzerothCore"
#define VER_LEGALCOPYRIGHT_STR "AzerothCore"
#define VER_FILEVERSION 0,0,0

View File

@@ -21,6 +21,16 @@ char const* GitRevision::GetBranch()
return _BRANCH;
}
char const* GitRevision::GetCMakeVersion()
{
return _CMAKE_VERSION;
}
char const* GitRevision::GetHostOSVersion()
{
return _CMAKE_HOST_SYSTEM;
}
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
# ifdef _WIN64
# define AZEROTH_PLATFORM_STR "Win64"
@@ -31,9 +41,15 @@ char const* GitRevision::GetBranch()
# define AZEROTH_PLATFORM_STR "Unix"
#endif
#ifndef ACORE_API_USE_DYNAMIC_LINKING
# define ACORE_LINKAGE_TYPE_STR "Static"
#else
# define ACORE_LINKAGE_TYPE_STR "Dynamic"
#endif
char const* GitRevision::GetFullVersion()
{
return VER_COMPANYNAME_STR " rev. " VER_PRODUCTVERSION_STR " (" AZEROTH_PLATFORM_STR ", " _BUILD_DIRECTIVE ")";
return VER_COMPANYNAME_STR " rev. " VER_PRODUCTVERSION_STR " (" AZEROTH_PLATFORM_STR ", " _BUILD_DIRECTIVE ", " ACORE_LINKAGE_TYPE_STR ")";
}
char const* GitRevision::GetCompanyNameStr()

View File

@@ -13,6 +13,8 @@ namespace GitRevision
char const* GetHash();
char const* GetDate();
char const* GetBranch();
char const* GetCMakeVersion();
char const* GetHostOSVersion();
char const* GetFullVersion();
char const* GetCompanyNameStr();
char const* GetLegalCopyrightStr();

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "MySQLThreading.h"
#include "Log.h"
#include <mysql.h>
void MySQL::Library_Init()
{
mysql_library_init(-1, nullptr, nullptr);
}
void MySQL::Library_End()
{
mysql_library_end();
}
uint32 MySQL::GetLibraryVersion()
{
return MYSQL_VERSION_ID;
}

View File

@@ -9,39 +9,11 @@
#include "Log.h"
class MySQL
namespace MySQL
{
public:
/*! Create a thread on the MySQL server to mirrior the calling thread,
initializes thread-specific variables and allows thread-specific
operations without concurrence from other threads.
This should only be called if multiple core threads are running
on the same MySQL connection. Seperate MySQL connections implicitly
create a mirror thread.
*/
static void Thread_Init()
{
mysql_thread_init();
}
/*! Shuts down MySQL thread and frees resources, should only be called
when we terminate. MySQL threads and connections are not configurable
during runtime.
*/
static void Thread_End()
{
mysql_thread_end();
}
static void Library_Init()
{
mysql_library_init(-1, nullptr, nullptr);
}
static void Library_End()
{
mysql_library_end();
}
};
void Library_Init();
void Library_End();
uint32 GetLibraryVersion();
}
#endif

View File

@@ -581,7 +581,11 @@ public:
virtual void UpdateRealmCharCount(uint32 accid) = 0;
virtual LocaleConstant GetAvailableDbcLocale(LocaleConstant locale) const = 0;
virtual void LoadDBVersion() = 0;
virtual void LoadDBRevision() = 0;
virtual char const* GetDBVersion() const = 0;
virtual char const* GetWorldDBRevision() const = 0;
virtual char const* GetCharacterDBRevision() const = 0;
virtual char const* GetAuthDBRevision() const = 0;
virtual void LoadAutobroadcasts() = 0;
virtual void UpdateAreaDependentAuras() = 0;
virtual uint32 GetCleaningFlags() const = 0;

View File

@@ -3109,6 +3109,45 @@ void World::LoadDBVersion()
m_DBVersion = "Unknown world database.";
}
void World::LoadDBRevision()
{
QueryResult resultWorld = WorldDatabase.Query("SELECT date FROM version_db_world ORDER BY date DESC LIMIT 1");
QueryResult resultCharacter = CharacterDatabase.Query("SELECT date FROM version_db_characters ORDER BY date DESC LIMIT 1");
QueryResult resultAuth = LoginDatabase.Query("SELECT date FROM version_db_auth ORDER BY date DESC LIMIT 1");
if (resultWorld)
{
Field* fields = resultWorld->Fetch();
m_WorldDBRevision = fields[0].GetString();
}
if (resultCharacter)
{
Field* fields = resultCharacter->Fetch();
m_CharacterDBRevision = fields[0].GetString();
}
if (resultAuth)
{
Field* fields = resultAuth->Fetch();
m_AuthDBRevision = fields[0].GetString();
}
if (m_WorldDBRevision.empty())
{
m_WorldDBRevision = "Unkown World Database Revision";
}
if (m_CharacterDBRevision.empty())
{
m_CharacterDBRevision = "Unkown Character Database Revision";
}
if (m_AuthDBRevision.empty())
{
m_AuthDBRevision = "Unkown Auth Database Revision";
}
}
void World::UpdateAreaDependentAuras()
{
SessionMap::const_iterator itr;

View File

@@ -370,7 +370,11 @@ public:
// used World DB version
void LoadDBVersion();
void LoadDBRevision();
char const* GetDBVersion() const { return m_DBVersion.c_str(); }
char const* GetWorldDBRevision() const { return m_WorldDBRevision.c_str(); }
char const* GetCharacterDBRevision() const { return m_CharacterDBRevision.c_str(); }
char const* GetAuthDBRevision() const { return m_AuthDBRevision.c_str(); }
void LoadAutobroadcasts();
@@ -478,6 +482,9 @@ private:
// used versions
std::string m_DBVersion;
std::string m_WorldDBRevision;
std::string m_CharacterDBRevision;
std::string m_AuthDBRevision;
typedef std::map<uint8, std::string> AutobroadcastsMap;
AutobroadcastsMap m_Autobroadcasts;

View File

@@ -15,12 +15,20 @@ EndScriptData */
#include "Chat.h"
#include "Config.h"
#include "GitRevision.h"
#include "VMapManager2.h"
#include "VMapFactory.h"
#include "Language.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "Realm.h"
#include "ScriptMgr.h"
#include "ServerMotd.h"
#include "StringConvert.h"
#include <boost/filesystem/operations.hpp>
#include <boost/version.hpp>
#include <openssl/crypto.h>
#include <openssl/opensslv.h>
#include <numeric>
class server_commandscript : public CommandScript
{
@@ -64,6 +72,7 @@ public:
static std::vector<ChatCommand> serverCommandTable =
{
{ "corpses", SEC_GAMEMASTER, true, &HandleServerCorpsesCommand, "" },
{ "debug", SEC_ADMINISTRATOR, true, &HandleServerDebugCommand, "" },
{ "exit", SEC_CONSOLE, true, &HandleServerExitCommand, "" },
{ "idlerestart", SEC_CONSOLE, true, nullptr, "", serverIdleRestartCommandTable },
{ "idleshutdown", SEC_CONSOLE, true, nullptr, "", serverIdleShutdownCommandTable },
@@ -89,6 +98,114 @@ public:
return true;
}
static bool HandleServerDebugCommand(ChatHandler* handler, char const* /*args*/)
{
uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
std::string dbPortOutput;
{
uint16 dbPort = 0;
if (QueryResult res = LoginDatabase.PQuery("SELECT port FROM realmlist WHERE id = %u", realm.Id.Realm))
dbPort = (*res)[0].GetUInt16();
if (dbPort)
dbPortOutput = acore::StringFormat("Realmlist (Realm Id: %u) configured in port %" PRIu16, realm.Id.Realm, dbPort);
else
dbPortOutput = acore::StringFormat("Realm Id: %u not found in `realmlist` table. Please check your setup", realm.Id.Realm);
}
handler->PSendSysMessage("%s", GitRevision::GetFullVersion());
handler->PSendSysMessage("Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
handler->PSendSysMessage("Using ACE version: %s", ACE_VERSION);
handler->PSendSysMessage("Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
handler->PSendSysMessage("Using MySQL version: %u", MySQL::GetLibraryVersion());
handler->PSendSysMessage("Using CMake version: %s", GitRevision::GetCMakeVersion());
handler->PSendSysMessage("Compiled on: %s", GitRevision::GetHostOSVersion());
handler->PSendSysMessage("Worldserver listening connections on port %" PRIu16, worldPort);
handler->PSendSysMessage("%s", dbPortOutput.c_str());
bool vmapIndoorCheck = sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK);
bool vmapLOSCheck = VMAP::VMapFactory::createOrGetVMapManager()->isLineOfSightCalcEnabled();
bool vmapHeightCheck = VMAP::VMapFactory::createOrGetVMapManager()->isHeightCalcEnabled();
bool mmapEnabled = sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS);
std::string dataDir = sWorld->GetDataPath();
std::vector<std::string> subDirs;
subDirs.emplace_back("maps");
if (vmapIndoorCheck || vmapLOSCheck || vmapHeightCheck)
{
handler->PSendSysMessage("VMAPs status: Enabled. LineOfSight: %i, getHeight: %i, indoorCheck: %i", vmapLOSCheck, vmapHeightCheck, vmapIndoorCheck);
subDirs.emplace_back("vmaps");
}
else
handler->SendSysMessage("VMAPs status: Disabled");
if (mmapEnabled)
{
handler->SendSysMessage("MMAPs status: Enabled");
subDirs.emplace_back("mmaps");
}
else
handler->SendSysMessage("MMAPs status: Disabled");
for (std::string const& subDir : subDirs)
{
boost::filesystem::path mapPath(dataDir);
mapPath /= subDir;
if (!boost::filesystem::exists(mapPath))
{
handler->PSendSysMessage("%s directory doesn't exist!. Using path: %s", subDir.c_str(), mapPath.generic_string().c_str());
continue;
}
auto end = boost::filesystem::directory_iterator();
std::size_t folderSize = std::accumulate(boost::filesystem::directory_iterator(mapPath), end, std::size_t(0), [](std::size_t val, boost::filesystem::path const& mapFile)
{
if (boost::filesystem::is_regular_file(mapFile))
val += boost::filesystem::file_size(mapFile);
return val;
});
handler->PSendSysMessage("%s directory located in %s. Total size: " SZFMTD " bytes", subDir.c_str(), mapPath.generic_string().c_str(), folderSize);
}
LocaleConstant defaultLocale = sWorld->GetDefaultDbcLocale();
uint32 availableLocalesMask = (1 << defaultLocale);
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
LocaleConstant locale = static_cast<LocaleConstant>(i);
if (locale == defaultLocale)
continue;
if (sWorld->GetAvailableDbcLocale(locale) != defaultLocale)
availableLocalesMask |= (1 << locale);
}
std::string availableLocales;
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
if (!(availableLocalesMask & (1 << i)))
continue;
availableLocales += localeNames[i];
if (i != TOTAL_LOCALES - 1)
availableLocales += " ";
}
handler->PSendSysMessage("Using %s DBC Locale as default. All available DBC locales: %s", localeNames[defaultLocale], availableLocales.c_str());
handler->PSendSysMessage("Using World DB: %s", sWorld->GetDBVersion());
handler->PSendSysMessage("Using World DB Revision: %s", sWorld->GetWorldDBRevision());
handler->PSendSysMessage("Using Character DB Revision: %s", sWorld->GetCharacterDBRevision());
handler->PSendSysMessage("Using Auth DB Revision: %s", sWorld->GetAuthDBRevision());
return true;
}
static bool HandleServerInfoCommand(ChatHandler* handler, char const* /*args*/)
{
std::string realmName = sWorld->GetRealmName();

View File

@@ -406,6 +406,7 @@ bool Master::_StartDB()
WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", GitRevision::GetFullVersion(), GitRevision::GetHash()); // One-time query
sWorld->LoadDBVersion();
sWorld->LoadDBRevision();
LOG_INFO("server", "Using World DB: %s", sWorld->GetDBVersion());
return true;

View File

@@ -112,7 +112,11 @@ public:
MOCK_METHOD(void, UpdateRealmCharCount, (uint32 accid), ());
MOCK_METHOD(LocaleConstant, GetAvailableDbcLocale, (LocaleConstant locale), (const));
MOCK_METHOD(void, LoadDBVersion, ());
MOCK_METHOD(void, LoadDBRevision, ());
MOCK_METHOD(char const *, GetDBVersion, (), (const));
MOCK_METHOD(char const *, GetWorldDBRevision, (), (const));
MOCK_METHOD(char const *, GetCharacterDBRevision, (), (const));
MOCK_METHOD(char const *, GetAuthDBRevision, (), (const));
MOCK_METHOD(void, LoadAutobroadcasts, ());
MOCK_METHOD(void, UpdateAreaDependentAuras, ());
MOCK_METHOD(uint32, GetCleaningFlags, (), (const));