jiateng_ws/utils/config_loader.py
2025-06-13 17:14:03 +08:00

299 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import json
import logging
class ConfigLoader:
"""配置加载器,用于加载和管理应用配置"""
_instance = None
@classmethod
def get_instance(cls):
"""获取单例实例"""
if cls._instance is None:
cls._instance = ConfigLoader()
return cls._instance
def __init__(self):
"""初始化配置加载器"""
self.config = {}
self.config_file = os.path.join('config', 'app_config.json')
# 创建配置目录(如果不存在)
os.makedirs('config', exist_ok=True)
# 加载配置
self.load_config()
def load_config(self):
"""加载配置文件"""
try:
if os.path.exists(self.config_file):
with open(self.config_file, 'r', encoding='utf-8') as f:
self.config = json.load(f)
logging.info(f"已加载配置文件: {self.config_file}")
# 检查并升级配置文件结构(兼容旧版本的配置)
self._upgrade_config_if_needed()
else:
# 创建默认配置
self.config = {
"app": {
"name": "腾智微丝产线包装系统",
"version": "1.0.0",
"features": {
"enable_serial_ports": False,
"enable_keyboard_listener": False,
"enable_camera": False
}
},
"database": {
"current": "sqlite",
"sources": {
"sqlite": {
"path": "db/jtDB.db",
"description": "默认SQLite数据库"
},
"postgresql": {
"host": "localhost",
"port": "5432",
"user": "postgres",
"password": "",
"name": "jtDB",
"description": ""
},
"mysql": {
"host": "localhost",
"port": "3306",
"user": "root",
"password": "",
"name": "jtDB",
"description": ""
}
}
},
"camera": {
"enabled": False,
"default_exposure": 20000,
"default_gain": 10,
"default_framerate": 30
},
"modbus": {
"host": "localhost",
"port": "5020"
},
"serial": {
"keyboard": {
"trigger_key": "Key.page_up",
"enabled": False
}
}
}
# 保存默认配置
self.save_config()
logging.info(f"已创建默认配置文件: {self.config_file}")
except Exception as e:
logging.error(f"加载配置文件失败: {e}")
# 使用默认配置
self.config = {
"app": {
"name": "腾智微丝产线包装系统",
"version": "1.0.0",
"features": {
"enable_serial_ports": False,
"enable_keyboard_listener": False,
"enable_camera": False
}
},
"database": {
"current": "sqlite",
"sources": {
"sqlite": {
"path": "db/jtDB.db",
"description": "默认SQLite数据库"
}
}
}
}
def _upgrade_config_if_needed(self):
"""升级配置文件结构(兼容旧版本的配置)"""
try:
# 检查数据库配置是否需要升级
if 'database' in self.config:
db_config = self.config['database']
# 旧版本配置结构检查
if 'type' in db_config and 'sources' not in db_config:
logging.info("检测到旧版本的数据库配置,正在升级...")
# 获取旧配置
db_type = db_config.get('type', 'sqlite')
# 创建新的配置结构
new_db_config = {
"default": db_type,
"sources": {}
}
# 转移旧配置到新结构
if db_type == 'sqlite':
new_db_config['sources']['sqlite'] = {
"path": db_config.get('path', 'db/jtDB.db'),
"description": "从旧版本升级的SQLite数据库"
}
else:
new_db_config['sources'][db_type] = {
"host": db_config.get('host', 'localhost'),
"port": db_config.get('port', '5432' if db_type == 'postgresql' else '3306'),
"user": db_config.get('user', ''),
"password": db_config.get('password', ''),
"name": db_config.get('name', 'jtDB'),
"description": f"从旧版本升级的{db_type}数据库"
}
# 确保至少有一个sqlite配置
if 'sqlite' not in new_db_config['sources']:
new_db_config['sources']['sqlite'] = {
"path": "db/jtDB.db",
"description": "默认SQLite数据库"
}
# 更新配置
self.config['database'] = new_db_config
self.save_config()
logging.info("数据库配置已成功升级")
# 将current改为default
if 'current' in db_config and 'default' not in db_config:
logging.info("将数据库配置中的'current'改为'default'...")
db_config['default'] = db_config.pop('current')
self.save_config()
# 将pgsql改为postgresql
if 'sources' in db_config and 'pgsql' in db_config['sources'] and 'postgresql' not in db_config['sources']:
logging.info("将数据库配置中的'pgsql'改为'postgresql'...")
db_config['sources']['postgresql'] = db_config['sources'].pop('pgsql')
# 如果默认值是pgsql也更新
if db_config.get('default') == 'pgsql':
db_config['default'] = 'postgresql'
self.save_config()
except Exception as e:
logging.error(f"升级配置文件结构失败: {e}")
def save_config(self):
"""保存配置到文件"""
try:
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(self.config, f, indent=4, ensure_ascii=False)
logging.info(f"已保存配置文件: {self.config_file}")
return True
except Exception as e:
logging.error(f"保存配置文件失败: {e}")
return False
def get_value(self, key_path, default=None):
"""
获取配置值
Args:
key_path: 配置键路径,例如 "app.features.enable_serial_ports"
default: 默认值,如果配置项不存在则返回此值
Returns:
配置值或默认值
"""
keys = key_path.split('.')
value = self.config
try:
for key in keys:
value = value[key]
return value
except (KeyError, TypeError):
return default
def set_value(self, key_path, value):
"""
设置配置值
Args:
key_path: 配置键路径,例如 "app.features.enable_serial_ports"
value: 要设置的值
Returns:
bool: 是否设置成功
"""
keys = key_path.split('.')
config = self.config
# 遍历路径中的所有键,除了最后一个
for key in keys[:-1]:
if key not in config:
config[key] = {}
config = config[key]
# 设置最后一个键的值
config[keys[-1]] = value
# 保存配置
return self.save_config()
def get_config(self, key):
"""
获取serial配置下的指定配置
Args:
key: 配置键,例如'mdz', 'cz'
Returns:
dict: 配置值未找到则返回None
"""
if 'serial' not in self.config:
self.config['serial'] = {}
if key not in self.config['serial']:
return None
return self.config['serial'][key]
def set_config(self, key, config_data):
"""
设置serial配置下的指定配置
Args:
key: 配置键,例如'mdz', 'cz'
config_data: 要设置的配置数据
Returns:
bool: 是否设置成功
"""
if 'serial' not in self.config:
self.config['serial'] = {}
self.config['serial'][key] = config_data
# 这里不保存配置等待调用save_config方法时一并保存
return True
def get_database_config(self, db_type=None):
"""
获取指定类型的数据库配置
Args:
db_type: 数据库类型,如'sqlite', 'postgresql', 'mysql'等,不指定则使用默认配置
Returns:
dict: 数据库配置
"""
# 如果未指定数据库类型,使用当前设置的类型
if db_type is None:
db_type = self.get_value('database.default', 'sqlite')
# 处理pgsql和postgresql兼容
if db_type == 'pgsql':
db_type = 'postgresql'
# 获取数据库配置
return self.get_value(f'database.sources.{db_type}', {})