You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Software_Architecture/src/Client/src/utils/ConfigManager.cpp

284 lines
8.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* @file ConfigManager.cpp
* @brief 配置管理器实现
* @author BattlefieldExplorationSystem Team
* @date 2025-7
* @version 2.0
*/
#include "utils/ConfigManager.h"
// C++标准库头文件
#include <iostream>
// Qt头文件
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDebug>
#include <QDir>
#include <QStandardPaths>
// 静态成员初始化
std::unique_ptr<ConfigManager> ConfigManager::m_instance = nullptr;
std::mutex ConfigManager::m_instanceMutex;
ConfigManager& ConfigManager::getInstance()
{
std::lock_guard<std::mutex> lock(m_instanceMutex);
if (!m_instance) {
// 使用make_unique需要public构造函数这里使用reset
m_instance.reset(new ConfigManager());
}
return *m_instance;
}
ConfigManager::ConfigManager(QObject* parent)
: QObject(parent)
, m_initialized(false)
{
// 私有构造函数仅供getInstance调用
}
ConfigManager::~ConfigManager()
{
if (m_settings && m_initialized) {
save();
}
}
bool ConfigManager::initialize(const QString& configFilePath)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_initialized) {
qWarning() << "ConfigManager already initialized";
return true;
}
// 确定配置文件路径
if (configFilePath.isEmpty()) {
// 使用默认路径
QString configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
QDir().mkpath(configDir);
m_configFilePath = configDir + "/config.ini";
} else {
m_configFilePath = configFilePath;
}
// 创建QSettings对象
m_settings = std::make_unique<QSettings>(m_configFilePath, QSettings::IniFormat);
m_settings->setIniCodec("UTF-8");
// 加载默认配置
loadDefaultConfig();
// 从环境变量加载敏感配置
loadFromEnvironment();
m_initialized = true;
qDebug() << "ConfigManager initialized with config file:" << m_configFilePath;
return true;
}
void ConfigManager::loadDefaultConfig()
{
// 数据库默认配置
if (!m_settings->contains(KEY_DB_HOST)) {
m_settings->setValue(KEY_DB_HOST, "localhost");
}
if (!m_settings->contains(KEY_DB_PORT)) {
m_settings->setValue(KEY_DB_PORT, 3306);
}
if (!m_settings->contains(KEY_DB_NAME)) {
m_settings->setValue(KEY_DB_NAME, "Client");
}
if (!m_settings->contains(KEY_DB_USER)) {
m_settings->setValue(KEY_DB_USER, "root");
}
// UI默认配置
if (!m_settings->contains("ui/window_width")) {
m_settings->setValue("ui/window_width", 1400);
}
if (!m_settings->contains("ui/window_height")) {
m_settings->setValue("ui/window_height", 1000);
}
if (!m_settings->contains("ui/window_margin")) {
m_settings->setValue("ui/window_margin", 100);
}
// 系统默认配置
if (!m_settings->contains("system/log_level")) {
m_settings->setValue("system/log_level", "INFO");
}
if (!m_settings->contains("system/auto_save_interval")) {
m_settings->setValue("system/auto_save_interval", 300); // 5分钟
}
}
void ConfigManager::loadFromEnvironment()
{
// 简化配置加载,使用固定的数据库配置便于项目交接
qDebug() << "Loading default database configuration for project handover";
// 可选:仍然支持从环境变量加载数据库主机(如果需要)
const char* dbHost = std::getenv("BES_DB_HOST");
if (dbHost && strlen(dbHost) > 0) {
m_settings->setValue(KEY_DB_HOST, QString::fromUtf8(dbHost));
qDebug() << "Using database host from environment:" << dbHost;
}
// 可选:仍然支持从环境变量加载数据库用户名(如果需要)
const char* dbUser = std::getenv("BES_DB_USER");
if (dbUser && strlen(dbUser) > 0) {
m_settings->setValue(KEY_DB_USER, QString::fromUtf8(dbUser));
qDebug() << "Using database user from environment:" << dbUser;
}
}
QString ConfigManager::getDatabaseHost() const
{
return getValue<QString>(KEY_DB_HOST, "localhost");
}
int ConfigManager::getDatabasePort() const
{
return getValue<int>(KEY_DB_PORT, 3306);
}
QString ConfigManager::getDatabaseName() const
{
return getValue<QString>(KEY_DB_NAME, "Client");
}
QString ConfigManager::getDatabaseUser() const
{
return getValue<QString>(KEY_DB_USER, "root");
}
QString ConfigManager::getDatabasePassword() const
{
// 优先使用环境变量,然后是配置文件,最后是默认值
// Priority: Environment variable > Configuration file > Default value
// 1. 检查环境变量
QString envPassword = qgetenv("BES_DB_PASSWORD");
if (!envPassword.isEmpty()) {
qDebug() << "Using database password from environment variable";
return envPassword;
}
// 2. 从配置文件读取
QString configPassword = getValue<QString>(KEY_DB_PASSWORD, "");
if (!configPassword.isEmpty()) {
qDebug() << "Using database password from configuration file";
return decryptString(configPassword);
}
// 3. 使用默认值(仅用于向后兼容)
qDebug() << "Using default database password (consider setting BES_DB_PASSWORD environment variable)";
return QString("your_password_here");
}
void ConfigManager::setDatabaseConfig(const QString& host, int port, const QString& database,
const QString& user, const QString& password)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
m_settings->setValue(KEY_DB_HOST, host);
m_settings->setValue(KEY_DB_PORT, port);
m_settings->setValue(KEY_DB_NAME, database);
m_settings->setValue(KEY_DB_USER, user);
if (!password.isEmpty()) {
QString encryptedPassword = encryptString(password);
m_settings->setValue(KEY_DB_PASSWORD, encryptedPassword);
}
m_settings->sync();
}
// 发送配置变更信号
emit configurationChanged("database");
}
bool ConfigManager::contains(const QString& key) const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_settings->contains(key);
}
void ConfigManager::remove(const QString& key)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
m_settings->remove(key);
m_settings->sync();
}
emit configurationChanged(key);
}
void ConfigManager::save()
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_settings) {
m_settings->sync();
qDebug() << "Configuration saved to:" << m_configFilePath;
}
}
void ConfigManager::reload()
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_settings) {
m_settings->sync();
loadFromEnvironment(); // 重新加载环境变量
qDebug() << "Configuration reloaded from:" << m_configFilePath;
}
}
QString ConfigManager::encryptString(const QString& plainText) const
{
if (plainText.isEmpty()) {
return QString();
}
// 简单的加密实现(实际项目中应使用更强的加密算法)
QByteArray key = generateKey();
QByteArray data = plainText.toUtf8();
// 异或加密
for (int i = 0; i < data.size(); ++i) {
data[i] = data[i] ^ key[i % key.size()];
}
return QString::fromLatin1(data.toBase64());
}
QString ConfigManager::decryptString(const QString& encryptedText) const
{
if (encryptedText.isEmpty()) {
return QString();
}
QByteArray key = generateKey();
QByteArray data = QByteArray::fromBase64(encryptedText.toLatin1());
// 异或解密
for (int i = 0; i < data.size(); ++i) {
data[i] = data[i] ^ key[i % key.size()];
}
return QString::fromUtf8(data);
}
QByteArray ConfigManager::generateKey() const
{
// 基于应用程序信息生成密钥
QString keySource = QCoreApplication::applicationName() +
QCoreApplication::organizationName() +
"BattlefieldExplorationSystem";
return QCryptographicHash::hash(keySource.toUtf8(), QCryptographicHash::Sha256);
}