mirror of
https://github.com/liyunfan1223/azerothcore-wotlk.git
synced 2026-08-08 15:58:04 +00:00
feat(Core/DBUpdater): implement db auto update (#6576)
* feat(Core/DBUpdater): implement db auto update * 1 * 2 * 3 * Some minor improvements * add find bin for mysql 8.0 * lic Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>
This commit is contained in:
12
data/sql/base/db_auth/updates.sql
Normal file
12
data/sql/base/db_auth/updates.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for updates
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `updates`;
|
||||||
|
CREATE TABLE `updates` (
|
||||||
|
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'filename with extension of the update.',
|
||||||
|
`hash` char(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT 'sha1 hash of the sql file.',
|
||||||
|
`state` enum('RELEASED','ARCHIVED','CUSTOM') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if an update is released or archived.',
|
||||||
|
`timestamp` timestamp(0) NOT NULL DEFAULT current_timestamp COMMENT 'timestamp when the query was applied.',
|
||||||
|
`speed` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'time the query takes to apply in ms.',
|
||||||
|
PRIMARY KEY (`name`) USING BTREE
|
||||||
|
) ENGINE = MyISAM CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'List of all applied updates in this database.' ROW_FORMAT = Dynamic;
|
||||||
15
data/sql/base/db_auth/updates_include.sql
Normal file
15
data/sql/base/db_auth/updates_include.sql
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for updates_include
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `updates_include`;
|
||||||
|
CREATE TABLE `updates_include` (
|
||||||
|
`path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'directory to include. $ means relative to the source directory.',
|
||||||
|
`state` enum('RELEASED','ARCHIVED','CUSTOM') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if the directory contains released or archived updates.',
|
||||||
|
PRIMARY KEY (`path`) USING BTREE
|
||||||
|
) ENGINE = MyISAM CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'List of directories where we want to include sql updates.' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of updates_include
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `updates_include` VALUES ('$/data/sql/updates/db_auth', 'RELEASED');
|
||||||
|
INSERT INTO `updates_include` VALUES ('$/data/sql/custom/db_auth', 'CUSTOM');
|
||||||
12
data/sql/base/db_characters/updates.sql
Normal file
12
data/sql/base/db_characters/updates.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for updates
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `updates`;
|
||||||
|
CREATE TABLE `updates` (
|
||||||
|
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'filename with extension of the update.',
|
||||||
|
`hash` char(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT 'sha1 hash of the sql file.',
|
||||||
|
`state` enum('RELEASED','ARCHIVED','CUSTOM') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if an update is released or archived.',
|
||||||
|
`timestamp` timestamp(0) NOT NULL DEFAULT current_timestamp COMMENT 'timestamp when the query was applied.',
|
||||||
|
`speed` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'time the query takes to apply in ms.',
|
||||||
|
PRIMARY KEY (`name`) USING BTREE
|
||||||
|
) ENGINE = MyISAM CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'List of all applied updates in this database.' ROW_FORMAT = Dynamic;
|
||||||
15
data/sql/base/db_characters/updates_include.sql
Normal file
15
data/sql/base/db_characters/updates_include.sql
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for updates_include
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `updates_include`;
|
||||||
|
CREATE TABLE `updates_include` (
|
||||||
|
`path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'directory to include. $ means relative to the source directory.',
|
||||||
|
`state` enum('RELEASED','ARCHIVED','CUSTOM') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if the directory contains released or archived updates.',
|
||||||
|
PRIMARY KEY (`path`) USING BTREE
|
||||||
|
) ENGINE = MyISAM CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'List of directories where we want to include sql updates.' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of updates_include
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `updates_include` VALUES ('$/data/sql/updates/db_characters', 'RELEASED');
|
||||||
|
INSERT INTO `updates_include` VALUES ('$/data/sql/custom/db_characters', 'CUSTOM');
|
||||||
12
data/sql/base/db_world/updates.sql
Normal file
12
data/sql/base/db_world/updates.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for updates
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `updates`;
|
||||||
|
CREATE TABLE `updates` (
|
||||||
|
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'filename with extension of the update.',
|
||||||
|
`hash` char(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT 'sha1 hash of the sql file.',
|
||||||
|
`state` enum('RELEASED','ARCHIVED','CUSTOM') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if an update is released or archived.',
|
||||||
|
`timestamp` timestamp(0) NOT NULL DEFAULT current_timestamp COMMENT 'timestamp when the query was applied.',
|
||||||
|
`speed` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'time the query takes to apply in ms.',
|
||||||
|
PRIMARY KEY (`name`) USING BTREE
|
||||||
|
) ENGINE = MyISAM CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'List of all applied updates in this database.' ROW_FORMAT = Dynamic;
|
||||||
15
data/sql/base/db_world/updates_include.sql
Normal file
15
data/sql/base/db_world/updates_include.sql
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for updates_include
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `updates_include`;
|
||||||
|
CREATE TABLE `updates_include` (
|
||||||
|
`path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'directory to include. $ means relative to the source directory.',
|
||||||
|
`state` enum('RELEASED','ARCHIVED','CUSTOM') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if the directory contains released or archived updates.',
|
||||||
|
PRIMARY KEY (`path`) USING BTREE
|
||||||
|
) ENGINE = MyISAM CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'List of directories where we want to include sql updates.' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of updates_include
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `updates_include` VALUES ('$/data/sql/updates/db_world', 'RELEASED');
|
||||||
|
INSERT INTO `updates_include` VALUES ('$/data/sql/custom/db_world', 'CUSTOM');
|
||||||
@@ -71,3 +71,18 @@ function(IsDynamicLinkingModulesRequired variable)
|
|||||||
endforeach()
|
endforeach()
|
||||||
set(${variable} ${IS_REQUIRED} PARENT_SCOPE)
|
set(${variable} ${IS_REQUIRED} PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# Get list all modules
|
||||||
|
function(GetModuleList)
|
||||||
|
file(GLOB LOCALE_MODULE_LIST RELATIVE
|
||||||
|
${CMAKE_SOURCE_DIR}/modules
|
||||||
|
${CMAKE_SOURCE_DIR}/modules/*)
|
||||||
|
|
||||||
|
foreach(MODULE_DIR ${LOCALE_MODULE_LIST})
|
||||||
|
if(IS_DIRECTORY "${CMAKE_SOURCE_DIR}/modules/${MODULE_DIR}")
|
||||||
|
set(MODULE_LIST__ ${MODULE_LIST__}${MODULE_DIR},)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
add_definitions(-DAC_MODULES_LIST=$<1:"${MODULE_LIST__}">)
|
||||||
|
endfunction()
|
||||||
|
|||||||
@@ -73,9 +73,22 @@ if (WIN32)
|
|||||||
if(MYSQL_LIBRARY)
|
if(MYSQL_LIBRARY)
|
||||||
set(MARIADB_FOUND_LIB 1)
|
set(MARIADB_FOUND_LIB 1)
|
||||||
endif()
|
endif()
|
||||||
if (MYSQL_LIBRARY AND MYSQL_INCLUDE_DIR)
|
|
||||||
|
find_program(MYSQL_EXECUTABLE mysql
|
||||||
|
PATHS
|
||||||
|
"${PROGRAM_FILES_64}/${MariaDBVersion}/bin"
|
||||||
|
"${PROGRAM_FILES_64}/${MariaDBVersion}/bin/opt"
|
||||||
|
"${PROGRAM_FILES_32}/${MariaDBVersion}/bin"
|
||||||
|
"${PROGRAM_FILES_32}/${MariaDBVersion}/bin/opt"
|
||||||
|
"$ENV{ProgramFiles}/${MariaDBVersion}/bin/opt"
|
||||||
|
"$ENV{SystemDrive}/${MariaDBVersion}/bin/opt"
|
||||||
|
DOC
|
||||||
|
"path to your mysql binary.")
|
||||||
|
|
||||||
|
if (MYSQL_LIBRARY AND MYSQL_INCLUDE_DIR AND MYSQL_EXECUTABLE)
|
||||||
set(MARIADB_FOUND 1)
|
set(MARIADB_FOUND 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endmacro(FindLibMariaDB)
|
endmacro(FindLibMariaDB)
|
||||||
|
|
||||||
foreach(version ${_MARIADB_KNOWN_VERSIONS})
|
foreach(version ${_MARIADB_KNOWN_VERSIONS})
|
||||||
@@ -207,7 +220,6 @@ endif( WIN32 )
|
|||||||
|
|
||||||
# On Windows you typically don't need to include any extra libraries
|
# On Windows you typically don't need to include any extra libraries
|
||||||
# to build MYSQL stuff.
|
# to build MYSQL stuff.
|
||||||
|
|
||||||
if( NOT WIN32 )
|
if( NOT WIN32 )
|
||||||
find_library( MYSQL_EXTRA_LIBRARIES
|
find_library( MYSQL_EXTRA_LIBRARIES
|
||||||
NAMES
|
NAMES
|
||||||
@@ -222,6 +234,50 @@ else( NOT WIN32 )
|
|||||||
set( MYSQL_EXTRA_LIBRARIES "" )
|
set( MYSQL_EXTRA_LIBRARIES "" )
|
||||||
endif( NOT WIN32 )
|
endif( NOT WIN32 )
|
||||||
|
|
||||||
|
if( UNIX )
|
||||||
|
find_program(MYSQL_EXECUTABLE mysql
|
||||||
|
PATHS
|
||||||
|
${MYSQL_CONFIG_PREFER_PATH}
|
||||||
|
/usr/local/mysql/bin/
|
||||||
|
/usr/local/bin/
|
||||||
|
/usr/bin/
|
||||||
|
DOC
|
||||||
|
"path to your mysql binary."
|
||||||
|
)
|
||||||
|
endif( UNIX )
|
||||||
|
|
||||||
|
if( WIN32 )
|
||||||
|
find_program(MYSQL_EXECUTABLE mysql
|
||||||
|
PATHS
|
||||||
|
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/bin"
|
||||||
|
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin"
|
||||||
|
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/bin/opt"
|
||||||
|
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin/opt"
|
||||||
|
"${PROGRAM_FILES_64}/MySQL/bin"
|
||||||
|
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/bin"
|
||||||
|
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin"
|
||||||
|
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/bin/opt"
|
||||||
|
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin/opt"
|
||||||
|
"${PROGRAM_FILES_32}/MySQL/bin"
|
||||||
|
"C:/MySQL/bin/debug"
|
||||||
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/bin"
|
||||||
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin"
|
||||||
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/bin/opt"
|
||||||
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt"
|
||||||
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/bin"
|
||||||
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin"
|
||||||
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/bin/opt"
|
||||||
|
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt"
|
||||||
|
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/bin/opt"
|
||||||
|
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/bin/opt"
|
||||||
|
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/bin/opt"
|
||||||
|
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/bin/opt"
|
||||||
|
"c:/msys/local/include"
|
||||||
|
"$ENV{MYSQL_ROOT}/bin"
|
||||||
|
DOC
|
||||||
|
"path to your mysql binary.")
|
||||||
|
endif( WIN32 )
|
||||||
|
|
||||||
if( MYSQL_LIBRARY )
|
if( MYSQL_LIBRARY )
|
||||||
if( MYSQL_INCLUDE_DIR )
|
if( MYSQL_INCLUDE_DIR )
|
||||||
set( MYSQL_FOUND 1 )
|
set( MYSQL_FOUND 1 )
|
||||||
@@ -230,7 +286,10 @@ if( MYSQL_LIBRARY )
|
|||||||
else( MYSQL_INCLUDE_DIR )
|
else( MYSQL_INCLUDE_DIR )
|
||||||
message(FATAL_ERROR "Could not find MySQL headers! Please install the development libraries and headers")
|
message(FATAL_ERROR "Could not find MySQL headers! Please install the development libraries and headers")
|
||||||
endif( MYSQL_INCLUDE_DIR )
|
endif( MYSQL_INCLUDE_DIR )
|
||||||
mark_as_advanced( MYSQL_FOUND MYSQL_LIBRARY MYSQL_EXTRA_LIBRARIES MYSQL_INCLUDE_DIR )
|
if( MYSQL_EXECUTABLE )
|
||||||
|
message(STATUS "Found MySQL executable: ${MYSQL_EXECUTABLE}")
|
||||||
|
endif( MYSQL_EXECUTABLE )
|
||||||
|
mark_as_advanced( MYSQL_FOUND MYSQL_LIBRARY MYSQL_EXTRA_LIBRARIES MYSQL_INCLUDE_DIR MYSQL_EXECUTABLE )
|
||||||
else( MYSQL_LIBRARY )
|
else( MYSQL_LIBRARY )
|
||||||
message(FATAL_ERROR "Could not find the MySQL libraries! Please install the development libraries and headers")
|
message(FATAL_ERROR "Could not find the MySQL libraries! Please install the development libraries and headers")
|
||||||
endif( MYSQL_LIBRARY )
|
endif( MYSQL_LIBRARY )
|
||||||
|
|||||||
@@ -4,8 +4,12 @@
|
|||||||
#define _HASH "@rev_hash@"
|
#define _HASH "@rev_hash@"
|
||||||
#define _DATE "@rev_date@"
|
#define _DATE "@rev_date@"
|
||||||
#define _BRANCH "@rev_branch@"
|
#define _BRANCH "@rev_branch@"
|
||||||
|
#define _CMAKE_COMMAND R"(@CMAKE_COMMAND@)"
|
||||||
#define _CMAKE_VERSION R"(@CMAKE_VERSION@)"
|
#define _CMAKE_VERSION R"(@CMAKE_VERSION@)"
|
||||||
#define _CMAKE_HOST_SYSTEM R"(@CMAKE_HOST_SYSTEM_NAME@ @CMAKE_HOST_SYSTEM_VERSION@)"
|
#define _CMAKE_HOST_SYSTEM R"(@CMAKE_HOST_SYSTEM_NAME@ @CMAKE_HOST_SYSTEM_VERSION@)"
|
||||||
|
#define _SOURCE_DIRECTORY R"(@CMAKE_SOURCE_DIR@)"
|
||||||
|
#define _BUILD_DIRECTORY R"(@BUILDDIR@)"
|
||||||
|
#define _MYSQL_EXECUTABLE R"(@MYSQL_EXECUTABLE@)"
|
||||||
#define VER_COMPANYNAME_STR "AzerothCore"
|
#define VER_COMPANYNAME_STR "AzerothCore"
|
||||||
#define VER_LEGALCOPYRIGHT_STR "(c)2016-@rev_year@ AzerothCore"
|
#define VER_LEGALCOPYRIGHT_STR "(c)2016-@rev_year@ AzerothCore"
|
||||||
#define VER_FILEVERSION 0,0,0
|
#define VER_FILEVERSION 0,0,0
|
||||||
|
|||||||
40
src/common/Configuration/BuiltInConfig.cpp
Normal file
40
src/common/Configuration/BuiltInConfig.cpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||||
|
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BuiltInConfig.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include "GitRevision.h"
|
||||||
|
|
||||||
|
template<typename Fn>
|
||||||
|
static std::string GetStringWithDefaultValueFromFunction(
|
||||||
|
std::string const& key, Fn getter)
|
||||||
|
{
|
||||||
|
std::string const value = sConfigMgr->GetOption<std::string>(key, "");
|
||||||
|
return value.empty() ? getter() : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BuiltInConfig::GetCMakeCommand()
|
||||||
|
{
|
||||||
|
return GetStringWithDefaultValueFromFunction(
|
||||||
|
"CMakeCommand", GitRevision::GetCMakeCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BuiltInConfig::GetBuildDirectory()
|
||||||
|
{
|
||||||
|
return GetStringWithDefaultValueFromFunction(
|
||||||
|
"BuildDirectory", GitRevision::GetBuildDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BuiltInConfig::GetSourceDirectory()
|
||||||
|
{
|
||||||
|
return GetStringWithDefaultValueFromFunction(
|
||||||
|
"SourceDirectory", GitRevision::GetSourceDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BuiltInConfig::GetMySQLExecutable()
|
||||||
|
{
|
||||||
|
return GetStringWithDefaultValueFromFunction(
|
||||||
|
"MySQLExecutable", GitRevision::GetMySQLExecutable);
|
||||||
|
}
|
||||||
34
src/common/Configuration/BuiltInConfig.h
Normal file
34
src/common/Configuration/BuiltInConfig.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||||
|
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BUILT_IN_CONFIG_H
|
||||||
|
#define BUILT_IN_CONFIG_H
|
||||||
|
|
||||||
|
#include "Define.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/// Provides helper functions to access built-in values
|
||||||
|
/// which can be overwritten in config
|
||||||
|
namespace BuiltInConfig
|
||||||
|
{
|
||||||
|
/// Returns the CMake command when any is specified in the config,
|
||||||
|
/// returns the built-in path otherwise
|
||||||
|
AC_COMMON_API std::string GetCMakeCommand();
|
||||||
|
|
||||||
|
/// Returns the build directory path when any is specified in the config,
|
||||||
|
/// returns the built-in one otherwise
|
||||||
|
AC_COMMON_API std::string GetBuildDirectory();
|
||||||
|
|
||||||
|
/// Returns the source directory path when any is specified in the config,
|
||||||
|
/// returns the built-in one otherwise
|
||||||
|
AC_COMMON_API std::string GetSourceDirectory();
|
||||||
|
|
||||||
|
/// Returns the path to the mysql executable (`mysql`) when any is specified
|
||||||
|
/// in the config, returns the built-in one otherwise
|
||||||
|
AC_COMMON_API std::string GetMySQLExecutable();
|
||||||
|
|
||||||
|
} // namespace BuiltInConfig
|
||||||
|
|
||||||
|
#endif // BUILT_IN_CONFIG_H
|
||||||
@@ -21,6 +21,11 @@ char const* GitRevision::GetBranch()
|
|||||||
return _BRANCH;
|
return _BRANCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char const* GitRevision::GetCMakeCommand()
|
||||||
|
{
|
||||||
|
return _CMAKE_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
char const* GitRevision::GetCMakeVersion()
|
char const* GitRevision::GetCMakeVersion()
|
||||||
{
|
{
|
||||||
return _CMAKE_VERSION;
|
return _CMAKE_VERSION;
|
||||||
@@ -31,6 +36,21 @@ char const* GitRevision::GetHostOSVersion()
|
|||||||
return _CMAKE_HOST_SYSTEM;
|
return _CMAKE_HOST_SYSTEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char const* GitRevision::GetBuildDirectory()
|
||||||
|
{
|
||||||
|
return _BUILD_DIRECTORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* GitRevision::GetSourceDirectory()
|
||||||
|
{
|
||||||
|
return _SOURCE_DIRECTORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* GitRevision::GetMySQLExecutable()
|
||||||
|
{
|
||||||
|
return _MYSQL_EXECUTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
|
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
|
||||||
# ifdef _WIN64
|
# ifdef _WIN64
|
||||||
# define AZEROTH_PLATFORM_STR "Win64"
|
# define AZEROTH_PLATFORM_STR "Win64"
|
||||||
|
|||||||
@@ -10,16 +10,20 @@
|
|||||||
|
|
||||||
namespace GitRevision
|
namespace GitRevision
|
||||||
{
|
{
|
||||||
char const* GetHash();
|
AC_COMMON_API char const* GetHash();
|
||||||
char const* GetDate();
|
AC_COMMON_API char const* GetDate();
|
||||||
char const* GetBranch();
|
AC_COMMON_API char const* GetBranch();
|
||||||
char const* GetCMakeVersion();
|
AC_COMMON_API char const* GetCMakeCommand();
|
||||||
char const* GetHostOSVersion();
|
AC_COMMON_API char const* GetCMakeVersion();
|
||||||
char const* GetFullVersion();
|
AC_COMMON_API char const* GetHostOSVersion();
|
||||||
char const* GetCompanyNameStr();
|
AC_COMMON_API char const* GetBuildDirectory();
|
||||||
char const* GetLegalCopyrightStr();
|
AC_COMMON_API char const* GetSourceDirectory();
|
||||||
char const* GetFileVersionStr();
|
AC_COMMON_API char const* GetMySQLExecutable();
|
||||||
char const* GetProductVersionStr();
|
AC_COMMON_API char const* GetFullVersion();
|
||||||
|
AC_COMMON_API char const* GetCompanyNameStr();
|
||||||
|
AC_COMMON_API char const* GetLegalCopyrightStr();
|
||||||
|
AC_COMMON_API char const* GetFileVersionStr();
|
||||||
|
AC_COMMON_API char const* GetProductVersionStr();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
257
src/common/Utilities/StartProcess.cpp
Normal file
257
src/common/Utilities/StartProcess.cpp
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||||
|
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StartProcess.h"
|
||||||
|
#include "Errors.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Optional.h"
|
||||||
|
#include "Util.h"
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
|
#include <boost/iostreams/copy.hpp>
|
||||||
|
#include <boost/process/args.hpp>
|
||||||
|
#include <boost/process/child.hpp>
|
||||||
|
#include <boost/process/env.hpp>
|
||||||
|
#include <boost/process/exe.hpp>
|
||||||
|
#include <boost/process/io.hpp>
|
||||||
|
#include <boost/process/pipe.hpp>
|
||||||
|
#include <boost/process/search_path.hpp>
|
||||||
|
|
||||||
|
using namespace boost::process;
|
||||||
|
using namespace boost::iostreams;
|
||||||
|
|
||||||
|
namespace Acore
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
class ACLogSink
|
||||||
|
{
|
||||||
|
T callback_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef char char_type;
|
||||||
|
typedef sink_tag category;
|
||||||
|
|
||||||
|
// Requires a callback type which has a void(std::string) signature
|
||||||
|
ACLogSink(T callback)
|
||||||
|
: callback_(std::move(callback)) { }
|
||||||
|
|
||||||
|
std::streamsize write(char const* str, std::streamsize size)
|
||||||
|
{
|
||||||
|
std::string consoleStr(str, size);
|
||||||
|
std::string utf8;
|
||||||
|
if (consoleToUtf8(consoleStr, utf8))
|
||||||
|
callback_(utf8);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto MakeACLogSink(T&& callback)
|
||||||
|
-> ACLogSink<typename std::decay<T>::type>
|
||||||
|
{
|
||||||
|
return { std::forward<T>(callback) };
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static int CreateChildProcess(T waiter, std::string const& executable,
|
||||||
|
std::vector<std::string> const& argsVector,
|
||||||
|
std::string const& logger, std::string const& input,
|
||||||
|
bool secure)
|
||||||
|
{
|
||||||
|
ipstream outStream;
|
||||||
|
ipstream errStream;
|
||||||
|
|
||||||
|
if (!secure)
|
||||||
|
{
|
||||||
|
LOG_TRACE(logger, "Starting process \"%s\" with arguments: \"%s\".",
|
||||||
|
executable.c_str(), boost::algorithm::join(argsVector, " ").c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare file with only read permission (boost process opens with read_write)
|
||||||
|
std::shared_ptr<FILE> inputFile(!input.empty() ? fopen(input.c_str(), "rb") : nullptr, [](FILE* ptr)
|
||||||
|
{
|
||||||
|
if (ptr != nullptr)
|
||||||
|
fclose(ptr);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the child process
|
||||||
|
child c = [&]()
|
||||||
|
{
|
||||||
|
if (inputFile)
|
||||||
|
{
|
||||||
|
// With binding stdin
|
||||||
|
return child{
|
||||||
|
exe = boost::filesystem::absolute(executable).string(),
|
||||||
|
args = argsVector,
|
||||||
|
env = environment(boost::this_process::environment()),
|
||||||
|
std_in = inputFile.get(),
|
||||||
|
std_out = outStream,
|
||||||
|
std_err = errStream
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Without binding stdin
|
||||||
|
return child{
|
||||||
|
exe = boost::filesystem::absolute(executable).string(),
|
||||||
|
args = argsVector,
|
||||||
|
env = environment(boost::this_process::environment()),
|
||||||
|
std_in = boost::process::close,
|
||||||
|
std_out = outStream,
|
||||||
|
std_err = errStream
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
auto outInfo = MakeACLogSink([&](std::string const& msg)
|
||||||
|
{
|
||||||
|
LOG_INFO(logger, "%s", msg.c_str());
|
||||||
|
});
|
||||||
|
|
||||||
|
auto outError = MakeACLogSink([&](std::string const& msg)
|
||||||
|
{
|
||||||
|
LOG_ERROR(logger, "%s", msg.c_str());
|
||||||
|
});
|
||||||
|
|
||||||
|
copy(outStream, outInfo);
|
||||||
|
copy(errStream, outError);
|
||||||
|
|
||||||
|
// Call the waiter in the current scope to prevent
|
||||||
|
// the streams from closing too early on leaving the scope.
|
||||||
|
int const result = waiter(c);
|
||||||
|
|
||||||
|
if (!secure)
|
||||||
|
{
|
||||||
|
LOG_TRACE(logger, ">> Process \"%s\" finished with return value %i.",
|
||||||
|
executable.c_str(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int StartProcess(std::string const& executable, std::vector<std::string> const& args,
|
||||||
|
std::string const& logger, std::string input_file, bool secure)
|
||||||
|
{
|
||||||
|
return CreateChildProcess([](child& c) -> int
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
c.wait();
|
||||||
|
return c.exit_code();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}, executable, args, logger, input_file, secure);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AsyncProcessResultImplementation
|
||||||
|
: public AsyncProcessResult
|
||||||
|
{
|
||||||
|
std::string const executable;
|
||||||
|
std::vector<std::string> const args;
|
||||||
|
std::string const logger;
|
||||||
|
std::string const input_file;
|
||||||
|
bool const is_secure;
|
||||||
|
|
||||||
|
std::atomic<bool> was_terminated;
|
||||||
|
|
||||||
|
// Workaround for missing move support in boost < 1.57
|
||||||
|
Optional<std::shared_ptr<std::future<int>>> result;
|
||||||
|
Optional<std::reference_wrapper<child>> my_child;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AsyncProcessResultImplementation(std::string executable_, std::vector<std::string> args_,
|
||||||
|
std::string logger_, std::string input_file_,
|
||||||
|
bool secure)
|
||||||
|
: executable(std::move(executable_)), args(std::move(args_)),
|
||||||
|
logger(std::move(logger_)), input_file(input_file_),
|
||||||
|
is_secure(secure), was_terminated(false) { }
|
||||||
|
|
||||||
|
AsyncProcessResultImplementation(AsyncProcessResultImplementation const&) = delete;
|
||||||
|
AsyncProcessResultImplementation& operator= (AsyncProcessResultImplementation const&) = delete;
|
||||||
|
AsyncProcessResultImplementation(AsyncProcessResultImplementation&&) = delete;
|
||||||
|
AsyncProcessResultImplementation& operator= (AsyncProcessResultImplementation&&) = delete;
|
||||||
|
|
||||||
|
int StartProcess()
|
||||||
|
{
|
||||||
|
ASSERT(!my_child, "Process started already!");
|
||||||
|
|
||||||
|
return CreateChildProcess([&](child& c) -> int
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
my_child = std::reference_wrapper<child>(c);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
c.wait();
|
||||||
|
result = c.exit_code();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
my_child.reset();
|
||||||
|
return was_terminated ? EXIT_FAILURE : result;
|
||||||
|
|
||||||
|
}, executable, args, logger, input_file, is_secure);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFuture(std::future<int> result_)
|
||||||
|
{
|
||||||
|
result = std::make_shared<std::future<int>>(std::move(result_));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the future which contains the result of the process
|
||||||
|
/// as soon it is finished.
|
||||||
|
std::future<int>& GetFutureResult() override
|
||||||
|
{
|
||||||
|
ASSERT(*result, "The process wasn't started!");
|
||||||
|
return **result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to terminate the process
|
||||||
|
void Terminate() override
|
||||||
|
{
|
||||||
|
if (my_child)
|
||||||
|
{
|
||||||
|
was_terminated = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
my_child->get().terminate();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<AsyncProcessResult>
|
||||||
|
StartAsyncProcess(std::string executable, std::vector<std::string> args,
|
||||||
|
std::string logger, std::string input_file, bool secure)
|
||||||
|
{
|
||||||
|
auto handle = std::make_shared<AsyncProcessResultImplementation>(
|
||||||
|
std::move(executable), std::move(args), std::move(logger), std::move(input_file), secure);
|
||||||
|
|
||||||
|
handle->SetFuture(std::async(std::launch::async, [handle] { return handle->StartProcess(); }));
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SearchExecutableInPath(std::string const& filename)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return search_path(filename).string();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Acore
|
||||||
57
src/common/Utilities/StartProcess.h
Normal file
57
src/common/Utilities/StartProcess.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||||
|
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PROCESS_H__
|
||||||
|
#define __PROCESS_H__
|
||||||
|
|
||||||
|
#include "Define.h"
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Acore
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Starts a process with the given arguments and parameters and will block
|
||||||
|
/// until the process is finished.
|
||||||
|
/// When an input path is given, the file will be routed to the processes stdin.
|
||||||
|
/// When the process is marked as secure no arguments are leaked to logs.
|
||||||
|
/// Note that most executables expect it's name as the first argument.
|
||||||
|
AC_COMMON_API int StartProcess(std::string const& executable, std::vector<std::string> const& args,
|
||||||
|
std::string const& logger, std::string input_file = "",
|
||||||
|
bool secure = false);
|
||||||
|
|
||||||
|
/// Platform and library independent representation
|
||||||
|
/// of asynchronous process results
|
||||||
|
class AsyncProcessResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~AsyncProcessResult() { }
|
||||||
|
|
||||||
|
/// Returns the future which contains the result of the process
|
||||||
|
/// as soon it is finished.
|
||||||
|
virtual std::future<int>& GetFutureResult() = 0;
|
||||||
|
|
||||||
|
/// Tries to terminate the process
|
||||||
|
virtual void Terminate() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Starts a process asynchronously with the given arguments and parameters and
|
||||||
|
/// returns an AsyncProcessResult immediately which is set, when the process exits.
|
||||||
|
/// When an input path is given, the file will be routed to the processes stdin.
|
||||||
|
/// When the process is marked as secure no arguments are leaked to logs.
|
||||||
|
/// Note that most executables expect it's name as the first argument.
|
||||||
|
AC_COMMON_API std::shared_ptr<AsyncProcessResult> StartAsyncProcess(std::string executable, std::vector<std::string> args,
|
||||||
|
std::string logger, std::string input_file = "",
|
||||||
|
bool secure = false);
|
||||||
|
|
||||||
|
/// Searches for the given executable in the PATH variable
|
||||||
|
/// and returns a non-empty string when it was found.
|
||||||
|
AC_COMMON_API std::string SearchExecutableInPath(std::string const& filename);
|
||||||
|
|
||||||
|
} // namespace Acore
|
||||||
|
|
||||||
|
#endif // __PROCESS_H__
|
||||||
@@ -10,9 +10,8 @@
|
|||||||
|
|
||||||
# Need to pass old ${CMAKE_BINARY_DIR} as param because its different at build stage
|
# Need to pass old ${CMAKE_BINARY_DIR} as param because its different at build stage
|
||||||
add_custom_target(revision.h ALL
|
add_custom_target(revision.h ALL
|
||||||
COMMAND ${CMAKE_COMMAND} -DBUILDDIR=${CMAKE_BINARY_DIR} -P ${CMAKE_SOURCE_DIR}/src/cmake/genrev.cmake
|
COMMAND "${CMAKE_COMMAND}" -DBUILDDIR="${CMAKE_BINARY_DIR}" -P "${CMAKE_SOURCE_DIR}/src/cmake/genrev.cmake" "${CMAKE_BINARY_DIR}"
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||||
)
|
|
||||||
|
|
||||||
set_target_properties(revision.h
|
set_target_properties(revision.h
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
# AUTH SERVER SETTINGS
|
# AUTH SERVER SETTINGS
|
||||||
# MYSQL SETTINGS
|
# MYSQL SETTINGS
|
||||||
# CRYPTOGRAPHY
|
# CRYPTOGRAPHY
|
||||||
|
# UPDATE SETTINGS
|
||||||
# LOGGING SYSTEM SETTINGS
|
# LOGGING SYSTEM SETTINGS
|
||||||
#
|
#
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
@@ -134,6 +135,29 @@ WrongPass.BanType = 0
|
|||||||
|
|
||||||
WrongPass.Logging = 0
|
WrongPass.Logging = 0
|
||||||
|
|
||||||
|
#
|
||||||
|
# SourceDirectory
|
||||||
|
# Description: The path to your AzerothCore source directory.
|
||||||
|
# If the path is left empty, the built-in CMAKE_SOURCE_DIR is used.
|
||||||
|
# Example: "../AzerothCore"
|
||||||
|
# Default: ""
|
||||||
|
#
|
||||||
|
|
||||||
|
SourceDirectory = ""
|
||||||
|
|
||||||
|
#
|
||||||
|
# MySQLExecutable
|
||||||
|
# Description: The path to your MySQL CLI binary.
|
||||||
|
# If the path is left empty, built-in path from cmake is used.
|
||||||
|
# Example: "C:/Program Files/MariaDB 10.5/bin/mysql.exe"
|
||||||
|
# "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe"
|
||||||
|
# "mysql.exe"
|
||||||
|
# "/usr/bin/mysql"
|
||||||
|
# Default: ""
|
||||||
|
#
|
||||||
|
|
||||||
|
MySQLExecutable = ""
|
||||||
|
|
||||||
#
|
#
|
||||||
# IPLocationFile
|
# IPLocationFile
|
||||||
# Description: The path to your IP2Location database CSV file.
|
# Description: The path to your IP2Location database CSV file.
|
||||||
@@ -219,6 +243,67 @@ TOTPMasterSecret =
|
|||||||
#
|
#
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
|
|
||||||
|
###################################################################################################
|
||||||
|
# UPDATE SETTINGS
|
||||||
|
#
|
||||||
|
# Updates.EnableDatabases
|
||||||
|
# Description: A mask that describes which databases shall be updated.
|
||||||
|
#
|
||||||
|
# Following flags are available
|
||||||
|
# DATABASE_LOGIN = 1, // Auth database
|
||||||
|
#
|
||||||
|
# Default: 0 - (All Disabled)
|
||||||
|
# 1 - (All Enabled)
|
||||||
|
|
||||||
|
Updates.EnableDatabases = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.AutoSetup
|
||||||
|
# Description: Auto populate empty databases.
|
||||||
|
# Default: 1 - (Enabled)
|
||||||
|
# 0 - (Disabled)
|
||||||
|
|
||||||
|
Updates.AutoSetup = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.Redundancy
|
||||||
|
# Description: Perform data redundancy checks through hashing
|
||||||
|
# to detect changes on sql updates and reapply it.
|
||||||
|
# Default: 1 - (Enabled)
|
||||||
|
# 0 - (Disabled)
|
||||||
|
|
||||||
|
Updates.Redundancy = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.ArchivedRedundancy
|
||||||
|
# Description: Check hashes of archived updates (slows down startup).
|
||||||
|
# Default: 0 - (Disabled)
|
||||||
|
# 1 - (Enabled)
|
||||||
|
|
||||||
|
Updates.ArchivedRedundancy = 0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.AllowRehash
|
||||||
|
# Description: Inserts the current file hash in the database if it is left empty.
|
||||||
|
# Useful if you want to mark a file as applied but you don't know its hash.
|
||||||
|
# Default: 1 - (Enabled)
|
||||||
|
# 0 - (Disabled)
|
||||||
|
|
||||||
|
Updates.AllowRehash = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.CleanDeadRefMaxCount
|
||||||
|
# Description: Cleans dead/ orphaned references that occur if an update was removed or renamed and edited in one step.
|
||||||
|
# It only starts the clean up if the count of the missing updates is below or equal the Updates.CleanDeadRefMaxCount value.
|
||||||
|
# This way prevents erasing of the update history due to wrong source directory state (maybe wrong branch or bad revision).
|
||||||
|
# Disable this if you want to know if the database is in a possible "dirty state".
|
||||||
|
# Default: 3 - (Enabled)
|
||||||
|
# 0 - (Disabled)
|
||||||
|
# -1 - (Enabled - unlimited)
|
||||||
|
|
||||||
|
Updates.CleanDeadRefMaxCount = 3
|
||||||
|
###################################################################################################
|
||||||
|
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
#
|
#
|
||||||
# LOGGING SYSTEM SETTINGS
|
# LOGGING SYSTEM SETTINGS
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ CollectSourceFiles(
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
PRIVATE_SOURCES
|
PRIVATE_SOURCES
|
||||||
# Exclude
|
# Exclude
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Updater
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders)
|
${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders)
|
||||||
|
|
||||||
if(USE_COREPCH)
|
if(USE_COREPCH)
|
||||||
@@ -47,6 +46,9 @@ target_link_libraries(database
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
common)
|
common)
|
||||||
|
|
||||||
|
# Add support auto update db for modules
|
||||||
|
GetModuleList()
|
||||||
|
|
||||||
set_target_properties(database
|
set_target_properties(database
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
FOLDER
|
FOLDER
|
||||||
|
|||||||
@@ -5,22 +5,26 @@
|
|||||||
|
|
||||||
#include "DatabaseLoader.h"
|
#include "DatabaseLoader.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
// #include "DBUpdater.h" not implement
|
#include "DBUpdater.h"
|
||||||
#include "DatabaseEnv.h"
|
#include "DatabaseEnv.h"
|
||||||
#include "Duration.h"
|
#include "Duration.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Duration.h"
|
|
||||||
#include <errmsg.h>
|
#include <errmsg.h>
|
||||||
#include <mysqld_error.h>
|
#include <mysqld_error.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
DatabaseLoader::DatabaseLoader(std::string const& logger)
|
DatabaseLoader::DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask)
|
||||||
: _logger(logger) { }
|
: _logger(logger), _autoSetup(sConfigMgr->GetOption<bool>("Updates.AutoSetup", true)),
|
||||||
|
_updateFlags(sConfigMgr->GetOption<uint32>("Updates.EnableDatabases", defaultUpdateMask))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::string const& name)
|
DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::string const& name)
|
||||||
{
|
{
|
||||||
_open.push([this, name, &pool]() -> bool
|
bool const updatesEnabledForThis = DBUpdater<T>::IsEnabled(_updateFlags);
|
||||||
|
|
||||||
|
_open.push([this, name, updatesEnabledForThis, &pool]() -> bool
|
||||||
{
|
{
|
||||||
std::string const dbString = sConfigMgr->GetOption<std::string>(name + "DatabaseInfo", "");
|
std::string const dbString = sConfigMgr->GetOption<std::string>(name + "DatabaseInfo", "");
|
||||||
if (dbString.empty())
|
if (dbString.empty())
|
||||||
@@ -67,6 +71,16 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Database does not exist
|
||||||
|
if ((error == ER_BAD_DB_ERROR) && updatesEnabledForThis && _autoSetup && !sConfigMgr->isDryRun())
|
||||||
|
{
|
||||||
|
// Try to create the database and connect again if auto setup is enabled
|
||||||
|
if (DBUpdater<T>::Create(pool) && (!pool.Open()))
|
||||||
|
{
|
||||||
|
error = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the error wasn't handled quit
|
// If the error wasn't handled quit
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
@@ -85,6 +99,32 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Populate and update only if updates are enabled for this pool
|
||||||
|
if (updatesEnabledForThis && !sConfigMgr->isDryRun())
|
||||||
|
{
|
||||||
|
_populate.push([this, name, &pool]() -> bool
|
||||||
|
{
|
||||||
|
if (!DBUpdater<T>::Populate(pool))
|
||||||
|
{
|
||||||
|
LOG_ERROR(_logger, "Could not populate the %s database, see log for details.", name.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
_update.push([this, name, &pool]() -> bool
|
||||||
|
{
|
||||||
|
if (!DBUpdater<T>::Update(pool))
|
||||||
|
{
|
||||||
|
LOG_ERROR(_logger, "Could not update the %s database, see log for details.", name.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_prepare.push([this, name, &pool]() -> bool
|
_prepare.push([this, name, &pool]() -> bool
|
||||||
{
|
{
|
||||||
if (!pool.PrepareStatements())
|
if (!pool.PrepareStatements())
|
||||||
@@ -101,7 +141,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
|
|||||||
|
|
||||||
bool DatabaseLoader::Load()
|
bool DatabaseLoader::Load()
|
||||||
{
|
{
|
||||||
return OpenDatabases() && PrepareStatements();
|
return OpenDatabases() && PopulateDatabases() && UpdateDatabases() && PrepareStatements();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DatabaseLoader::OpenDatabases()
|
bool DatabaseLoader::OpenDatabases()
|
||||||
@@ -109,6 +149,16 @@ bool DatabaseLoader::OpenDatabases()
|
|||||||
return Process(_open);
|
return Process(_open);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DatabaseLoader::PopulateDatabases()
|
||||||
|
{
|
||||||
|
return Process(_populate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DatabaseLoader::UpdateDatabases()
|
||||||
|
{
|
||||||
|
return Process(_update);
|
||||||
|
}
|
||||||
|
|
||||||
bool DatabaseLoader::PrepareStatements()
|
bool DatabaseLoader::PrepareStatements()
|
||||||
{
|
{
|
||||||
return Process(_prepare);
|
return Process(_prepare);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class DatabaseWorkerPool;
|
|||||||
class AC_DATABASE_API DatabaseLoader
|
class AC_DATABASE_API DatabaseLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DatabaseLoader(std::string const& logger);
|
DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask = 0);
|
||||||
|
|
||||||
// Register a database to the loader (lazy implemented)
|
// Register a database to the loader (lazy implemented)
|
||||||
template <class T>
|
template <class T>
|
||||||
@@ -42,6 +42,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool OpenDatabases();
|
bool OpenDatabases();
|
||||||
|
bool PopulateDatabases();
|
||||||
|
bool UpdateDatabases();
|
||||||
bool PrepareStatements();
|
bool PrepareStatements();
|
||||||
|
|
||||||
using Predicate = std::function<bool()>;
|
using Predicate = std::function<bool()>;
|
||||||
@@ -52,8 +54,10 @@ private:
|
|||||||
bool Process(std::queue<Predicate>& queue);
|
bool Process(std::queue<Predicate>& queue);
|
||||||
|
|
||||||
std::string const _logger;
|
std::string const _logger;
|
||||||
|
bool const _autoSetup;
|
||||||
|
uint32 const _updateFlags;
|
||||||
|
|
||||||
std::queue<Predicate> _open, _prepare;
|
std::queue<Predicate> _open, _populate, _update, _prepare;
|
||||||
std::stack<Closer> _close;
|
std::stack<Closer> _close;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "DBUpdater.h"
|
#include "DBUpdater.h"
|
||||||
#include "BuiltInConfig.h"
|
#include "BuiltInConfig.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
@@ -29,7 +30,7 @@ bool DBUpdaterUtil::CheckExecutable()
|
|||||||
boost::filesystem::path exe(GetCorrectedMySQLExecutable());
|
boost::filesystem::path exe(GetCorrectedMySQLExecutable());
|
||||||
if (!is_regular_file(exe))
|
if (!is_regular_file(exe))
|
||||||
{
|
{
|
||||||
exe = Warhead::SearchExecutableInPath("mysql");
|
exe = Acore::SearchExecutableInPath("mysql");
|
||||||
if (!exe.empty() && is_regular_file(exe))
|
if (!exe.empty() && is_regular_file(exe))
|
||||||
{
|
{
|
||||||
// Correct the path to the cli
|
// Correct the path to the cli
|
||||||
@@ -80,7 +81,7 @@ bool DBUpdater<LoginDatabaseConnection>::IsEnabled(uint32 const updateMask)
|
|||||||
template<>
|
template<>
|
||||||
std::string DBUpdater<LoginDatabaseConnection>::GetDBModuleName()
|
std::string DBUpdater<LoginDatabaseConnection>::GetDBModuleName()
|
||||||
{
|
{
|
||||||
return "db_auth";
|
return "db-auth";
|
||||||
}
|
}
|
||||||
|
|
||||||
// World Database
|
// World Database
|
||||||
@@ -112,7 +113,7 @@ bool DBUpdater<WorldDatabaseConnection>::IsEnabled(uint32 const updateMask)
|
|||||||
template<>
|
template<>
|
||||||
std::string DBUpdater<WorldDatabaseConnection>::GetDBModuleName()
|
std::string DBUpdater<WorldDatabaseConnection>::GetDBModuleName()
|
||||||
{
|
{
|
||||||
return "db_world";
|
return "db-world";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Character Database
|
// Character Database
|
||||||
@@ -144,7 +145,7 @@ bool DBUpdater<CharacterDatabaseConnection>::IsEnabled(uint32 const updateMask)
|
|||||||
template<>
|
template<>
|
||||||
std::string DBUpdater<CharacterDatabaseConnection>::GetDBModuleName()
|
std::string DBUpdater<CharacterDatabaseConnection>::GetDBModuleName()
|
||||||
{
|
{
|
||||||
return "db_characters";
|
return "db-characters";
|
||||||
}
|
}
|
||||||
|
|
||||||
// All
|
// All
|
||||||
@@ -162,7 +163,7 @@ bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool)
|
|||||||
|
|
||||||
std::string answer;
|
std::string answer;
|
||||||
std::getline(std::cin, answer);
|
std::getline(std::cin, answer);
|
||||||
if (!sConfigMgr->isDryRun() && !answer.empty() && !(answer.substr(0, 1) == "y"))
|
if (!answer.empty() && !(answer.substr(0, 1) == "y"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
LOG_INFO("sql.updates", "Creating database \"%s\"...", pool.GetConnectionInfo()->database.c_str());
|
LOG_INFO("sql.updates", "Creating database \"%s\"...", pool.GetConnectionInfo()->database.c_str());
|
||||||
@@ -219,7 +220,7 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool)
|
|||||||
|
|
||||||
auto CheckUpdateTable = [&](std::string const& tableName)
|
auto CheckUpdateTable = [&](std::string const& tableName)
|
||||||
{
|
{
|
||||||
auto checkTable = DBUpdater<T>::Retrieve(pool, Warhead::StringFormat("SHOW TABLES LIKE '%s'", tableName.c_str()));
|
auto checkTable = DBUpdater<T>::Retrieve(pool, Acore::StringFormat("SHOW TABLES LIKE '%s'", tableName.c_str()));
|
||||||
if (!checkTable)
|
if (!checkTable)
|
||||||
{
|
{
|
||||||
LOG_WARN("sql.updates", "> Table '%s' not exist! Try add based table", tableName.c_str());
|
LOG_WARN("sql.updates", "> Table '%s' not exist! Try add based table", tableName.c_str());
|
||||||
@@ -253,17 +254,17 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = updateFetcher.Update(
|
result = updateFetcher.Update(
|
||||||
sConfigMgr->GetBoolDefault("Updates.Redundancy", true),
|
sConfigMgr->GetOption<bool>("Updates.Redundancy", true),
|
||||||
sConfigMgr->GetBoolDefault("Updates.AllowRehash", true),
|
sConfigMgr->GetOption<bool>("Updates.AllowRehash", true),
|
||||||
sConfigMgr->GetBoolDefault("Updates.ArchivedRedundancy", false),
|
sConfigMgr->GetOption<bool>("Updates.ArchivedRedundancy", false),
|
||||||
sConfigMgr->GetIntDefault("Updates.CleanDeadRefMaxCount", 3));
|
sConfigMgr->GetOption<int32>("Updates.CleanDeadRefMaxCount", 3));
|
||||||
}
|
}
|
||||||
catch (UpdateException&)
|
catch (UpdateException&)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const info = Warhead::StringFormat("Containing " SZFMTD " new and " SZFMTD " archived updates.",
|
std::string const info = Acore::StringFormat("Containing " SZFMTD " new and " SZFMTD " archived updates.",
|
||||||
result.recent, result.archived);
|
result.recent, result.archived);
|
||||||
|
|
||||||
if (!result.updated)
|
if (!result.updated)
|
||||||
@@ -412,7 +413,7 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
|
|||||||
args.emplace_back(database);
|
args.emplace_back(database);
|
||||||
|
|
||||||
// Invokes a mysql process which doesn't leak credentials to logs
|
// Invokes a mysql process which doesn't leak credentials to logs
|
||||||
int const ret = Warhead::StartProcess(DBUpdaterUtil::GetCorrectedMySQLExecutable(), args,
|
int const ret = Acore::StartProcess(DBUpdaterUtil::GetCorrectedMySQLExecutable(), args,
|
||||||
"sql.updates", path.generic_string(), true);
|
"sql.updates", path.generic_string(), true);
|
||||||
|
|
||||||
if (ret != EXIT_SUCCESS)
|
if (ret != EXIT_SUCCESS)
|
||||||
@@ -420,7 +421,7 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
|
|||||||
LOG_FATAL("sql.updates", "Applying of file \'%s\' to database \'%s\' failed!" \
|
LOG_FATAL("sql.updates", "Applying of file \'%s\' to database \'%s\' failed!" \
|
||||||
" If you are a user, please pull the latest revision from the repository. "
|
" If you are a user, please pull the latest revision from the repository. "
|
||||||
"Also make sure you have not applied any of the databases with your sql client. "
|
"Also make sure you have not applied any of the databases with your sql client. "
|
||||||
"You cannot use auto-update system and import sql files from WarheadCore repository with your sql client. "
|
"You cannot use auto-update system and import sql files from AzerothCore repository with your sql client. "
|
||||||
"If you are a developer, please fix your sql query.",
|
"If you are a developer, please fix your sql query.",
|
||||||
path.generic_string().c_str(), pool.GetConnectionInfo()->database.c_str());
|
path.generic_string().c_str(), pool.GetConnectionInfo()->database.c_str());
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ void UpdateFetcher::FillFileListRecursively(Path const& path, LocaleFileStorage&
|
|||||||
}
|
}
|
||||||
else if (itr->path().extension() == ".sql")
|
else if (itr->path().extension() == ".sql")
|
||||||
{
|
{
|
||||||
LOG_TRACE("sql.updates", "Added locale file \"%s\".", itr->path().filename().generic_string().c_str());
|
LOG_TRACE("sql.updates", "Added locale file \"%s\" state '%s'.", itr->path().filename().generic_string().c_str(), AppliedFileEntry::StateConvert(state).c_str());
|
||||||
|
|
||||||
LocaleFileEntry const entry = { itr->path(), state };
|
LocaleFileEntry const entry = { itr->path(), state };
|
||||||
|
|
||||||
@@ -95,6 +95,7 @@ UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() cons
|
|||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
|
|
||||||
std::string path = fields[0].GetString();
|
std::string path = fields[0].GetString();
|
||||||
|
std::string state = fields[1].GetString();
|
||||||
if (path.substr(0, 1) == "$")
|
if (path.substr(0, 1) == "$")
|
||||||
path = _sourceDirectory->generic_string() + path.substr(1);
|
path = _sourceDirectory->generic_string() + path.substr(1);
|
||||||
|
|
||||||
@@ -106,28 +107,29 @@ UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() cons
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryEntry const entry = { p, AppliedFileEntry::StateConvert(fields[1].GetString()) };
|
DirectoryEntry const entry = { p, AppliedFileEntry::StateConvert(state) };
|
||||||
directories.push_back(entry);
|
directories.push_back(entry);
|
||||||
|
|
||||||
LOG_TRACE("sql.updates", "Added applied file \"%s\" from remote.", p.filename().generic_string().c_str());
|
LOG_TRACE("sql.updates", "Added applied file \"%s\" '%s' state from remote.", p.filename().generic_string().c_str(), state.c_str());
|
||||||
|
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
|
|
||||||
std::vector<std::string> moduleList;
|
std::vector<std::string> moduleList;
|
||||||
|
|
||||||
auto const& _modulesTokens = Warhead::Tokenize(WH_MODULES_LIST, ',', true);
|
auto const& _modulesTokens = Acore::Tokenize(AC_MODULES_LIST, ',', true);
|
||||||
for (auto const& itr : _modulesTokens)
|
for (auto const& itr : _modulesTokens)
|
||||||
moduleList.push_back(std::string(itr));
|
moduleList.emplace_back(itr);
|
||||||
|
|
||||||
|
// data/sql
|
||||||
for (auto const& itr : moduleList)
|
for (auto const& itr : moduleList)
|
||||||
{
|
{
|
||||||
std::string path = _sourceDirectory->generic_string() + "/modules/" + itr + "/sql/" + _dbModuleName; // module/mod-name/sql/db_world
|
std::string path = _sourceDirectory->generic_string() + "/modules/" + itr + "/data/sql/" + _dbModuleName; // modules/mod-name/data/sql/db-world
|
||||||
|
|
||||||
Path const p(path);
|
Path const p(path);
|
||||||
if (!is_directory(p))
|
if (!is_directory(p))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
DirectoryEntry const entry = { p, AppliedFileEntry::StateConvert("RELEASED") };
|
DirectoryEntry const entry = { p, AppliedFileEntry::StateConvert("CUSTOM") };
|
||||||
directories.push_back(entry);
|
directories.push_back(entry);
|
||||||
|
|
||||||
LOG_TRACE("sql.updates", "Added applied modules file \"%s\" from remote.", p.filename().generic_string().c_str());
|
LOG_TRACE("sql.updates", "Added applied modules file \"%s\" from remote.", p.filename().generic_string().c_str());
|
||||||
@@ -148,11 +150,12 @@ UpdateFetcher::AppliedFileStorage UpdateFetcher::ReceiveAppliedFiles() const
|
|||||||
{
|
{
|
||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
|
|
||||||
AppliedFileEntry const entry = { fields[0].GetString(), fields[1].GetString(),
|
AppliedFileEntry const entry =
|
||||||
AppliedFileEntry::StateConvert(fields[2].GetString()), fields[3].GetUInt64()
|
{
|
||||||
};
|
fields[0].GetString(), fields[1].GetString(), AppliedFileEntry::StateConvert(fields[2].GetString()), fields[3].GetUInt64()
|
||||||
|
};
|
||||||
|
|
||||||
map.insert(std::make_pair(entry.name, entry));
|
map.emplace(entry.name, entry);
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
@@ -207,11 +210,14 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks,
|
|||||||
|
|
||||||
size_t importedUpdates = 0;
|
size_t importedUpdates = 0;
|
||||||
|
|
||||||
for (auto const& availableQuery : available)
|
auto ApplyUpdateFile = [&](LocaleFileEntry const& sqlFile)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("sql.updates", "Checking update \"%s\"...", availableQuery.first.filename().generic_string().c_str());
|
auto filePath = sqlFile.first;
|
||||||
|
auto fileState = sqlFile.second;
|
||||||
|
|
||||||
AppliedFileStorage::const_iterator iter = applied.find(availableQuery.first.filename().string());
|
LOG_DEBUG("sql.updates", "Checking update \"%s\"...", filePath.filename().generic_string().c_str());
|
||||||
|
|
||||||
|
AppliedFileStorage::const_iterator iter = applied.find(filePath.filename().string());
|
||||||
if (iter != applied.end())
|
if (iter != applied.end())
|
||||||
{
|
{
|
||||||
// If redundancy is disabled, skip it, because the update is already applied.
|
// If redundancy is disabled, skip it, because the update is already applied.
|
||||||
@@ -219,19 +225,19 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks,
|
|||||||
{
|
{
|
||||||
LOG_DEBUG("sql.updates", ">> Update is already applied, skipping redundancy checks.");
|
LOG_DEBUG("sql.updates", ">> Update is already applied, skipping redundancy checks.");
|
||||||
applied.erase(iter);
|
applied.erase(iter);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the update is in an archived directory and is marked as archived in our database, skip redundancy checks (archived updates never change).
|
// If the update is in an archived directory and is marked as archived in our database, skip redundancy checks (archived updates never change).
|
||||||
if (!archivedRedundancy && (iter->second.state == ARCHIVED) && (availableQuery.second == ARCHIVED))
|
if (!archivedRedundancy && (iter->second.state == ARCHIVED) && (sqlFile.second == ARCHIVED))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("sql.updates", ">> Update is archived and marked as archived in database, skipping redundancy checks.");
|
LOG_DEBUG("sql.updates", ">> Update is archived and marked as archived in database, skipping redundancy checks.");
|
||||||
applied.erase(iter);
|
applied.erase(iter);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const hash = ByteArrayToHexStr(Warhead::Crypto::SHA1::GetDigestOf(ReadSQLUpdate(availableQuery.first)));
|
std::string const hash = ByteArrayToHexStr(Acore::Crypto::SHA1::GetDigestOf(ReadSQLUpdate(filePath)));
|
||||||
|
|
||||||
UpdateMode mode = MODE_APPLY;
|
UpdateMode mode = MODE_APPLY;
|
||||||
|
|
||||||
@@ -244,6 +250,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks,
|
|||||||
{
|
{
|
||||||
// Check if the original file was removed. If not, we've got a problem.
|
// Check if the original file was removed. If not, we've got a problem.
|
||||||
LocaleFileStorage::const_iterator localeIter;
|
LocaleFileStorage::const_iterator localeIter;
|
||||||
|
|
||||||
// Push localeIter forward
|
// Push localeIter forward
|
||||||
for (localeIter = available.begin(); (localeIter != available.end()) &&
|
for (localeIter = available.begin(); (localeIter != available.end()) &&
|
||||||
(localeIter->first.filename().string() != hashIter->second); ++localeIter);
|
(localeIter->first.filename().string() != hashIter->second); ++localeIter);
|
||||||
@@ -253,25 +260,24 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks,
|
|||||||
{
|
{
|
||||||
LOG_WARN("sql.updates", ">> It seems like the update \"%s\" \'%s\' was renamed, but the old file is still there! " \
|
LOG_WARN("sql.updates", ">> It seems like the update \"%s\" \'%s\' was renamed, but the old file is still there! " \
|
||||||
"Treating it as a new file! (It is probably an unmodified copy of the file \"%s\")",
|
"Treating it as a new file! (It is probably an unmodified copy of the file \"%s\")",
|
||||||
availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str(),
|
filePath.filename().string().c_str(), hash.substr(0, 7).c_str(),
|
||||||
localeIter->first.filename().string().c_str());
|
localeIter->first.filename().string().c_str());
|
||||||
}
|
}
|
||||||
// It is safe to treat the file as renamed here
|
else // It is safe to treat the file as renamed here
|
||||||
else
|
|
||||||
{
|
{
|
||||||
LOG_INFO("sql.updates", ">> Renaming update \"%s\" to \"%s\" \'%s\'.",
|
LOG_INFO("sql.updates", ">> Renaming update \"%s\" to \"%s\" \'%s\'.",
|
||||||
hashIter->second.c_str(), availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str());
|
hashIter->second.c_str(), filePath.filename().string().c_str(), hash.substr(0, 7).c_str());
|
||||||
|
|
||||||
RenameEntry(hashIter->second, availableQuery.first.filename().string());
|
RenameEntry(hashIter->second, filePath.filename().string());
|
||||||
applied.erase(hashIter->second);
|
applied.erase(hashIter->second);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Apply the update if it was never seen before.
|
// Apply the update if it was never seen before.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_INFO("sql.updates", ">> Applying update \"%s\" \'%s\'...",
|
LOG_INFO("sql.updates", ">> Applying update \"%s\" \'%s\'...",
|
||||||
availableQuery.first.filename().string().c_str(), hash.substr(0, 7).c_str());
|
filePath.filename().string().c_str(), hash.substr(0, 7).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Rehash the update entry if it exists in our database with an empty hash.
|
// Rehash the update entry if it exists in our database with an empty hash.
|
||||||
@@ -279,42 +285,42 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks,
|
|||||||
{
|
{
|
||||||
mode = MODE_REHASH;
|
mode = MODE_REHASH;
|
||||||
|
|
||||||
LOG_INFO("sql.updates", ">> Re-hashing update \"%s\" \'%s\'...", availableQuery.first.filename().string().c_str(),
|
LOG_INFO("sql.updates", ">> Re-hashing update \"%s\" \'%s\'...", filePath.filename().string().c_str(),
|
||||||
hash.substr(0, 7).c_str());
|
hash.substr(0, 7).c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the hash of the files differs from the one stored in our database, reapply the update (because it changed).
|
// If the hash of the files differs from the one stored in our database, reapply the update (because it changed).
|
||||||
if (iter->second.hash != hash)
|
if (iter->second.hash != hash)
|
||||||
{
|
{
|
||||||
LOG_INFO("sql.updates", ">> Reapplying update \"%s\" \'%s\' -> \'%s\' (it changed)...", availableQuery.first.filename().string().c_str(),
|
LOG_INFO("sql.updates", ">> Reapplying update \"%s\" \'%s\' -> \'%s\' (it changed)...", filePath.filename().string().c_str(),
|
||||||
iter->second.hash.substr(0, 7).c_str(), hash.substr(0, 7).c_str());
|
iter->second.hash.substr(0, 7).c_str(), hash.substr(0, 7).c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the file wasn't changed and just moved, update its state (if necessary).
|
// If the file wasn't changed and just moved, update its state (if necessary).
|
||||||
if (iter->second.state != availableQuery.second)
|
if (iter->second.state != fileState)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("sql.updates", ">> Updating the state of \"%s\" to \'%s\'...",
|
LOG_DEBUG("sql.updates", ">> Updating the state of \"%s\" to \'%s\'...",
|
||||||
availableQuery.first.filename().string().c_str(), AppliedFileEntry::StateConvert(availableQuery.second).c_str());
|
filePath.filename().string().c_str(), AppliedFileEntry::StateConvert(fileState).c_str());
|
||||||
|
|
||||||
UpdateState(availableQuery.first.filename().string(), availableQuery.second);
|
UpdateState(filePath.filename().string(), fileState);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("sql.updates", ">> Update is already applied and matches the hash \'%s\'.", hash.substr(0, 7).c_str());
|
LOG_DEBUG("sql.updates", ">> Update is already applied and matches the hash \'%s\'.", hash.substr(0, 7).c_str());
|
||||||
|
|
||||||
applied.erase(iter);
|
applied.erase(iter);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 speed = 0;
|
uint32 speed = 0;
|
||||||
AppliedFileEntry const file = { availableQuery.first.filename().string(), hash, availableQuery.second, 0 };
|
AppliedFileEntry const file = { filePath.filename().string(), hash, fileState, 0 };
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case MODE_APPLY:
|
case MODE_APPLY:
|
||||||
speed = Apply(availableQuery.first);
|
speed = Apply(filePath);
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case MODE_REHASH:
|
case MODE_REHASH:
|
||||||
UpdateEntry(file, speed);
|
UpdateEntry(file, speed);
|
||||||
@@ -326,6 +332,20 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks,
|
|||||||
|
|
||||||
if (mode == MODE_APPLY)
|
if (mode == MODE_APPLY)
|
||||||
++importedUpdates;
|
++importedUpdates;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply default updates
|
||||||
|
for (auto const& availableQuery : available)
|
||||||
|
{
|
||||||
|
if (availableQuery.second != CUSTOM)
|
||||||
|
ApplyUpdateFile(availableQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply only custom updates
|
||||||
|
for (auto const& availableQuery : available)
|
||||||
|
{
|
||||||
|
if (availableQuery.second == CUSTOM)
|
||||||
|
ApplyUpdateFile(availableQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup up orphaned entries (if enabled)
|
// Cleanup up orphaned entries (if enabled)
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ private:
|
|||||||
enum State
|
enum State
|
||||||
{
|
{
|
||||||
RELEASED,
|
RELEASED,
|
||||||
|
CUSTOM,
|
||||||
ARCHIVED
|
ARCHIVED
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,21 +65,33 @@ private:
|
|||||||
: name(name_), hash(hash_), state(state_), timestamp(timestamp_) { }
|
: name(name_), hash(hash_), state(state_), timestamp(timestamp_) { }
|
||||||
|
|
||||||
std::string const name;
|
std::string const name;
|
||||||
|
|
||||||
std::string const hash;
|
std::string const hash;
|
||||||
|
|
||||||
State const state;
|
State const state;
|
||||||
|
|
||||||
uint64 const timestamp;
|
uint64 const timestamp;
|
||||||
|
|
||||||
static inline State StateConvert(std::string const& state)
|
static inline State StateConvert(std::string const& state)
|
||||||
{
|
{
|
||||||
return (state == "RELEASED") ? RELEASED : ARCHIVED;
|
if (state == "RELEASED")
|
||||||
|
return RELEASED;
|
||||||
|
else if (state == "CUSTOM")
|
||||||
|
return CUSTOM;
|
||||||
|
|
||||||
|
return ARCHIVED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline std::string StateConvert(State const state)
|
static inline std::string StateConvert(State const state)
|
||||||
{
|
{
|
||||||
return (state == RELEASED) ? "RELEASED" : "ARCHIVED";
|
switch (state)
|
||||||
|
{
|
||||||
|
case RELEASED:
|
||||||
|
return "RELEASED";
|
||||||
|
case CUSTOM:
|
||||||
|
return "CUSTOM";
|
||||||
|
case ARCHIVED:
|
||||||
|
return "ARCHIVED";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetStateAsString() const
|
std::string GetStateAsString() const
|
||||||
|
|||||||
@@ -3461,4 +3461,3 @@ uint32 World::GetNextWhoListUpdateDelaySecs()
|
|||||||
|
|
||||||
return uint32(ceil(t / 1000.0f));
|
return uint32(ceil(t / 1000.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
# CHARACTER DELETE OPTIONS
|
# CHARACTER DELETE OPTIONS
|
||||||
# ITEM DELETE OPTIONS
|
# ITEM DELETE OPTIONS
|
||||||
# CUSTOM SERVER OPTIONS
|
# CUSTOM SERVER OPTIONS
|
||||||
|
# UPDATE SETTINGS
|
||||||
# LOGGING SYSTEM SETTINGS
|
# LOGGING SYSTEM SETTINGS
|
||||||
# PACKET SPOOF PROTECTION SETTINGS
|
# PACKET SPOOF PROTECTION SETTINGS
|
||||||
# DEBUG
|
# DEBUG
|
||||||
@@ -157,6 +158,45 @@ WorldServerPort = 8085
|
|||||||
|
|
||||||
BindIP = "0.0.0.0"
|
BindIP = "0.0.0.0"
|
||||||
|
|
||||||
|
#
|
||||||
|
# CMakeCommand
|
||||||
|
# Description: The path to your CMake binary.
|
||||||
|
# If the path is left empty, the built-in CMAKE_COMMAND is used.
|
||||||
|
# Example: "C:/Program Files/CMake/bin/cmake.exe"
|
||||||
|
# "/usr/bin/cmake"
|
||||||
|
# Default: ""
|
||||||
|
|
||||||
|
CMakeCommand = ""
|
||||||
|
|
||||||
|
#
|
||||||
|
# BuildDirectory
|
||||||
|
# Description: The path to your build directory.
|
||||||
|
# If the path is left empty, the built-in CMAKE_BINARY_DIR is used.
|
||||||
|
# Example: "../AzerothCore"
|
||||||
|
# Default: ""
|
||||||
|
|
||||||
|
BuildDirectory = ""
|
||||||
|
|
||||||
|
#
|
||||||
|
# SourceDirectory
|
||||||
|
# Description: The path to your AzerothCore source directory.
|
||||||
|
# If the path is left empty, the built-in CMAKE_SOURCE_DIR is used.
|
||||||
|
# Example: "../AzerothCore"
|
||||||
|
# Default: ""
|
||||||
|
|
||||||
|
SourceDirectory = ""
|
||||||
|
|
||||||
|
#
|
||||||
|
# MySQLExecutable
|
||||||
|
# Description: The path to your MySQL CLI binary.
|
||||||
|
# If the path is left empty, built-in path from cmake is used.
|
||||||
|
# Example: "C:/Program Files/MySQL/MySQL Server 5.7/bin/mysql.exe"
|
||||||
|
# "mysql.exe"
|
||||||
|
# "/usr/bin/mysql"
|
||||||
|
# Default: ""
|
||||||
|
|
||||||
|
MySQLExecutable = ""
|
||||||
|
|
||||||
#
|
#
|
||||||
# IPLocationFile
|
# IPLocationFile
|
||||||
# Description: The path to your IP2Location database CSV file.
|
# Description: The path to your IP2Location database CSV file.
|
||||||
@@ -1249,6 +1289,72 @@ TOTPMasterSecret =
|
|||||||
#
|
#
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
|
|
||||||
|
###################################################################################################
|
||||||
|
# UPDATE SETTINGS
|
||||||
|
#
|
||||||
|
# Updates.EnableDatabases
|
||||||
|
# Description: A mask that describes which databases shall be updated.
|
||||||
|
#
|
||||||
|
# Following flags are available
|
||||||
|
# DATABASE_LOGIN = 1, // Auth database
|
||||||
|
# DATABASE_CHARACTER = 2, // Character database
|
||||||
|
# DATABASE_WORLD = 4, // World database
|
||||||
|
#
|
||||||
|
# Default: 7 - (All enabled)
|
||||||
|
# 4 - (Enable world only)
|
||||||
|
# 0 - (All disabled)
|
||||||
|
|
||||||
|
Updates.EnableDatabases = 7
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.AutoSetup
|
||||||
|
# Description: Auto populate empty databases.
|
||||||
|
# Default: 1 - (Enabled)
|
||||||
|
# 0 - (Disabled)
|
||||||
|
|
||||||
|
Updates.AutoSetup = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.Redundancy
|
||||||
|
# Description: Perform data redundancy checks through hashing
|
||||||
|
# to detect changes on sql updates and reapply it.
|
||||||
|
# Default: 1 - (Enabled)
|
||||||
|
# 0 - (Disabled)
|
||||||
|
|
||||||
|
Updates.Redundancy = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.ArchivedRedundancy
|
||||||
|
# Description: Check hashes of archived updates (slows down startup).
|
||||||
|
# Default: 0 - (Disabled)
|
||||||
|
# 1 - (Enabled)
|
||||||
|
|
||||||
|
Updates.ArchivedRedundancy = 0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.AllowRehash
|
||||||
|
# Description: Inserts the current file hash in the database if it is left empty.
|
||||||
|
# Useful if you want to mark a file as applied but you don't know its hash.
|
||||||
|
# Default: 1 - (Enabled)
|
||||||
|
# 0 - (Disabled)
|
||||||
|
|
||||||
|
Updates.AllowRehash = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Updates.CleanDeadRefMaxCount
|
||||||
|
# Description: Cleans dead/ orphaned references that occur if an update was removed or renamed and edited in one step.
|
||||||
|
# It only starts the clean up if the count of the missing updates is below or equal the Updates.CleanDeadRefMaxCount value.
|
||||||
|
# This way prevents erasing of the update history due to wrong source directory state (maybe wrong branch or bad revision).
|
||||||
|
# Disable this if you want to know if the database is in a possible "dirty state".
|
||||||
|
# Default: 3 - (Enabled)
|
||||||
|
# 0 - (Disabled)
|
||||||
|
# -1 - (Enabled - unlimited)
|
||||||
|
|
||||||
|
Updates.CleanDeadRefMaxCount = 3
|
||||||
|
|
||||||
|
#
|
||||||
|
###################################################################################################
|
||||||
|
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
# WARDEN SETTINGS
|
# WARDEN SETTINGS
|
||||||
#
|
#
|
||||||
|
|||||||
Reference in New Issue
Block a user