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:
@@ -4,10 +4,14 @@ commands:
|
||||
permissions:
|
||||
- framework.tui.control
|
||||
source: internal
|
||||
chat_broadcast: &id001
|
||||
description: 向所有聊天客户端广播消息
|
||||
create-plugin:
|
||||
description: 创建新插件脚手架
|
||||
permissions:
|
||||
- plugin.example.chat.broadcast
|
||||
- framework.scaffold.plugin
|
||||
source: internal
|
||||
echo: &id001
|
||||
description: echo input
|
||||
permissions: []
|
||||
source: plugin.example_plugin
|
||||
help:
|
||||
description: 显示帮助信息
|
||||
@@ -24,15 +28,15 @@ commands:
|
||||
permissions:
|
||||
- framework.network.diagnose
|
||||
source: internal
|
||||
network_info: &id002
|
||||
description: 显示插件网络信息
|
||||
permissions: []
|
||||
source: plugin.example_plugin
|
||||
permissions:
|
||||
description: '权限管理: 显示权限状态'
|
||||
permissions:
|
||||
- framework.permission.read
|
||||
source: internal
|
||||
plugin_status: &id002
|
||||
description: show plugin status
|
||||
permissions: []
|
||||
source: plugin.example_plugin
|
||||
pm_plugin_status:
|
||||
description: '权限管理: 查看插件权限状态'
|
||||
permissions:
|
||||
@@ -88,9 +92,9 @@ commands:
|
||||
permissions:
|
||||
- framework.command.test
|
||||
source: internal
|
||||
last_updated: 119133.773274654
|
||||
last_updated: 248209.227564533
|
||||
plugin_commands:
|
||||
example_plugin:
|
||||
chat_broadcast: *id001
|
||||
network_info: *id002
|
||||
total_commands: 18
|
||||
echo: *id001
|
||||
plugin_status: *id002
|
||||
total_commands: 19
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
http_port: 8000
|
||||
last_updated: 119133.817076582
|
||||
http_port: 4200
|
||||
last_updated: 248209.231599689
|
||||
plugin_routes:
|
||||
example_plugin:
|
||||
- methods:
|
||||
- GET
|
||||
path: /plugin/example_plugin/api/info
|
||||
path: /example_plugin/api/example/info
|
||||
require_auth: false
|
||||
- methods:
|
||||
- POST
|
||||
path: /plugin/example_plugin/api/echo
|
||||
require_auth: true
|
||||
- methods:
|
||||
- WEBSOCKET
|
||||
path: /plugin/example_plugin/ws/chat
|
||||
require_auth: true
|
||||
websocket_port: 8765
|
||||
websocket_port: 4240
|
||||
|
||||
@@ -24,8 +24,6 @@ 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 services.project_service import ProjectService
|
||||
from services.sensu_db import SenSuDB
|
||||
|
||||
from bridges.core_bridge import CoreBridge
|
||||
from bridges.plugin_bridge import PluginBridge
|
||||
@@ -33,11 +31,12 @@ from service_manager import ServiceManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class CatFramework:
|
||||
class SenSuFramework:
|
||||
"""框架主类"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, headless=False):
|
||||
self.service_manager = ServiceManager()
|
||||
self.headless = headless
|
||||
self.is_running = False
|
||||
self.headless = headless
|
||||
logger.debug("🐱 DreamSu 框架初始化开始")
|
||||
@@ -85,7 +84,7 @@ class CatFramework:
|
||||
|
||||
# 8. TUI服务
|
||||
if self.headless:
|
||||
logger.info("Headless 模式,跳过 TUI")
|
||||
logger.info("Headless: skip TUI")
|
||||
self.service_manager.register_service("tui", self._create_fallback_tui())
|
||||
else:
|
||||
try:
|
||||
@@ -94,10 +93,8 @@ class CatFramework:
|
||||
self.service_manager.register_service("tui", tui_service)
|
||||
logger.info("TUI服务启动成功")
|
||||
except Exception as e:
|
||||
logger.warning(f"TUI服务启动失败,使用命令行模式: {str(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()
|
||||
@@ -124,8 +121,6 @@ class CatFramework:
|
||||
# 确保 internet_service 已经实例化(在第10步)
|
||||
if internet_service:
|
||||
from services.web_panel.manager import WebPanelManager
|
||||
from services.project_service import ProjectService
|
||||
from services.sensu_db import SenSuDB
|
||||
|
||||
# 初始化面板管理器
|
||||
web_panel = WebPanelManager(base_config, self.service_manager)
|
||||
@@ -134,17 +129,6 @@ from services.sensu_db import SenSuDB
|
||||
if await web_panel.start():
|
||||
self.service_manager.register_service("web_panel", web_panel)
|
||||
logger.info("✅ Web 面板挂载完成")
|
||||
# 11.6 项目注册表 + 数据库
|
||||
logger.info("> 初始化 项目注册表 中...")
|
||||
try:
|
||||
db = SenSuDB("data/sensu.db")
|
||||
project_service = ProjectService(self.service_manager, db)
|
||||
await project_service.start()
|
||||
self.service_manager.register_service("project", project_service)
|
||||
logger.info("✅ 项目注册表就绪")
|
||||
except Exception as e:
|
||||
logger.warning(f"项目注册表初始化跳过: {e}")
|
||||
|
||||
else:
|
||||
logger.warning("Web 面板初始化未完成")
|
||||
except Exception as e:
|
||||
@@ -238,7 +222,7 @@ from services.sensu_db import SenSuDB
|
||||
def _create_fallback_tui(self):
|
||||
"""创建回退的TUI服务(命令行模式)"""
|
||||
class FallbackTuiService:
|
||||
def __init__(self):
|
||||
def __init__(self, headless=False):
|
||||
self.is_running = True
|
||||
|
||||
def show_message(self, message: str, msg_type: str = "info", persistent: bool = False):
|
||||
@@ -396,9 +380,9 @@ from services.sensu_db import SenSuDB
|
||||
logger.error(f"关闭框架时出错: {str(e)}", exc_info=True)
|
||||
await self._safe_shutdown()
|
||||
|
||||
async def main():
|
||||
async def main(headless=False):
|
||||
"""主函数"""
|
||||
framework = CatFramework()
|
||||
framework = SenSuFramework(headless=headless)
|
||||
|
||||
try:
|
||||
# 初始化框架
|
||||
@@ -420,6 +404,7 @@ if __name__ == "__main__":
|
||||
# 设置更详细的异常处理
|
||||
import signal
|
||||
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
"""信号处理"""
|
||||
print(f"\n🐱 接收到信号 {signum},正在关闭...")
|
||||
@@ -430,8 +415,8 @@ if __name__ == "__main__":
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
|
||||
print("\n🐱 主程序启动...")
|
||||
parser = argparse.ArgumentParser(description="SenSu 插件化项目管理框架")
|
||||
parser.add_argument("--headless", action="store_true", help="无头模式 (不启动 TUI)")
|
||||
parser = argparse.ArgumentParser(description="SenSu")
|
||||
parser.add_argument("--headless", action="store_true")
|
||||
args = parser.parse_args()
|
||||
asyncio.run(main(headless=args.headless))
|
||||
|
||||
|
||||
+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("🐱 框架进程结束")
|
||||
@@ -14,8 +14,8 @@ except ImportError:
|
||||
logger=logging.getLogger(__name__)
|
||||
|
||||
class Plugin:
|
||||
def __init__(self,n,c,bridge):
|
||||
self.plugin_name=n;self.config=c;self.bridge=bridge
|
||||
def __init__(self, plugin_name=None, config=None, bridge=None, n=None, c=None):
|
||||
self.plugin_name=plugin_name or n;self.config=config or c;self.bridge=bridge
|
||||
self.network_bridge=None;self.is_running=False
|
||||
|
||||
async def initialize(self):
|
||||
|
||||
@@ -12,8 +12,6 @@ from dataclasses import dataclass
|
||||
import yaml
|
||||
import traceback
|
||||
from sdk.plugin_command_decorator import plugin_command, command
|
||||
from sdk.plugin_status import PluginStatus
|
||||
from sdk.plugin_error import PluginConfigError, PluginLoadError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -41,7 +39,6 @@ class PluginService:
|
||||
self.service_manager = service_manager # 新增服务管理器
|
||||
self.bridge_service.service_manager = self.service_manager
|
||||
self.plugins: Dict[str, Any] = {}
|
||||
self.plugin_status: Dict[str, Any] = {}
|
||||
self.plugin_info: Dict[str, PluginInfo] = {}
|
||||
self.plugins_dir = Path("plugins")
|
||||
self.is_running = False
|
||||
@@ -211,7 +208,6 @@ class PluginService:
|
||||
commands=plugin_commands
|
||||
)
|
||||
|
||||
self.plugin_status[plugin_name] = PluginStatus.RUNNING
|
||||
logger.info(f"插件加载成功: {plugin_name} v{plugin_config['version']}, 注册了 {len(plugin_commands)} 个命令")
|
||||
return True
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
"""SenSu TUI 系统监控组件 — CPU/内存/磁盘/插件状态"""
|
||||
import psutil, time, asyncio, logging
|
||||
try:
|
||||
import psutil
|
||||
except ImportError:
|
||||
psutil = None
|
||||
import time, asyncio, logging
|
||||
from textual.widgets import Static
|
||||
from textual.reactive import reactive
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ from textual.app import App
|
||||
from textual.containers import Container, ScrollableContainer
|
||||
from textual.widgets import Static, Input, Header, Footer
|
||||
from textual.reactive import reactive
|
||||
from services.sysmon_widget import SysMonWidget
|
||||
from typing import List, Dict
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
@@ -659,42 +658,6 @@ class TUIFramework(App):
|
||||
except Exception as e:
|
||||
print(f"❌ 关闭TUI时出错: {str(e)}")
|
||||
|
||||
|
||||
def _start_plugin_status_refresh(self):
|
||||
async def refresh():
|
||||
while True:
|
||||
try:
|
||||
ps = self.service_manager.get_service("plugin")
|
||||
if ps and hasattr(ps, "plugin_status"):
|
||||
lines = []
|
||||
for name, status in ps.plugin_status.items():
|
||||
icon = {"running":"🟢","error":"🔴","loading":"🟡","unloaded":"⚫"}.get(str(status),"⚪")
|
||||
lines.append(f"{icon} {name}: {status}")
|
||||
widget = self.tui_app.query_one(SysMonWidget)
|
||||
widget.update_plugins("\n".join(lines) if lines else "无已加载插件")
|
||||
except: pass
|
||||
await asyncio.sleep(3)
|
||||
import asyncio
|
||||
asyncio.create_task(refresh())
|
||||
|
||||
|
||||
def _get_suggester(self):
|
||||
from textual.suggester import Suggester
|
||||
class CmdSuggester(Suggester):
|
||||
async def get_suggestion(self, value):
|
||||
try:
|
||||
cs = self.app.query_one("#input-area").app
|
||||
names = ["help","status","history","testlog","netdiag",
|
||||
"permissions","pmpending","pmhelp","echo","plugin_status",
|
||||
"scroll","autoscroll","create-plugin","exit","quit"]
|
||||
if not value: return None
|
||||
for n in names:
|
||||
if n.startswith(value) and n != value:
|
||||
return n
|
||||
except: pass
|
||||
return None
|
||||
return CmdSuggester()
|
||||
|
||||
class TuiService:
|
||||
"""TUI服务"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user