3993cc41a9
- Phases 1-3 all integrated - 28/28 tests passing - 7/7 modules import OK
454 lines
19 KiB
Python
454 lines
19 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
|
||
import logging
|
||
import asyncio
|
||
import sys
|
||
import signal
|
||
from services.project_engine import ProjectEngine
|
||
from services.pyenv_manager import PyEnvManager
|
||
from services.proxy_service import ProxyService
|
||
from services.web_panel.routes import projects
|
||
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)
|
||
# 11.7 项目引擎 + 反向代理
|
||
try:
|
||
project_engine = ProjectEngine(self.service_manager)
|
||
await project_engine.start()
|
||
self.service_manager.register_service("project_engine", project_engine)
|
||
self.service_manager.register_service("pyenv", PyEnvManager("data/projects"))
|
||
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("🎉 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("🐱 框架进程结束")
|