|
|
/**
|
|
|
* @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);
|
|
|
} |