Initial commit: SenSu Alpha 0.2.0
- 13-service async plugin framework - Textual TUI with CLI fallback - Plugin hot-reload + permission system - Web management panel (aiohttp) - Bridge-based inter-module communication - 10 regression tests Fixes applied: - PBKDF2-SHA256 auth (was plain SHA256) - Auth bypass removed (was allow-all on fail) - Bare excepts replaced with logged errors - CatFramework/DreamSu -> SenSu naming unified - ServiceManager: health checks + startup_order - Env var credentials (SENSU_ADMIN_PASSWORD etc)
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any
|
||||
import yaml
|
||||
import importlib.util
|
||||
import sys
|
||||
import os
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class InitService:
|
||||
"""初始化服务"""
|
||||
|
||||
def __init__(self, config_path: str = "config/framework"):
|
||||
self.config_path = Path(config_path)
|
||||
self.configs: Dict[str, Any] = {}
|
||||
self.fmfuncs_loaded = False
|
||||
logger.debug("InitService初始化开始")
|
||||
|
||||
async def initialize_framework(self):
|
||||
"""初始化框架"""
|
||||
try:
|
||||
logger.info("开始初始化框架")
|
||||
|
||||
# 1. 加载配置
|
||||
await self._load_configs()
|
||||
|
||||
# 2. 创建必要目录
|
||||
await self._create_directories()
|
||||
|
||||
# 3. 加载框架功能集
|
||||
await self._load_fmfuncs()
|
||||
|
||||
# 4. 验证初始化状态
|
||||
await self._validate_init()
|
||||
|
||||
logger.info("框架初始化完成")
|
||||
return self.configs
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"框架初始化失败: {str(e)}", exc_info=True)
|
||||
raise
|
||||
|
||||
async def _load_configs(self):
|
||||
"""加载配置文件"""
|
||||
try:
|
||||
logger.debug("开始加载配置文件")
|
||||
|
||||
if not self.config_path.exists():
|
||||
logger.warning(f"配置路径不存在: {self.config_path},将创建默认配置")
|
||||
self.config_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 加载基础配置
|
||||
base_config_file = self.config_path / "base_config.yaml"
|
||||
if base_config_file.exists():
|
||||
with open(base_config_file, 'r', encoding='utf-8') as f:
|
||||
self.configs['base'] = yaml.safe_load(f)
|
||||
logger.debug("基础配置加载成功")
|
||||
else:
|
||||
logger.warning("基础配置文件不存在,使用默认配置")
|
||||
self.configs['base'] = self._get_default_base_config()
|
||||
self._save_config(base_config_file, self.configs['base'])
|
||||
|
||||
# 加载权限规则
|
||||
permission_file = self.config_path / "permission_rules.yaml"
|
||||
if permission_file.exists():
|
||||
with open(permission_file, 'r', encoding='utf-8') as f:
|
||||
self.configs['permission_rules'] = yaml.safe_load(f)
|
||||
logger.debug("权限规则配置加载成功")
|
||||
else:
|
||||
logger.warning("权限规则文件不存在,使用默认配置")
|
||||
self.configs['permission_rules'] = self._get_default_permission_rules()
|
||||
self._save_config(permission_file, self.configs['permission_rules'])
|
||||
|
||||
logger.debug(f"配置文件加载完成,共加载 {len(self.configs)} 个配置集")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"加载配置文件时出错: {str(e)}", exc_info=True)
|
||||
raise
|
||||
|
||||
async def _create_directories(self):
|
||||
"""创建必要目录"""
|
||||
try:
|
||||
logger.debug("开始创建必要目录")
|
||||
|
||||
directories = [
|
||||
"config/plugins",
|
||||
"config/services",
|
||||
"config/permissions",
|
||||
"logs/runtime",
|
||||
"logs/debug",
|
||||
"plugins",
|
||||
"utils",
|
||||
"fmfuncs"
|
||||
]
|
||||
|
||||
for dir_path in directories:
|
||||
path = Path(dir_path)
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
logger.debug(f"创建目录: {dir_path}")
|
||||
|
||||
logger.debug("目录创建完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"创建目录时出错: {str(e)}", exc_info=True)
|
||||
raise
|
||||
|
||||
async def _load_fmfuncs(self):
|
||||
"""加载框架功能集"""
|
||||
try:
|
||||
logger.debug("开始加载框架功能集")
|
||||
|
||||
fmfuncs_path = Path(os.getenv("SENSU_CODE_DIR", ".")) / "fmfuncs"
|
||||
if not fmfuncs_path.exists():
|
||||
logger.warning("fmfuncs目录不存在,跳过加载")
|
||||
return
|
||||
|
||||
# 动态加载所有Python文件
|
||||
for py_file in fmfuncs_path.glob("*.py"):
|
||||
if py_file.name == "__init__.py":
|
||||
continue
|
||||
|
||||
try:
|
||||
module_name = f"fmfuncs.{py_file.stem}"
|
||||
spec = importlib.util.spec_from_file_location(module_name, py_file)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[module_name] = module
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
logger.debug(f"加载框架功能: {module_name}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"加载框架功能 {py_file} 时出错: {str(e)}", exc_info=True)
|
||||
continue
|
||||
|
||||
self.fmfuncs_loaded = True
|
||||
logger.debug("框架功能集加载完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"加载框架功能集时出错: {str(e)}", exc_info=True)
|
||||
raise
|
||||
|
||||
async def _validate_init(self):
|
||||
"""验证初始化状态"""
|
||||
try:
|
||||
logger.debug("开始验证初始化状态")
|
||||
|
||||
required_configs = ['base', 'permission_rules']
|
||||
for config_name in required_configs:
|
||||
if config_name not in self.configs:
|
||||
logger.error(f"缺少必要配置: {config_name}")
|
||||
raise ValueError(f"缺少必要配置: {config_name}")
|
||||
|
||||
required_dirs = ['config', 'logs', 'plugins']
|
||||
for dir_name in required_dirs:
|
||||
if not Path(dir_name).exists():
|
||||
logger.error(f"必要目录不存在: {dir_name}")
|
||||
raise ValueError(f"必要目录不存在: {dir_name}")
|
||||
|
||||
logger.debug("初始化状态验证通过")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"验证初始化状态时出错: {str(e)}", exc_info=True)
|
||||
raise
|
||||
|
||||
def _get_default_base_config(self) -> Dict:
|
||||
"""获取默认基础配置"""
|
||||
return {
|
||||
'framework': {
|
||||
'name': 'SenSu',
|
||||
'version': 'Alpha_0.2.0',
|
||||
'debug': True
|
||||
},
|
||||
'logging': {
|
||||
'level': 'INFO',
|
||||
'debug_level_file': True,
|
||||
'max_log_files': 20,
|
||||
'max_file_size': '10MB'
|
||||
},
|
||||
'tui': {
|
||||
'layout': {
|
||||
'grid-rows': '4fr 5fr 1fr'
|
||||
}
|
||||
},
|
||||
'services': {
|
||||
'internet': {
|
||||
'ws_port': 8765,
|
||||
'api_port': 8000,
|
||||
'enable_reverse_proxy': False
|
||||
}
|
||||
},
|
||||
'plugins': {
|
||||
'auto_load': True,
|
||||
'hot_reload': True,
|
||||
'max_retry_count': 3
|
||||
}
|
||||
}
|
||||
|
||||
def _get_default_permission_rules(self) -> Dict:
|
||||
"""获取默认权限规则"""
|
||||
return {
|
||||
'permission_levels': ['read', 'write', 'execute', 'admin'],
|
||||
'default_permissions': [
|
||||
'framework.status.read',
|
||||
'plugin.self.info.read'
|
||||
],
|
||||
'admin_permissions': [
|
||||
'framework.*',
|
||||
'plugin.*',
|
||||
'service.*'
|
||||
]
|
||||
}
|
||||
|
||||
def _save_config(self, file_path: Path, config: Dict):
|
||||
"""保存配置到文件"""
|
||||
try:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
|
||||
logger.debug(f"配置保存到: {file_path}")
|
||||
except Exception as e:
|
||||
logger.error(f"保存配置到 {file_path} 时出错: {str(e)}", exc_info=True)
|
||||
|
||||
def get_config(self, config_name: str) -> Dict:
|
||||
"""获取配置"""
|
||||
try:
|
||||
config = self.configs.get(config_name)
|
||||
if not config:
|
||||
logger.error(f"配置不存在: {config_name}")
|
||||
raise ValueError(f"配置 {config_name} 不存在")
|
||||
logger.debug(f"获取配置: {config_name}")
|
||||
return config
|
||||
except Exception as e:
|
||||
logger.error(f"获取配置 {config_name} 时出错: {str(e)}", exc_info=True)
|
||||
raise
|
||||
|
||||
def shutdown(self):
|
||||
"""关闭初始化服务"""
|
||||
try:
|
||||
logger.info("关闭初始化服务")
|
||||
self.configs.clear()
|
||||
logger.debug("初始化服务关闭完成")
|
||||
except Exception as e:
|
||||
logger.error(f"关闭初始化服务时出错: {str(e)}", exc_info=True)
|
||||
Reference in New Issue
Block a user