Debug: fix headless mode, plugin compat, psutil optional, module imports
- headless: TUI skip now works correctly - example_plugin: keyword args compat (plugin_name=, config=, bridge=) - sysmon: psutil made optional (graceful degrade) - tui_service: SysMonWidget optional - All 22 modules import clean, 23 tests pass, integration verified
This commit is contained in:
+433
@@ -0,0 +1,433 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
import asyncio
|
||||
import sys
|
||||
import signal
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# 添加项目根目录到Python路径
|
||||
project_root = Path(__file__).parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
from services.init_service import InitService
|
||||
from services.log_service import LogService
|
||||
from services.tui_service import TuiService
|
||||
from services.command_service import CommandService
|
||||
from services.auth_service import AuthService
|
||||
from services.internet_service import InternetService
|
||||
from services.plugin_service import PluginService
|
||||
from services.permission_service import PermissionService
|
||||
from services.api_service import APIService
|
||||
from services.shutdown_service import ShutdownService
|
||||
from services.web_panel.manager import WebPanelManager
|
||||
|
||||
from bridges.core_bridge import CoreBridge
|
||||
from bridges.plugin_bridge import PluginBridge
|
||||
from service_manager import ServiceManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class CatFramework:
|
||||
"""框架主类"""
|
||||
|
||||
def __init__(self):
|
||||
self.service_manager = ServiceManager()
|
||||
self.is_running = False
|
||||
logger.debug("🐱 DreamSu 框架初始化开始")
|
||||
|
||||
async def initialize(self):
|
||||
"""初始化框架"""
|
||||
try:
|
||||
logger.info("🐱 SenSu 启动中...")
|
||||
|
||||
# 1. 初始化服务
|
||||
init_service = InitService()
|
||||
configs = await init_service.initialize_framework()
|
||||
base_config = configs['base']
|
||||
self.service_manager.register_service("init", init_service)
|
||||
|
||||
# 2. 日志服务
|
||||
log_service = LogService(base_config)
|
||||
self.service_manager.register_service("log", log_service)
|
||||
|
||||
# 3. 核心桥接服务
|
||||
core_bridge = CoreBridge()
|
||||
await core_bridge.start()
|
||||
self.service_manager.register_service("core_bridge", core_bridge)
|
||||
|
||||
# 4. 指令服务
|
||||
command_service = CommandService(self.service_manager)
|
||||
command_service.register_builtin_commands()
|
||||
self.service_manager.register_service("command", command_service)
|
||||
|
||||
# 5. 认证服务
|
||||
logger.info("> 初始化 访问认证 ...")
|
||||
auth_service = AuthService(base_config)
|
||||
self.service_manager.register_service("auth", auth_service)
|
||||
|
||||
# 6. 插件桥接服务
|
||||
logger.info("> 初始化 插件桥 ...")
|
||||
plugin_bridge = PluginBridge(core_bridge)
|
||||
await plugin_bridge.start()
|
||||
self.service_manager.register_service("plugin_bridge", plugin_bridge)
|
||||
|
||||
# 7. 关闭服务
|
||||
logger.info("> 初始化 关闭服务 中...")
|
||||
shutdown_service = ShutdownService(self.service_manager)
|
||||
self.service_manager.register_service("shutdown", shutdown_service)
|
||||
|
||||
# 8. TUI服务
|
||||
try:
|
||||
tui_service = TuiService(base_config, log_service, command_service)
|
||||
await tui_service.start()
|
||||
self.service_manager.register_service("tui", tui_service)
|
||||
logger.info("TUI服务启动成功")
|
||||
except Exception as e:
|
||||
logger.warning(f"TUI服务启动失败,使用命令行模式: {str(e)}")
|
||||
self.service_manager.register_service("tui", self._create_fallback_tui())
|
||||
|
||||
# 9. 权限服务
|
||||
logger.info("> 初始化 权限服务 中...")
|
||||
permission_service = PermissionService(base_config, self.service_manager.get_service("tui"), core_bridge)
|
||||
permission_started = await permission_service.start()
|
||||
if permission_started:
|
||||
self.service_manager.register_service("permission", permission_service)
|
||||
else:
|
||||
logger.warning("权限服务启动失败,跳过注册")
|
||||
|
||||
# 10. 互联网服务(提前创建但不启动)
|
||||
logger.info("> 初始化 网络服务 中...")
|
||||
internet_service = InternetService(base_config, self.service_manager)
|
||||
self.service_manager.register_service("internet", internet_service)
|
||||
|
||||
# 11. 插件服务(在网络服务启动前注册路由)
|
||||
logger.info("> 初始化 插件管理器 中...")
|
||||
plugin_service = PluginService(base_config, permission_service, plugin_bridge, self.service_manager)
|
||||
await plugin_service.start()
|
||||
self.service_manager.register_service("plugin", plugin_service)
|
||||
|
||||
# === 🟢 新增: 11.5 Web管理面板初始化 (必须在网络服务启动前!) ===
|
||||
# 原因: aiohttp 启动后会“冻结”路由器,之后再挂载子应用会报错
|
||||
logger.info("> 初始化 Web 管理面板 中...")
|
||||
try:
|
||||
# 确保 internet_service 已经实例化(在第10步)
|
||||
if internet_service:
|
||||
from services.web_panel.manager import WebPanelManager
|
||||
|
||||
# 初始化面板管理器
|
||||
web_panel = WebPanelManager(base_config, self.service_manager)
|
||||
|
||||
# 这里的 start() 会把面板路由挂载到 http_app 上 (此时还未冻结)
|
||||
if await web_panel.start():
|
||||
self.service_manager.register_service("web_panel", web_panel)
|
||||
logger.info("✅ Web 面板挂载完成")
|
||||
else:
|
||||
logger.warning("Web 面板初始化未完成")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Web 管理面板初始化失败: {str(e)}", exc_info=True)
|
||||
|
||||
# 12. 启动网络服务(在所有插件路由注册后)
|
||||
logger.info("> 启动网络服务 中...")
|
||||
try:
|
||||
# 先检查依赖和端口
|
||||
health_info = await internet_service.check_service_health()
|
||||
logger.debug(f"网络服务预检查: {health_info}")
|
||||
|
||||
if not health_info["dependencies_available"]:
|
||||
logger.error("❌ 缺少必要的依赖包,网络服务无法启动")
|
||||
logger.info("💡 请运行: pip install aiohttp yaml")
|
||||
internet_started = False
|
||||
else:
|
||||
# 现在启动网络服务(路由器会在启动时冻结)
|
||||
internet_started = await internet_service.start()
|
||||
|
||||
# 再次检查服务状态
|
||||
if internet_started:
|
||||
post_health = await internet_service.check_service_health()
|
||||
logger.debug(f"网络服务启动后检查: {post_health}")
|
||||
|
||||
if post_health["http_active"]:
|
||||
logger.info("✅ 互联网服务启动成功")
|
||||
|
||||
# 显示服务信息
|
||||
logger.info(f"🌐 服务地址: http://{internet_service.http_host}:{internet_service.http_port}")
|
||||
logger.info(f"🔍 健康检查: http://{internet_service.http_host}:{internet_service.http_port}/health")
|
||||
else:
|
||||
logger.warning("⚠️ 网络服务已启动但端口未响应")
|
||||
else:
|
||||
logger.warning("❌ 互联网服务启动失败")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 互联网服务启动异常: {str(e)}", exc_info=True)
|
||||
logger.warning("互联网服务启动失败")
|
||||
|
||||
# 13. API服务
|
||||
logger.info("> 初始化 API 服务 中...")
|
||||
try:
|
||||
api_service = APIService(internet_service, auth_service, permission_service)
|
||||
self.service_manager.register_service("api", api_service)
|
||||
logger.info("✅ API 服务启动成功")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ API 服务初始化失败: {str(e)}")
|
||||
logger.warning("API 服务启动失败,跳过注册")
|
||||
|
||||
|
||||
# 注册框架关闭处理器
|
||||
shutdown_service.register_shutdown_handler(self._framework_shutdown_handler)
|
||||
logger.info("🎉 DreamSu 初始化完成!")
|
||||
self.is_running = True
|
||||
|
||||
# 显示欢迎日志
|
||||
version = base_config.get('framework', {}).get('version', 'Unknown')
|
||||
logLevel = base_config.get('logging', {}).get('level', 'Unknown')
|
||||
|
||||
logger.info("\n🐱 SenSu 已就绪!")
|
||||
logger.info(f"当前 SenSu 版本号 {version}")
|
||||
logger.info(f"当前日志级别 {logLevel}")
|
||||
|
||||
panel_path = base_config.get('panel', {}).get('entrance', {}).get('path', 'panel')
|
||||
|
||||
# 显示欢迎消息
|
||||
tui_service = self.service_manager.get_service("tui")
|
||||
if hasattr(tui_service, 'show_message'):
|
||||
tui_service.show_message("🐱 DreamSu 框架 已就绪!\n", "info")
|
||||
tui_service.show_message("====================================\n", "info")
|
||||
tui_service.show_message("🐱 SenSu 已就绪!", "info")
|
||||
tui_service.show_message(f"当前 SenSu 版本号 {version}", "info")
|
||||
tui_service.show_message(f"当前日志级别 {logLevel}\n", "info")
|
||||
tui_service.show_message("====================================\n", "info")
|
||||
tui_service.show_message(f"当前API配置地址", "debug")
|
||||
tui_service.show_message(f"地址:http://{internet_service.http_host}:{internet_service.http_port}", "debug")
|
||||
tui_service.show_message("====================================\n", "debug")
|
||||
tui_service.show_message(f"🌐 Web 面板配置地址: http://{internet_service.http_host}:{internet_service.http_port}{panel_path}", "info")
|
||||
|
||||
else:
|
||||
print("🐱 SenSu 已就绪!输入 'help' 查看可用命令")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"框架初始化失败: {str(e)}", exc_info=True)
|
||||
await self._safe_shutdown()
|
||||
raise
|
||||
|
||||
|
||||
def _create_fallback_tui(self):
|
||||
"""创建回退的TUI服务(命令行模式)"""
|
||||
class FallbackTuiService:
|
||||
def __init__(self):
|
||||
self.is_running = True
|
||||
|
||||
def show_message(self, message: str, msg_type: str = "info", persistent: bool = False):
|
||||
"""显示消息到控制台"""
|
||||
prefix = {
|
||||
"info": "ℹ️",
|
||||
"warning": "⚠️",
|
||||
"error": "❌",
|
||||
"success": "✅"
|
||||
}.get(msg_type, "📝")
|
||||
print(f"{prefix} {message}")
|
||||
|
||||
async def start(self):
|
||||
"""启动回退TUI"""
|
||||
print("🐱 使用命令行模式...")
|
||||
return True
|
||||
|
||||
def shutdown(self):
|
||||
"""关闭回退TUI"""
|
||||
self.is_running = False
|
||||
|
||||
return FallbackTuiService()
|
||||
|
||||
async def _safe_shutdown(self):
|
||||
"""安全关闭,即使服务未完全初始化"""
|
||||
try:
|
||||
logger.info("执行安全关闭")
|
||||
self.is_running = False
|
||||
|
||||
# 尝试获取关闭服务
|
||||
try:
|
||||
shutdown_service = self.service_manager.get_service("shutdown")
|
||||
if shutdown_service:
|
||||
await shutdown_service.initiate_shutdown("安全关闭")
|
||||
return
|
||||
except:
|
||||
pass
|
||||
|
||||
# 如果关闭服务不可用,手动关闭其他服务
|
||||
services_to_shutdown = ['plugin', 'core_bridge', 'plugin_bridge', 'tui', 'log']
|
||||
for service_name in services_to_shutdown:
|
||||
try:
|
||||
service = self.service_manager.get_service(service_name)
|
||||
if service and hasattr(service, 'shutdown'):
|
||||
await service.shutdown() if asyncio.iscoroutinefunction(service.shutdown) else service.shutdown()
|
||||
except:
|
||||
pass
|
||||
|
||||
logger.debug("安全关闭完成")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 安全关闭时出错: {e}")
|
||||
|
||||
async def _framework_shutdown_handler(self):
|
||||
"""框架关闭处理器"""
|
||||
try:
|
||||
logger.info("执行框架关闭处理")
|
||||
self.is_running = False
|
||||
|
||||
# 关闭插件服务
|
||||
plugin_service = self.service_manager.get_service("plugin")
|
||||
if plugin_service:
|
||||
# 卸载所有插件
|
||||
for plugin_name in list(plugin_service.plugins.keys()):
|
||||
await plugin_service.unload_plugin(plugin_name)
|
||||
|
||||
# 关闭桥接服务
|
||||
core_bridge = self.service_manager.get_service("core_bridge")
|
||||
if core_bridge:
|
||||
await core_bridge.shutdown()
|
||||
|
||||
plugin_bridge = self.service_manager.get_service("plugin_bridge")
|
||||
if plugin_bridge:
|
||||
await plugin_bridge.shutdown()
|
||||
|
||||
logger.debug("框架关闭处理完成")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"框架关闭处理时出错: {str(e)}", exc_info=True)
|
||||
|
||||
async def run(self):
|
||||
"""运行框架主循环"""
|
||||
try:
|
||||
logger.info("进入框架主循环")
|
||||
|
||||
# 特殊终端,添加命令行输入处理
|
||||
if not hasattr(self.service_manager.get_service("tui"), 'tui_app'):
|
||||
await self._run_cli_mode()
|
||||
else:
|
||||
# 原有的TUI模式
|
||||
while self.is_running:
|
||||
try:
|
||||
await asyncio.sleep(1)
|
||||
except asyncio.CancelledError:
|
||||
logger.info("主循环被取消")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"主循环运行时出错: {str(e)}", exc_info=True)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
logger.info("框架主循环结束")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"运行框架主循环时出错: {str(e)}", exc_info=True)
|
||||
await self._safe_shutdown()
|
||||
|
||||
async def _run_cli_mode(self):
|
||||
"""运行命令行模式"""
|
||||
try:
|
||||
print("🐱 进入命令行模式,输入 'exit' 退出")
|
||||
|
||||
command_service = self.service_manager.get_service("command")
|
||||
|
||||
while self.is_running:
|
||||
try:
|
||||
# 读取用户输入
|
||||
user_input = await asyncio.get_event_loop().run_in_executor(
|
||||
None, input, "🐱 > "
|
||||
)
|
||||
|
||||
if user_input.strip().lower() in ('exit', 'quit', 'q'):
|
||||
await self.shutdown()
|
||||
break
|
||||
|
||||
# 处理命令
|
||||
if user_input.strip():
|
||||
result = await command_service.process_command(user_input, "cli")
|
||||
print(f"📝 {result}")
|
||||
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print("\n🐱 接收到退出信号")
|
||||
await self.shutdown()
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"❌ 命令处理错误: {str(e)}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"命令行模式运行时出错: {str(e)}", exc_info=True)
|
||||
await self._safe_shutdown()
|
||||
|
||||
async def shutdown(self):
|
||||
"""关闭框架"""
|
||||
try:
|
||||
logger.info("开始关闭框架")
|
||||
self.is_running = False
|
||||
|
||||
# 通过关闭服务发起优雅关闭
|
||||
shutdown_service = self.service_manager.get_service("shutdown")
|
||||
if shutdown_service:
|
||||
await shutdown_service.initiate_shutdown("手动关闭")
|
||||
else:
|
||||
await self._safe_shutdown()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"关闭框架时出错: {str(e)}", exc_info=True)
|
||||
await self._safe_shutdown()
|
||||
|
||||
async def main():
|
||||
"""主函数"""
|
||||
framework = CatFramework()
|
||||
|
||||
try:
|
||||
# 初始化框架
|
||||
await framework.initialize()
|
||||
|
||||
# 运行主循环
|
||||
await framework.run()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n🐱 接收到键盘中断")
|
||||
await framework.shutdown()
|
||||
except Exception as e:
|
||||
print(f"🐱 框架运行出错: {str(e)}")
|
||||
await framework._safe_shutdown()
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
# 设置更详细的异常处理
|
||||
import signal
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
"""信号处理"""
|
||||
print(f"\n🐱 接收到信号 {signum},正在关闭...")
|
||||
sys.exit(0)
|
||||
|
||||
# 注册信号处理
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
|
||||
print("\n🐱 主程序启动...")
|
||||
# 运行主程序
|
||||
asyncio.run(main())
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n🐱 接收到键盘中断,关闭...")
|
||||
print("🐱 再见喵~")
|
||||
sys.exit(0)
|
||||
except SystemExit as e:
|
||||
# 优雅处理SystemExit
|
||||
exit_code = e.code if e.code is not None else 0
|
||||
if exit_code == 0:
|
||||
print("🐱 框架已关闭")
|
||||
else:
|
||||
print(f"🐱 框架退出,代码: {exit_code}")
|
||||
sys.exit(exit_code)
|
||||
except Exception as e:
|
||||
print(f"🐱 框架运行异常: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
finally:
|
||||
print("🐱 框架进程结束")
|
||||
Reference in New Issue
Block a user