#!/usr/bin/env python3 # -*- coding: utf-8 -*- import logging import asyncio import sys import signal import argparse from services.project_engine import ProjectEngine from services.pyenv_manager import PyEnvManager from services.proxy_service import ProxyService 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 SenSuFramework: """框架主类""" def __init__(self, headless=False): self.service_manager = ServiceManager() self.is_running = False self.headless = headless logger.debug("🐱 SenSu 框架初始化开始") 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服务 if self.headless: logger.info("Headless mode, skip TUI") self.service_manager.register_service("tui", self._create_fallback_tui()) else: 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服务启动失败: {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) # 11.7 项目引擎 + 反向代理 try: logger.info("> 初始化 项目引擎 中...") project_engine = ProjectEngine(self.service_manager) await project_engine.start() self.service_manager.register_service("project_engine", project_engine) pe_mgr = PyEnvManager("data/projects") self.service_manager.register_service("pyenv", pe_mgr) logger.info("> 初始化 反向代理 中...") proxy_service = ProxyService(self.service_manager) await proxy_service.start() if internet_service and internet_service.http_app: proxy_service.setup_routes(internet_service.http_app) self.service_manager.register_service("proxy", proxy_service) logger.info("✅ 项目引擎+反向代理就绪") except Exception as e: logger.warning(f"引擎/代理初始化跳过: {e}") logger.info("🎉 SenSu 初始化完成!") 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("🐱 SenSu 框架 已就绪!\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("进入框架主循环") # 特殊终端,添加命令行输入处理 tui = self.service_manager.get_service("tui") if self.headless: while self.is_running: try: await asyncio.sleep(1) except asyncio.CancelledError: break elif not hasattr(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(headless=False): """主函数""" framework = SenSuFramework(headless=headless) 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🐱 主程序启动...") # 运行主程序 parser = argparse.ArgumentParser(description="SenSu") parser.add_argument("--headless", action="store_true") args = parser.parse_args() asyncio.run(main(headless=args.headless)) 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("🐱 框架进程结束")