VWED_server/tests/test.py

320 lines
11 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
WebSocket 脚本日志订阅测试
用于监控 VWED 脚本日志推送
"""
import asyncio
import json
from datetime import datetime
import signal
import sys
try:
import websockets
except ImportError:
print("❌ 缺少 websockets 依赖,请运行: pip install websockets")
sys.exit(1)
class VWEDWebSocketLogMonitor:
"""VWED WebSocket 日志监控器"""
def __init__(self, host="localhost", port=8000, client_id="monitor_test", client_type="monitor"):
self.host = host
self.port = port
self.client_id = client_id
self.client_type = client_type
self.websocket = None
self.running = False
self.subscribed_scripts = set()
async def connect(self):
"""连接到 WebSocket 服务器"""
uri = f"ws://{self.host}:{self.port}/api/script/ws/script-logs?client_id={self.client_id}&client_type={self.client_type}"
try:
print(f"正在连接到 WebSocket 服务器: {uri}")
self.websocket = await websockets.connect(uri)
self.running = True
print(f"✅ WebSocket 连接成功建立")
return True
except Exception as e:
print(f"❌ WebSocket 连接失败: {e}")
return False
async def disconnect(self):
"""断开连接"""
self.running = False
if self.websocket:
await self.websocket.close()
print("🔌 WebSocket 连接已断开")
async def subscribe_script(self, script_id):
"""订阅脚本日志"""
if not self.websocket:
print("WebSocket 未连接")
return False
try:
message = {
"type": "subscribe",
"script_id": script_id
}
await self.websocket.send(json.dumps(message))
self.subscribed_scripts.add(script_id)
print(f"📡 已发送订阅请求: {script_id}")
return True
except Exception as e:
print(f"订阅脚本失败: {e}")
return False
async def unsubscribe_script(self, script_id):
"""取消订阅脚本日志"""
if not self.websocket:
print("WebSocket 未连接")
return False
try:
message = {
"type": "unsubscribe",
"script_id": script_id
}
await self.websocket.send(json.dumps(message))
self.subscribed_scripts.discard(script_id)
print(f" 已发送取消订阅请求: {script_id}")
return True
except Exception as e:
print(f"取消订阅脚本失败: {e}")
return False
async def get_status(self):
"""获取连接状态"""
if not self.websocket:
print("WebSocket 未连接")
return False
try:
message = {"type": "get_status"}
await self.websocket.send(json.dumps(message))
print("已发送状态查询请求")
return True
except Exception as e:
print(f"获取状态失败: {e}")
return False
async def send_ping(self):
"""发送心跳"""
if not self.websocket:
return False
try:
message = {
"type": "ping",
"timestamp": datetime.now().isoformat()
}
await self.websocket.send(json.dumps(message))
return True
except Exception as e:
print(f"❌ 发送心跳失败: {e}")
return False
def format_message(self, message):
"""格式化消息显示"""
msg_type = message.get("type", "unknown")
timestamp = datetime.now().strftime("%H:%M:%S")
if msg_type == "welcome":
return f"🎉 [{timestamp}] 欢迎消息: {message.get('message')} (连接ID: {message.get('connection_id')})"
elif msg_type == "script_log":
script_id = message.get("script_id", "unknown")
level = message.get("level", "INFO")
log_msg = message.get("message", "")
# 根据日志级别选择emoji
level_emoji = {
"INFO": "",
"WARNING": "⚠️",
"ERROR": "",
"DEBUG": "🐛"
}
emoji = level_emoji.get(level, "📝")
return f"{emoji} [{timestamp}] [{script_id}] {level}: {log_msg}"
elif msg_type == "script_status":
script_id = message.get("script_id", "unknown")
status = message.get("status", "unknown")
status_msg = message.get("message", "")
return f"🔄 [{timestamp}] [{script_id}] 状态变更: {status} - {status_msg}"
elif msg_type == "function_execution":
script_id = message.get("script_id", "unknown")
func_name = message.get("function_name", "unknown")
result = message.get("result", {})
return f"⚡ [{timestamp}] [{script_id}] 函数执行: {func_name} -> {json.dumps(result, ensure_ascii=False)}"
elif msg_type == "subscription_success":
return f"✅ [{timestamp}] 订阅成功: {message.get('message')}"
elif msg_type == "unsubscription_success":
return f"✅ [{timestamp}] 取消订阅成功: {message.get('message')}"
elif msg_type == "status":
data = message.get("data", {})
total_connections = data.get("total_connections", 0)
total_scripts = data.get("total_script_subscriptions", 0)
return f"📊 [{timestamp}] 连接状态: {total_connections} 个连接, {total_scripts} 个脚本订阅"
elif msg_type == "error":
return f"❌ [{timestamp}] 错误: {message.get('message')}"
elif msg_type == "pong":
return f"💓 [{timestamp}] 心跳响应"
else:
return f"❓ [{timestamp}] 未知消息类型 {msg_type}: {json.dumps(message, ensure_ascii=False)}"
async def listen_messages(self):
"""监听消息"""
if not self.websocket:
print("❌ WebSocket 未连接")
return
try:
while self.running:
try:
# 等待消息,设置超时避免无限阻塞
message = await asyncio.wait_for(
self.websocket.recv(),
timeout=1.0
)
try:
data = json.loads(message)
formatted_msg = self.format_message(data)
print(formatted_msg)
except json.JSONDecodeError:
print(f"❌ JSON 解析失败: {message}")
except asyncio.TimeoutError:
# 超时是正常的,继续循环
continue
except websockets.exceptions.ConnectionClosed:
print("🔌 WebSocket 连接已关闭")
break
except Exception as e:
print(f"❌ 接收消息异常: {e}")
break
except Exception as e:
print(f"❌ 监听消息异常: {e}")
async def interactive_monitor(self):
"""交互式监控"""
print("\n" + "="*50)
print("VWED WebSocket 脚本日志监控器")
print("="*50)
print("可用命令:")
print(" sub <script_id> - 订阅脚本日志")
print(" unsub <script_id> - 取消订阅脚本日志")
print(" status - 获取连接状态")
print(" ping - 发送心跳")
print(" list - 显示已订阅的脚本")
print(" quit - 退出监控")
print("="*50)
# 启动消息监听任务
listen_task = asyncio.create_task(self.listen_messages())
try:
while self.running:
try:
# 等待用户输入
user_input = await asyncio.get_event_loop().run_in_executor(
None, input, "请输入命令 (sub/unsub/status/ping/list/quit): "
)
command_parts = user_input.strip().split()
if not command_parts:
continue
command = command_parts[0].lower()
if command == "quit":
print("👋 退出监控...")
break
elif command == "sub" and len(command_parts) > 1:
script_id = command_parts[1]
await self.subscribe_script(script_id)
elif command == "unsub" and len(command_parts) > 1:
script_id = command_parts[1]
await self.unsubscribe_script(script_id)
elif command == "status":
await self.get_status()
elif command == "ping":
await self.send_ping()
elif command == "list":
if self.subscribed_scripts:
print(f"📋 已订阅的脚本: {', '.join(self.subscribed_scripts)}")
else:
print("📋 当前没有订阅任何脚本")
else:
print("❌ 未知命令或参数不足")
except KeyboardInterrupt:
print("\n👋 收到退出信号...")
break
except Exception as e:
print(f"❌ 处理命令异常: {e}")
finally:
self.running = False
listen_task.cancel()
try:
await listen_task
except asyncio.CancelledError:
pass
async def main():
"""主函数"""
monitor = VWEDWebSocketLogMonitor()
# 设置信号处理
def signal_handler(signum, _):
print(f"\n👋 收到信号 {signum},正在退出...")
monitor.running = False
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
try:
# 连接 WebSocket
if await monitor.connect():
# 开始交互式监控
await monitor.interactive_monitor()
else:
print("❌ 无法连接到 WebSocket 服务器")
return 1
except Exception as e:
print(f"❌ 监控异常: {e}")
return 1
finally:
# 清理连接
await monitor.disconnect()
return 0
if __name__ == "__main__":
try:
exit_code = asyncio.run(main())
sys.exit(exit_code)
except KeyboardInterrupt:
print("\n👋 程序已退出")
sys.exit(0)