config: support env-based SQL overrides
This commit is contained in:
248
src/db/Main.cpp
248
src/db/Main.cpp
@@ -47,6 +47,15 @@ extern void WriteVersion();
|
||||
|
||||
namespace
|
||||
{
|
||||
struct SQLConnectionConfig
|
||||
{
|
||||
char host[64];
|
||||
char database[64];
|
||||
char user[64];
|
||||
char password[64];
|
||||
int port;
|
||||
};
|
||||
|
||||
const char* BoolState(bool value)
|
||||
{
|
||||
return value ? "on" : "off";
|
||||
@@ -57,6 +66,112 @@ const char* EmptyToLabel(const std::string& value, const char* fallback)
|
||||
return value.empty() ? fallback : value.c_str();
|
||||
}
|
||||
|
||||
bool CopyEnvString(const char* env_name, char* dest, size_t dest_size)
|
||||
{
|
||||
const char* value = std::getenv(env_name);
|
||||
if (!value)
|
||||
return false;
|
||||
|
||||
strlcpy(dest, value, dest_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CopyEnvInt(const char* env_name, int* dest)
|
||||
{
|
||||
const char* value = std::getenv(env_name);
|
||||
if (!value)
|
||||
return false;
|
||||
|
||||
str_to_number(*dest, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasSQLConfig(const SQLConnectionConfig& config)
|
||||
{
|
||||
return config.host[0] && config.database[0] && config.user[0] && config.password[0];
|
||||
}
|
||||
|
||||
bool ParseSQLConfig(const char* value, SQLConnectionConfig* config, const char* label)
|
||||
{
|
||||
int token_count = sscanf(
|
||||
value,
|
||||
" %63s %63s %63s %63s %d ",
|
||||
config->host,
|
||||
config->database,
|
||||
config->user,
|
||||
config->password,
|
||||
&config->port);
|
||||
|
||||
if (token_count < 4 || !HasSQLConfig(*config))
|
||||
{
|
||||
fprintf(stderr, "%s syntax: <host db user password [port]>\n", label);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadSQLConfig(const char* key, const char* env_prefix, SQLConnectionConfig* config)
|
||||
{
|
||||
char line[256 + 1];
|
||||
bool loaded_from_file = false;
|
||||
|
||||
if (CConfig::instance().GetValue(key, line, sizeof(line) - 1))
|
||||
{
|
||||
if (!ParseSQLConfig(line, config, key))
|
||||
return false;
|
||||
|
||||
loaded_from_file = true;
|
||||
}
|
||||
|
||||
bool overridden = false;
|
||||
const std::string prefix = env_prefix;
|
||||
overridden |= CopyEnvString((prefix + "_HOST").c_str(), config->host, sizeof(config->host));
|
||||
overridden |= CopyEnvString((prefix + "_DB").c_str(), config->database, sizeof(config->database));
|
||||
overridden |= CopyEnvString((prefix + "_USER").c_str(), config->user, sizeof(config->user));
|
||||
overridden |= CopyEnvString((prefix + "_PASSWORD").c_str(), config->password, sizeof(config->password));
|
||||
overridden |= CopyEnvInt((prefix + "_PORT").c_str(), &config->port);
|
||||
|
||||
if (overridden)
|
||||
sys_log(0, "CONFIG: %s overridden from environment", key);
|
||||
|
||||
if (!loaded_from_file && !overridden)
|
||||
{
|
||||
sys_err("%s not configured", key);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasSQLConfig(*config))
|
||||
{
|
||||
sys_err("%s incomplete after applying config/environment overrides", key);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConnectDatabase(int slot, const SQLConnectionConfig& config, const char* label)
|
||||
{
|
||||
sys_log(0, "connecting to MySQL server (%s)", label);
|
||||
|
||||
int retry_count = 5;
|
||||
do
|
||||
{
|
||||
if (CDBManager::instance().Connect(slot, config.host, config.port, config.database, config.user, config.password))
|
||||
{
|
||||
sys_log(0, " OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
sys_log(0, " failed, retrying in 5 seconds");
|
||||
fprintf(stderr, " failed, retrying in 5 seconds");
|
||||
sleep(5);
|
||||
}
|
||||
while (retry_count--);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LogStartupSummary(int heart_fps, int player_id_start)
|
||||
{
|
||||
sys_log(0,
|
||||
@@ -274,120 +389,43 @@ int Start()
|
||||
g_stLocaleNameColumn = szBuf;
|
||||
}
|
||||
|
||||
char szAddr[64], szDB[64], szUser[64], szPassword[64];
|
||||
int iPort;
|
||||
char line[256+1];
|
||||
SQLConnectionConfig player_sql = {};
|
||||
SQLConnectionConfig account_sql = {};
|
||||
SQLConnectionConfig common_sql = {};
|
||||
SQLConnectionConfig hotbackup_sql = {};
|
||||
|
||||
if (CConfig::instance().GetValue("SQL_PLAYER", line, 256))
|
||||
{
|
||||
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
|
||||
sys_log(0, "connecting to MySQL server (player)");
|
||||
|
||||
int iRetry = 5;
|
||||
|
||||
do
|
||||
{
|
||||
if (CDBManager::instance().Connect(SQL_PLAYER, szAddr, iPort, szDB, szUser, szPassword))
|
||||
{
|
||||
sys_log(0, " OK");
|
||||
break;
|
||||
}
|
||||
|
||||
sys_log(0, " failed, retrying in 5 seconds");
|
||||
fprintf(stderr, " failed, retrying in 5 seconds");
|
||||
sleep(5);
|
||||
} while (iRetry--);
|
||||
fprintf(stderr, "Success PLAYER\n");
|
||||
SetPlayerDBName(szDB);
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_err("SQL_PLAYER not configured");
|
||||
if (!LoadSQLConfig("SQL_PLAYER", "METIN2_PLAYER_SQL", &player_sql))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CConfig::instance().GetValue("SQL_ACCOUNT", line, 256))
|
||||
{
|
||||
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
|
||||
sys_log(0, "connecting to MySQL server (account)");
|
||||
|
||||
int iRetry = 5;
|
||||
|
||||
do
|
||||
{
|
||||
if (CDBManager::instance().Connect(SQL_ACCOUNT, szAddr, iPort, szDB, szUser, szPassword))
|
||||
{
|
||||
sys_log(0, " OK");
|
||||
break;
|
||||
}
|
||||
|
||||
sys_log(0, " failed, retrying in 5 seconds");
|
||||
fprintf(stderr, " failed, retrying in 5 seconds");
|
||||
sleep(5);
|
||||
} while (iRetry--);
|
||||
fprintf(stderr, "Success ACCOUNT\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_err("SQL_ACCOUNT not configured");
|
||||
if (!ConnectDatabase(SQL_PLAYER, player_sql, "player"))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CConfig::instance().GetValue("SQL_COMMON", line, 256))
|
||||
{
|
||||
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
|
||||
sys_log(0, "connecting to MySQL server (common)");
|
||||
fprintf(stderr, "Success PLAYER\n");
|
||||
SetPlayerDBName(player_sql.database);
|
||||
|
||||
int iRetry = 5;
|
||||
|
||||
do
|
||||
{
|
||||
if (CDBManager::instance().Connect(SQL_COMMON, szAddr, iPort, szDB, szUser, szPassword))
|
||||
{
|
||||
sys_log(0, " OK");
|
||||
break;
|
||||
}
|
||||
|
||||
sys_log(0, " failed, retrying in 5 seconds");
|
||||
fprintf(stderr, " failed, retrying in 5 seconds");
|
||||
sleep(5);
|
||||
} while (iRetry--);
|
||||
fprintf(stderr, "Success COMMON\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_err("SQL_COMMON not configured");
|
||||
if (!LoadSQLConfig("SQL_ACCOUNT", "METIN2_ACCOUNT_SQL", &account_sql))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CConfig::instance().GetValue("SQL_HOTBACKUP", line, 256))
|
||||
{
|
||||
sscanf(line, " %s %s %s %s %d ", szAddr, szDB, szUser, szPassword, &iPort);
|
||||
sys_log(0, "connecting to MySQL server (hotbackup)");
|
||||
|
||||
int iRetry = 5;
|
||||
|
||||
do
|
||||
{
|
||||
if (CDBManager::instance().Connect(SQL_HOTBACKUP, szAddr, iPort, szDB, szUser, szPassword))
|
||||
{
|
||||
sys_log(0, " OK");
|
||||
break;
|
||||
}
|
||||
|
||||
sys_log(0, " failed, retrying in 5 seconds");
|
||||
fprintf(stderr, " failed, retrying in 5 seconds");
|
||||
sleep(5);
|
||||
}
|
||||
while (iRetry--);
|
||||
|
||||
fprintf(stderr, "Success HOTBACKUP\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_err("SQL_HOTBACKUP not configured");
|
||||
if (!ConnectDatabase(SQL_ACCOUNT, account_sql, "account"))
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Success ACCOUNT\n");
|
||||
|
||||
if (!LoadSQLConfig("SQL_COMMON", "METIN2_COMMON_SQL", &common_sql))
|
||||
return false;
|
||||
|
||||
if (!ConnectDatabase(SQL_COMMON, common_sql, "common"))
|
||||
return false;
|
||||
|
||||
fprintf(stderr, "Success COMMON\n");
|
||||
|
||||
if (!LoadSQLConfig("SQL_HOTBACKUP", "METIN2_HOTBACKUP_SQL", &hotbackup_sql))
|
||||
return false;
|
||||
|
||||
if (!ConnectDatabase(SQL_HOTBACKUP, hotbackup_sql, "hotbackup"))
|
||||
return false;
|
||||
|
||||
fprintf(stderr, "Success HOTBACKUP\n");
|
||||
|
||||
if (!CNetPoller::instance().Create())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user