添加插件系统
This commit is contained in:
parent
0c2e9f0c1b
commit
6cf616d1bb
383
plugins/user/matchmaking_system/README.md
Normal file
383
plugins/user/matchmaking_system/README.md
Normal file
@ -0,0 +1,383 @@
|
||||
# 匹配系统插件
|
||||
|
||||
为EG引擎提供完整的玩家匹配功能,包括队列管理、算法匹配、房间分配、规则配置、实时监控和数据分析等核心功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. 匹配管理
|
||||
- 智能匹配过程管理
|
||||
- 多种匹配模式支持
|
||||
- 匹配状态跟踪和控制
|
||||
- 匹配结果处理和回调
|
||||
|
||||
### 2. 队列系统
|
||||
- 玩家排队管理
|
||||
- 队列优先级处理
|
||||
- 超时自动清理
|
||||
- 实时队列状态监控
|
||||
|
||||
### 3. 匹配算法
|
||||
- 技能匹配算法
|
||||
- 快速匹配算法
|
||||
- 团队平衡算法
|
||||
- 自定义算法支持
|
||||
- 匹配质量评估
|
||||
|
||||
### 4. 房间分配
|
||||
- 动态房间创建和销毁
|
||||
- 玩家房间分配管理
|
||||
- 房间状态跟踪
|
||||
- 房间密码保护
|
||||
|
||||
### 5. 规则配置
|
||||
- 灵活的匹配规则系统
|
||||
- 游戏模式特定规则
|
||||
- 自定义规则集支持
|
||||
- 实时规则验证
|
||||
|
||||
### 6. 实时监控
|
||||
- 性能指标收集
|
||||
- 实时数据监控
|
||||
- 警报系统
|
||||
- 系统健康状态检查
|
||||
|
||||
### 7. 事件系统
|
||||
- 事件驱动架构
|
||||
- 异步事件处理
|
||||
- 事件过滤和优先级
|
||||
- 事件监听器系统
|
||||
|
||||
### 8. 配置管理
|
||||
- 持久化配置存储
|
||||
- 动态配置更新
|
||||
- 配置变更监听
|
||||
- 配置导入导出
|
||||
|
||||
### 9. 可视化编辑器
|
||||
- 实时数据展示
|
||||
- 配置参数调整
|
||||
- 统计图表显示
|
||||
- 数据导出功能
|
||||
|
||||
### 10. 数据统计
|
||||
- 实时数据收集
|
||||
- 历史数据分析
|
||||
- 统计报告生成
|
||||
- 数据导出支持
|
||||
|
||||
## 系统架构
|
||||
|
||||
```
|
||||
匹配系统插件
|
||||
├── 核心模块
|
||||
│ └── 匹配管理器 (core/match_manager.py)
|
||||
├── 队列系统
|
||||
│ └── 队列管理器 (queue/queue_manager.py)
|
||||
├── 算法系统
|
||||
│ └── 算法管理器 (algorithms/algorithm_manager.py)
|
||||
├── 房间系统
|
||||
│ └── 房间分配器 (rooms/room_allocator.py)
|
||||
├── 规则系统
|
||||
│ └── 规则管理器 (rules/rule_manager.py)
|
||||
├── 监控系统
|
||||
│ └── 匹配监控器 (monitoring/match_monitor.py)
|
||||
├── 事件系统
|
||||
│ └── 事件处理器 (events/event_handler.py)
|
||||
├── 配置系统
|
||||
│ └── 配置管理器 (config/match_config.py)
|
||||
├── 编辑器系统
|
||||
│ └── 匹配编辑器 (editor/match_editor.py)
|
||||
├── 统计系统
|
||||
│ └── 统计管理器 (stats/stats_manager.py)
|
||||
└── 插件主文件
|
||||
└── 插件入口 (plugin.py)
|
||||
```
|
||||
|
||||
## 安装和使用
|
||||
|
||||
### 安装依赖
|
||||
|
||||
```bash
|
||||
# 无特殊依赖,使用标准Python库
|
||||
```
|
||||
|
||||
### 配置插件
|
||||
|
||||
插件配置文件位于 `config/matchmaking_config.json`,包含以下主要配置项:
|
||||
|
||||
```json
|
||||
{
|
||||
"system": {
|
||||
"enable_matchmaking": true,
|
||||
"max_concurrent_matches": 1000,
|
||||
"default_match_timeout": 300.0
|
||||
},
|
||||
"queue": {
|
||||
"default_queue_timeout": 300.0,
|
||||
"queue_processing_interval": 2.0
|
||||
},
|
||||
"matching": {
|
||||
"default_algorithm": "skill_based",
|
||||
"skill_range": 100
|
||||
},
|
||||
"room": {
|
||||
"default_max_players": 8,
|
||||
"enable_room_passwords": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 启动插件
|
||||
|
||||
```python
|
||||
# 初始化插件
|
||||
plugin = MatchmakingSystemPlugin(engine)
|
||||
plugin.initialize()
|
||||
plugin.enable()
|
||||
|
||||
# 插件会自动处理匹配过程
|
||||
```
|
||||
|
||||
## API参考
|
||||
|
||||
### 匹配管理
|
||||
|
||||
```python
|
||||
# 开始匹配
|
||||
match_id = plugin.match_manager.start_matchmaking(player_ids, match_params)
|
||||
|
||||
# 取消匹配
|
||||
plugin.match_manager.cancel_matchmaking(match_id)
|
||||
|
||||
# 获取匹配统计
|
||||
stats = plugin.match_manager.get_match_stats()
|
||||
```
|
||||
|
||||
### 队列管理
|
||||
|
||||
```python
|
||||
# 添加玩家到队列
|
||||
plugin.queue_manager.add_players_to_queue(player_ids, queue_params)
|
||||
|
||||
# 从队列移除玩家
|
||||
plugin.queue_manager.remove_players_from_queue(player_ids=player_ids)
|
||||
|
||||
# 获取队列信息
|
||||
queue_info = plugin.queue_manager.get_queue_info(queue_name)
|
||||
```
|
||||
|
||||
### 算法管理
|
||||
|
||||
```python
|
||||
# 设置活动算法
|
||||
plugin.algorithm_manager.set_active_algorithm("skill_based")
|
||||
|
||||
# 运行匹配算法
|
||||
result = plugin.algorithm_manager.run_matching_algorithm(players)
|
||||
|
||||
# 更新玩家技能
|
||||
plugin.algorithm_manager.update_player_skill(player_id, skill_level)
|
||||
```
|
||||
|
||||
### 房间分配
|
||||
|
||||
```python
|
||||
# 创建房间
|
||||
room_id = plugin.room_allocator.create_room(room_name, room_settings)
|
||||
|
||||
# 添加玩家到房间
|
||||
plugin.room_allocator.add_client_to_room(room_id, player_id)
|
||||
|
||||
# 从房间移除玩家
|
||||
plugin.room_allocator.remove_client_from_room(room_id, player_id)
|
||||
```
|
||||
|
||||
### 规则管理
|
||||
|
||||
```python
|
||||
# 应用规则
|
||||
is_valid = plugin.rule_manager.apply_rules(players, game_mode)
|
||||
|
||||
# 添加自定义规则集
|
||||
plugin.rule_manager.add_custom_rule_set("custom_rules", rules)
|
||||
|
||||
# 设置活动规则集
|
||||
plugin.rule_manager.set_active_rules("custom_rules")
|
||||
```
|
||||
|
||||
### 监控系统
|
||||
|
||||
```python
|
||||
# 获取性能指标
|
||||
metrics = plugin.monitor.get_performance_metrics()
|
||||
|
||||
# 获取活动警报
|
||||
alerts = plugin.monitor.get_active_alerts()
|
||||
|
||||
# 记录匹配队列时间
|
||||
plugin.monitor.record_match_queue_time(queue_time)
|
||||
```
|
||||
|
||||
### 事件系统
|
||||
|
||||
```python
|
||||
# 发出事件
|
||||
plugin.event_handler.emit_event("match_found", payload)
|
||||
|
||||
# 注册事件处理器
|
||||
plugin.event_handler.register_event_handler("match_found", handler_func)
|
||||
|
||||
# 注册事件过滤器
|
||||
plugin.event_handler.register_event_filter("match_found", filter_func)
|
||||
```
|
||||
|
||||
### 配置管理
|
||||
|
||||
```python
|
||||
# 获取配置
|
||||
config_value = plugin.config_manager.get_config("section", "key", default_value)
|
||||
|
||||
# 设置配置
|
||||
plugin.config_manager.set_config("section", "key", value)
|
||||
|
||||
# 保存配置
|
||||
plugin.config_manager.save_config()
|
||||
|
||||
# 加载配置
|
||||
plugin.config_manager.load_config()
|
||||
```
|
||||
|
||||
### 编辑器系统
|
||||
|
||||
```python
|
||||
# 显示编辑器
|
||||
plugin.editor.show_editor()
|
||||
|
||||
# 隐藏编辑器
|
||||
plugin.editor.hide_editor()
|
||||
|
||||
# 切换标签页
|
||||
plugin.editor.switch_tab("overview")
|
||||
|
||||
# 更新配置
|
||||
plugin.editor.update_config("section", "key", value)
|
||||
```
|
||||
|
||||
### 统计系统
|
||||
|
||||
```python
|
||||
# 获取实时统计数据
|
||||
realtime_stats = plugin.stats_manager.get_realtime_stats()
|
||||
|
||||
# 生成报告
|
||||
report = plugin.stats_manager.generate_report("summary", "24h")
|
||||
|
||||
# 导出统计数据
|
||||
plugin.stats_manager.export_stats("stats.json")
|
||||
|
||||
# 重置统计数据
|
||||
plugin.stats_manager.reset_stats()
|
||||
```
|
||||
|
||||
## 匹配流程
|
||||
|
||||
### 1. 玩家加入队列
|
||||
```
|
||||
玩家 -> 队列管理器 -> 添加到匹配队列
|
||||
```
|
||||
|
||||
### 2. 队列处理
|
||||
```
|
||||
队列管理器 -> 算法管理器 -> 运行匹配算法
|
||||
```
|
||||
|
||||
### 3. 匹配创建
|
||||
```
|
||||
算法管理器 -> 房间分配器 -> 创建匹配房间
|
||||
```
|
||||
|
||||
### 4. 玩家分配
|
||||
```
|
||||
房间分配器 -> 玩家 -> 加入匹配房间
|
||||
```
|
||||
|
||||
### 5. 匹配完成
|
||||
```
|
||||
匹配管理器 -> 事件系统 -> 发出匹配完成事件
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
1. **异步处理**:采用多线程和异步I/O提高并发性能
|
||||
2. **智能队列**:高效的队列管理和玩家匹配算法
|
||||
3. **内存优化**:及时清理无用数据和对象
|
||||
4. **缓存机制**:对频繁访问的数据进行缓存
|
||||
5. **批量处理**:批量处理队列和匹配操作
|
||||
|
||||
## 扩展开发
|
||||
|
||||
### 添加新的匹配算法
|
||||
|
||||
```python
|
||||
# 在算法管理器中实现新的匹配算法
|
||||
def _run_custom_matching(self, players):
|
||||
# 实现自定义匹配逻辑
|
||||
pass
|
||||
|
||||
# 注册算法
|
||||
plugin.algorithm_manager.register_algorithm("custom", _run_custom_matching)
|
||||
```
|
||||
|
||||
### 添加新的事件类型
|
||||
|
||||
```python
|
||||
# 注册事件处理器
|
||||
plugin.event_handler.register_event_handler("custom_event", custom_handler)
|
||||
|
||||
# 发出事件
|
||||
plugin.event_handler.emit_event("custom_event", payload)
|
||||
```
|
||||
|
||||
### 添加自定义规则
|
||||
|
||||
```python
|
||||
# 添加自定义规则集
|
||||
plugin.rule_manager.add_custom_rule_set("my_rules", {
|
||||
"min_players": 2,
|
||||
"max_players": 8,
|
||||
"custom_rule": True
|
||||
})
|
||||
|
||||
# 应用规则
|
||||
plugin.rule_manager.apply_rules(players, "my_rules")
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **匹配失败**:检查匹配规则和算法配置
|
||||
2. **队列超时**:调整队列超时时间和匹配参数
|
||||
3. **性能问题**:检查系统资源使用情况,优化配置
|
||||
4. **配置错误**:验证配置文件格式和参数
|
||||
|
||||
### 日志分析
|
||||
|
||||
查看日志文件以诊断问题:
|
||||
```
|
||||
logs/matchmaking_system.log
|
||||
```
|
||||
|
||||
## 版本信息
|
||||
|
||||
- 版本:1.0.0
|
||||
- 作者:EG Plugin System
|
||||
- 许可证:MIT
|
||||
|
||||
## 贡献指南
|
||||
|
||||
欢迎提交Issue和Pull Request来改进这个插件。
|
||||
|
||||
## 支持
|
||||
|
||||
如需技术支持,请联系插件维护团队或查看相关文档。
|
||||
616
plugins/user/matchmaking_system/algorithms/algorithm_manager.py
Normal file
616
plugins/user/matchmaking_system/algorithms/algorithm_manager.py
Normal file
@ -0,0 +1,616 @@
|
||||
"""
|
||||
算法管理器模块
|
||||
实现不同的匹配算法(技能匹配、快速匹配等)
|
||||
"""
|
||||
|
||||
import time
|
||||
import random
|
||||
from typing import Dict, Any, List, Optional
|
||||
from collections import defaultdict
|
||||
|
||||
class AlgorithmManager:
|
||||
"""
|
||||
算法管理器
|
||||
实现不同的匹配算法(技能匹配、快速匹配等)
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化算法管理器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 算法配置
|
||||
self.algorithm_config = {
|
||||
"default_algorithm": "skill_based",
|
||||
"available_algorithms": ["skill_based", "quick", "team_balanced", "custom"],
|
||||
"skill_based_config": {
|
||||
"skill_range": 100, # 技能匹配范围
|
||||
"max_wait_time": 120.0, # 最大等待时间(秒)
|
||||
"expand_range_over_time": True, # 随时间扩展匹配范围
|
||||
"range_expansion_rate": 10 # 每秒扩展范围
|
||||
},
|
||||
"team_balanced_config": {
|
||||
"balance_threshold": 0.1, # 平衡阈值
|
||||
"max_balance_attempts": 5 # 最大平衡尝试次数
|
||||
},
|
||||
"quick_match_config": {
|
||||
"max_queue_time": 30.0, # 最大排队时间
|
||||
"min_players": 2, # 最少玩家数
|
||||
"max_players": 8 # 最多玩家数
|
||||
}
|
||||
}
|
||||
|
||||
# 算法状态
|
||||
self.algorithm_state = {
|
||||
"active_algorithm": "skill_based",
|
||||
"total_matches": 0,
|
||||
"successful_matches": 0,
|
||||
"failed_matches": 0,
|
||||
"average_match_quality": 0.0
|
||||
}
|
||||
|
||||
# 玩家数据存储
|
||||
self.player_data = {} # 玩家技能、统计数据等
|
||||
|
||||
# 算法统计
|
||||
self.algorithm_stats = {
|
||||
"algorithms_run": 0,
|
||||
"matches_created": 0,
|
||||
"players_matched": 0,
|
||||
"algorithm_errors": 0
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.algorithm_callbacks = {
|
||||
"algorithm_selected": [],
|
||||
"match_quality_calculated": [],
|
||||
"algorithm_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_algorithm_run = 0.0
|
||||
self.last_stats_reset = 0.0
|
||||
|
||||
print("✓ 算法管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化算法管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化算法管理器...")
|
||||
|
||||
# 注册默认算法
|
||||
self._register_default_algorithms()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 算法管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 算法管理器初始化失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _register_default_algorithms(self):
|
||||
"""注册默认算法"""
|
||||
try:
|
||||
print("✓ 默认算法已注册")
|
||||
except Exception as e:
|
||||
print(f"✗ 默认算法注册失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用算法管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 算法管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 算法管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 算法管理器启用失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用算法管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
print("✓ 算法管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 算法管理器禁用失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理算法管理器资源"""
|
||||
try:
|
||||
# 禁用算法管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.algorithm_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 算法管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 算法管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新算法管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
self.last_algorithm_run = time.time()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 算法管理器更新失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def set_active_algorithm(self, algorithm_name: str) -> bool:
|
||||
"""
|
||||
设置活动算法
|
||||
|
||||
Args:
|
||||
algorithm_name: 算法名称
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
if algorithm_name not in self.algorithm_config["available_algorithms"]:
|
||||
print(f"✗ 不支持的算法: {algorithm_name}")
|
||||
return False
|
||||
|
||||
self.algorithm_state["active_algorithm"] = algorithm_name
|
||||
print(f"✓ 活动算法已设置为: {algorithm_name}")
|
||||
|
||||
# 触发算法选择回调
|
||||
self._trigger_algorithm_callback("algorithm_selected", {
|
||||
"algorithm": algorithm_name,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 活动算法设置失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
return False
|
||||
|
||||
def run_matching_algorithm(self, players: List[Dict[str, Any]], algorithm: str = None) -> Optional[List[List[Dict[str, Any]]]]:
|
||||
"""
|
||||
运行匹配算法
|
||||
|
||||
Args:
|
||||
players: 玩家列表
|
||||
algorithm: 算法名称(可选,默认使用活动算法)
|
||||
|
||||
Returns:
|
||||
匹配结果(玩家分组列表)或None
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
# 使用指定算法或活动算法
|
||||
if algorithm is None:
|
||||
algorithm = self.algorithm_state["active_algorithm"]
|
||||
|
||||
# 验证算法支持
|
||||
if algorithm not in self.algorithm_config["available_algorithms"]:
|
||||
print(f"✗ 不支持的算法: {algorithm}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
return None
|
||||
|
||||
self.algorithm_stats["algorithms_run"] += 1
|
||||
|
||||
# 根据算法类型运行相应算法
|
||||
if algorithm == "skill_based":
|
||||
result = self._run_skill_based_matching(players)
|
||||
elif algorithm == "quick":
|
||||
result = self._run_quick_matching(players)
|
||||
elif algorithm == "team_balanced":
|
||||
result = self._run_team_balanced_matching(players)
|
||||
else:
|
||||
# 默认使用技能匹配
|
||||
result = self._run_skill_based_matching(players)
|
||||
|
||||
if result:
|
||||
self.algorithm_state["successful_matches"] += 1
|
||||
self.algorithm_state["total_matches"] += 1
|
||||
self.algorithm_stats["matches_created"] += 1
|
||||
|
||||
# 计算匹配质量
|
||||
match_quality = self._calculate_match_quality(result)
|
||||
self.algorithm_state["average_match_quality"] = (
|
||||
self.algorithm_state["average_match_quality"] * (self.algorithm_state["successful_matches"] - 1) +
|
||||
match_quality
|
||||
) / self.algorithm_state["successful_matches"]
|
||||
|
||||
# 触发匹配质量计算回调
|
||||
self._trigger_algorithm_callback("match_quality_calculated", {
|
||||
"quality": match_quality,
|
||||
"algorithm": algorithm,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
else:
|
||||
self.algorithm_state["failed_matches"] += 1
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配算法运行失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
return None
|
||||
|
||||
def _run_skill_based_matching(self, players: List[Dict[str, Any]]) -> Optional[List[List[Dict[str, Any]]]]:
|
||||
"""
|
||||
运行基于技能的匹配算法
|
||||
|
||||
Args:
|
||||
players: 玩家列表
|
||||
|
||||
Returns:
|
||||
匹配结果或None
|
||||
"""
|
||||
try:
|
||||
if not players:
|
||||
return None
|
||||
|
||||
config = self.algorithm_config["skill_based_config"]
|
||||
skill_range = config["skill_range"]
|
||||
|
||||
# 按技能水平排序玩家
|
||||
sorted_players = sorted(players, key=lambda p: p.get("skill_level", 0))
|
||||
|
||||
# 简化实现:将技能相近的玩家分组
|
||||
groups = []
|
||||
current_group = [sorted_players[0]]
|
||||
|
||||
for i in range(1, len(sorted_players)):
|
||||
current_player = sorted_players[i]
|
||||
last_player = current_group[-1]
|
||||
|
||||
# 检查技能差异是否在范围内
|
||||
skill_diff = abs(current_player.get("skill_level", 0) - last_player.get("skill_level", 0))
|
||||
|
||||
if skill_diff <= skill_range and len(current_group) < 8: # 最多8人一组
|
||||
current_group.append(current_player)
|
||||
else:
|
||||
# 创建新组
|
||||
groups.append(current_group)
|
||||
current_group = [current_player]
|
||||
|
||||
# 添加最后一组
|
||||
if current_group:
|
||||
groups.append(current_group)
|
||||
|
||||
print(f"✓ 技能匹配完成: 创建了 {len(groups)} 个组")
|
||||
return groups
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 技能匹配算法失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
return None
|
||||
|
||||
def _run_quick_matching(self, players: List[Dict[str, Any]]) -> Optional[List[List[Dict[str, Any]]]]:
|
||||
"""
|
||||
运行快速匹配算法
|
||||
|
||||
Args:
|
||||
players: 玩家列表
|
||||
|
||||
Returns:
|
||||
匹配结果或None
|
||||
"""
|
||||
try:
|
||||
if not players:
|
||||
return None
|
||||
|
||||
config = self.algorithm_config["quick_match_config"]
|
||||
min_players = config["min_players"]
|
||||
max_players = config["max_players"]
|
||||
|
||||
# 简化实现:随机分组
|
||||
groups = []
|
||||
player_pool = players.copy()
|
||||
random.shuffle(player_pool)
|
||||
|
||||
while player_pool:
|
||||
group_size = min(random.randint(min_players, max_players), len(player_pool))
|
||||
group = player_pool[:group_size]
|
||||
groups.append(group)
|
||||
player_pool = player_pool[group_size:]
|
||||
|
||||
print(f"✓ 快速匹配完成: 创建了 {len(groups)} 个组")
|
||||
return groups
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 快速匹配算法失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
return None
|
||||
|
||||
def _run_team_balanced_matching(self, players: List[Dict[str, Any]]) -> Optional[List[List[Dict[str, Any]]]]:
|
||||
"""
|
||||
运行团队平衡匹配算法
|
||||
|
||||
Args:
|
||||
players: 玩家列表
|
||||
|
||||
Returns:
|
||||
匹配结果或None
|
||||
"""
|
||||
try:
|
||||
if not players or len(players) < 2:
|
||||
return None
|
||||
|
||||
# 简化实现:创建两个平衡的团队
|
||||
# 按技能排序
|
||||
sorted_players = sorted(players, key=lambda p: p.get("skill_level", 0), reverse=True)
|
||||
|
||||
team1 = []
|
||||
team2 = []
|
||||
team1_skill = 0
|
||||
team2_skill = 0
|
||||
|
||||
# 贪心算法分配玩家到技能平衡的团队
|
||||
for player in sorted_players:
|
||||
player_skill = player.get("skill_level", 0)
|
||||
|
||||
if team1_skill <= team2_skill:
|
||||
team1.append(player)
|
||||
team1_skill += player_skill
|
||||
else:
|
||||
team2.append(player)
|
||||
team2_skill += player_skill
|
||||
|
||||
groups = [team1, team2] if team1 and team2 else [sorted_players]
|
||||
|
||||
print(f"✓ 团队平衡匹配完成: 创建了 {len(groups)} 个组")
|
||||
return groups
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 团队平衡匹配算法失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
return None
|
||||
|
||||
def _calculate_match_quality(self, groups: List[List[Dict[str, Any]]]) -> float:
|
||||
"""
|
||||
计算匹配质量
|
||||
|
||||
Args:
|
||||
groups: 玩家分组
|
||||
|
||||
Returns:
|
||||
匹配质量分数(0-1)
|
||||
"""
|
||||
try:
|
||||
if not groups:
|
||||
return 0.0
|
||||
|
||||
total_quality = 0.0
|
||||
group_count = 0
|
||||
|
||||
for group in groups:
|
||||
if len(group) < 2:
|
||||
continue
|
||||
|
||||
# 计算组内技能差异
|
||||
skills = [p.get("skill_level", 0) for p in group]
|
||||
avg_skill = sum(skills) / len(skills)
|
||||
variance = sum((s - avg_skill) ** 2 for s in skills) / len(skills)
|
||||
std_dev = variance ** 0.5
|
||||
|
||||
# 转换为质量分数(标准差越小质量越高)
|
||||
max_expected_std = 100.0 # 假设最大预期标准差
|
||||
quality = max(0.0, 1.0 - (std_dev / max_expected_std))
|
||||
|
||||
total_quality += quality
|
||||
group_count += 1
|
||||
|
||||
return total_quality / group_count if group_count > 0 else 0.0
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配质量计算失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
return 0.0
|
||||
|
||||
def update_player_skill(self, player_id: str, skill_level: float, stats: Dict[str, Any] = None):
|
||||
"""
|
||||
更新玩家技能
|
||||
|
||||
Args:
|
||||
player_id: 玩家ID
|
||||
skill_level: 技能等级
|
||||
stats: 玩家统计数据
|
||||
"""
|
||||
try:
|
||||
if player_id not in self.player_data:
|
||||
self.player_data[player_id] = {
|
||||
"skill_history": [],
|
||||
"match_stats": {}
|
||||
}
|
||||
|
||||
player_info = self.player_data[player_id]
|
||||
player_info["current_skill"] = skill_level
|
||||
player_info["skill_history"].append({
|
||||
"skill": skill_level,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
if stats:
|
||||
player_info["match_stats"].update(stats)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家技能更新失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
|
||||
def get_player_skill(self, player_id: str) -> Optional[float]:
|
||||
"""
|
||||
获取玩家技能
|
||||
|
||||
Args:
|
||||
player_id: 玩家ID
|
||||
|
||||
Returns:
|
||||
玩家技能等级或None
|
||||
"""
|
||||
try:
|
||||
if player_id in self.player_data:
|
||||
return self.player_data[player_id].get("current_skill")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家技能获取失败: {e}")
|
||||
self.algorithm_stats["algorithm_errors"] += 1
|
||||
return None
|
||||
|
||||
def get_algorithm_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取算法统计信息
|
||||
|
||||
Returns:
|
||||
算法统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.algorithm_state.copy(),
|
||||
"stats": self.algorithm_stats.copy(),
|
||||
"config": self.algorithm_config.copy(),
|
||||
"tracked_players": len(self.player_data)
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置算法统计信息"""
|
||||
try:
|
||||
self.algorithm_stats = {
|
||||
"algorithms_run": 0,
|
||||
"matches_created": 0,
|
||||
"players_matched": 0,
|
||||
"algorithm_errors": 0
|
||||
}
|
||||
|
||||
self.algorithm_state["total_matches"] = 0
|
||||
self.algorithm_state["successful_matches"] = 0
|
||||
self.algorithm_state["failed_matches"] = 0
|
||||
self.algorithm_state["average_match_quality"] = 0.0
|
||||
|
||||
print("✓ 算法统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 算法统计信息重置失败: {e}")
|
||||
|
||||
def set_algorithm_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置算法配置
|
||||
|
||||
Args:
|
||||
config: 算法配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.algorithm_config.update(config)
|
||||
print(f"✓ 算法配置已更新: {self.algorithm_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 算法配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_algorithm_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取算法配置
|
||||
|
||||
Returns:
|
||||
算法配置字典
|
||||
"""
|
||||
return self.algorithm_config.copy()
|
||||
|
||||
def _trigger_algorithm_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发算法回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.algorithm_callbacks:
|
||||
for callback in self.algorithm_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 算法回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 算法回调触发失败: {e}")
|
||||
|
||||
def register_algorithm_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册算法回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.algorithm_callbacks:
|
||||
self.algorithm_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 算法回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 算法回调注册失败: {e}")
|
||||
|
||||
def unregister_algorithm_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销算法回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.algorithm_callbacks:
|
||||
if callback in self.algorithm_callbacks[callback_type]:
|
||||
self.algorithm_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 算法回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 算法回调注销失败: {e}")
|
||||
712
plugins/user/matchmaking_system/config/match_config.py
Normal file
712
plugins/user/matchmaking_system/config/match_config.py
Normal file
@ -0,0 +1,712 @@
|
||||
"""
|
||||
匹配配置管理器模块
|
||||
管理匹配系统配置
|
||||
"""
|
||||
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class MatchConfig:
|
||||
"""
|
||||
匹配配置管理器
|
||||
管理匹配系统配置
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化匹配配置管理器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 配置文件路径
|
||||
self.config_file_path = "/home/hello/EG/plugins/user/matchmaking_system/config/matchmaking_config.json"
|
||||
|
||||
# 默认配置
|
||||
self.default_config = {
|
||||
"system": {
|
||||
"enable_matchmaking": True,
|
||||
"max_concurrent_matches": 1000,
|
||||
"default_match_timeout": 300.0,
|
||||
"enable_cross_platform_matching": True
|
||||
},
|
||||
"queue": {
|
||||
"default_queue_timeout": 300.0,
|
||||
"queue_processing_interval": 2.0,
|
||||
"max_players_per_match": 100,
|
||||
"min_players_per_match": 2,
|
||||
"enable_queue_prioritization": True
|
||||
},
|
||||
"matching": {
|
||||
"default_algorithm": "skill_based",
|
||||
"skill_range": 100,
|
||||
"max_wait_time": 120.0,
|
||||
"enable_skill_based_matching": True,
|
||||
"enable_team_balancing": True
|
||||
},
|
||||
"room": {
|
||||
"default_max_players": 8,
|
||||
"enable_room_passwords": True,
|
||||
"enable_room_visibility": True,
|
||||
"room_timeout": 3600,
|
||||
"max_rooms": 1000
|
||||
},
|
||||
"monitoring": {
|
||||
"enable_monitoring": True,
|
||||
"monitoring_interval": 5.0,
|
||||
"log_level": "INFO",
|
||||
"enable_performance_monitoring": True
|
||||
},
|
||||
"events": {
|
||||
"enable_event_system": True,
|
||||
"max_event_queue_size": 10000,
|
||||
"enable_event_filtering": True
|
||||
}
|
||||
}
|
||||
|
||||
# 当前配置
|
||||
self.current_config = self.default_config.copy()
|
||||
|
||||
# 配置状态
|
||||
self.config_state = {
|
||||
"last_loaded": 0.0,
|
||||
"last_saved": 0.0,
|
||||
"config_version": "1.0.0",
|
||||
"is_dirty": False
|
||||
}
|
||||
|
||||
# 配置统计
|
||||
self.config_stats = {
|
||||
"loads": 0,
|
||||
"saves": 0,
|
||||
"updates": 0,
|
||||
"config_errors": 0
|
||||
}
|
||||
|
||||
# 配置监听器
|
||||
self.config_listeners = {}
|
||||
|
||||
# 回调函数
|
||||
self.config_callbacks = {
|
||||
"config_loaded": [],
|
||||
"config_saved": [],
|
||||
"config_updated": [],
|
||||
"config_error": []
|
||||
}
|
||||
|
||||
print("✓ 匹配配置管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化匹配配置管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化匹配配置管理器...")
|
||||
|
||||
# 创建配置目录
|
||||
config_dir = os.path.dirname(self.config_file_path)
|
||||
if not os.path.exists(config_dir):
|
||||
os.makedirs(config_dir)
|
||||
|
||||
# 加载配置
|
||||
self.load_config()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 匹配配置管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配配置管理器初始化失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用匹配配置管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 匹配配置管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 匹配配置管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配配置管理器启用失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用匹配配置管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 保存配置(如果有更改)
|
||||
if self.config_state["is_dirty"]:
|
||||
self.save_config()
|
||||
|
||||
print("✓ 匹配配置管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配配置管理器禁用失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理匹配配置管理器资源"""
|
||||
try:
|
||||
# 禁用匹配配置管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.config_callbacks.clear()
|
||||
self.config_listeners.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 匹配配置管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配配置管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新匹配配置管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
# 检查配置文件是否被外部修改
|
||||
self._check_config_file_changes()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配配置管理器更新失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _check_config_file_changes(self):
|
||||
"""检查配置文件是否被外部修改"""
|
||||
try:
|
||||
if not os.path.exists(self.config_file_path):
|
||||
return
|
||||
|
||||
last_modified = os.path.getmtime(self.config_file_path)
|
||||
if last_modified > self.config_state["last_loaded"]:
|
||||
# 配置文件已被修改,重新加载
|
||||
print("检测到配置文件被外部修改,正在重新加载...")
|
||||
self.load_config()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置文件变更检查失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
def load_config(self) -> bool:
|
||||
"""
|
||||
加载配置
|
||||
|
||||
Returns:
|
||||
是否加载成功
|
||||
"""
|
||||
try:
|
||||
# 检查配置文件是否存在
|
||||
if os.path.exists(self.config_file_path):
|
||||
with open(self.config_file_path, 'r', encoding='utf-8') as f:
|
||||
loaded_config = json.load(f)
|
||||
|
||||
# 合并配置(使用默认配置作为基础)
|
||||
self.current_config = self._merge_config(self.default_config, loaded_config)
|
||||
|
||||
print(f"✓ 配置已从文件加载: {self.config_file_path}")
|
||||
else:
|
||||
# 使用默认配置
|
||||
self.current_config = self.default_config.copy()
|
||||
print("✓ 使用默认配置")
|
||||
|
||||
self.config_state["last_loaded"] = time.time()
|
||||
self.config_state["is_dirty"] = False
|
||||
self.config_stats["loads"] += 1
|
||||
|
||||
# 触发配置加载回调
|
||||
self._trigger_config_callback("config_loaded", {
|
||||
"config": self.current_config,
|
||||
"timestamp": self.config_state["last_loaded"]
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置加载失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
# 使用默认配置
|
||||
self.current_config = self.default_config.copy()
|
||||
return False
|
||||
|
||||
def _merge_config(self, base_config: Dict[str, Any], override_config: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
合并配置(递归)
|
||||
|
||||
Args:
|
||||
base_config: 基础配置
|
||||
override_config: 覆盖配置
|
||||
|
||||
Returns:
|
||||
合并后的配置
|
||||
"""
|
||||
try:
|
||||
merged = base_config.copy()
|
||||
|
||||
for key, value in override_config.items():
|
||||
if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
|
||||
# 递归合并嵌套字典
|
||||
merged[key] = self._merge_config(merged[key], value)
|
||||
else:
|
||||
# 直接覆盖
|
||||
merged[key] = value
|
||||
|
||||
return merged
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置合并失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return base_config
|
||||
|
||||
def save_config(self) -> bool:
|
||||
"""
|
||||
保存配置
|
||||
|
||||
Returns:
|
||||
是否保存成功
|
||||
"""
|
||||
try:
|
||||
# 创建配置目录(如果不存在)
|
||||
config_dir = os.path.dirname(self.config_file_path)
|
||||
if not os.path.exists(config_dir):
|
||||
os.makedirs(config_dir)
|
||||
|
||||
# 保存配置到文件
|
||||
with open(self.config_file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.current_config, f, indent=2, ensure_ascii=False)
|
||||
|
||||
self.config_state["last_saved"] = time.time()
|
||||
self.config_state["is_dirty"] = False
|
||||
self.config_stats["saves"] += 1
|
||||
|
||||
# 触发配置保存回调
|
||||
self._trigger_config_callback("config_saved", {
|
||||
"config": self.current_config,
|
||||
"timestamp": self.config_state["last_saved"]
|
||||
})
|
||||
|
||||
print(f"✓ 配置已保存到文件: {self.config_file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置保存失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_config(self, section: str = None, key: str = None, default_value: Any = None) -> Any:
|
||||
"""
|
||||
获取配置值
|
||||
|
||||
Args:
|
||||
section: 配置节(可选)
|
||||
key: 配置键(可选)
|
||||
default_value: 默认值
|
||||
|
||||
Returns:
|
||||
配置值
|
||||
"""
|
||||
try:
|
||||
if section is None:
|
||||
return self.current_config.copy()
|
||||
|
||||
if section not in self.current_config:
|
||||
return default_value
|
||||
|
||||
if key is None:
|
||||
return self.current_config[section].copy()
|
||||
|
||||
if key not in self.current_config[section]:
|
||||
return default_value
|
||||
|
||||
return self.current_config[section][key]
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取配置失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return default_value
|
||||
|
||||
def set_config(self, section: str, key: str, value: Any) -> bool:
|
||||
"""
|
||||
设置配置值
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
value: 配置值
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
if section not in self.current_config:
|
||||
self.current_config[section] = {}
|
||||
|
||||
self.current_config[section][key] = value
|
||||
self.config_state["is_dirty"] = True
|
||||
self.config_stats["updates"] += 1
|
||||
|
||||
# 通知配置监听器
|
||||
self._notify_config_listeners(section, key, value)
|
||||
|
||||
# 触发配置更新回调
|
||||
self._trigger_config_callback("config_updated", {
|
||||
"section": section,
|
||||
"key": key,
|
||||
"value": value,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 设置配置失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def update_config_section(self, section: str, config_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
更新配置节
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
config_data: 配置数据
|
||||
|
||||
Returns:
|
||||
是否更新成功
|
||||
"""
|
||||
try:
|
||||
if section not in self.current_config:
|
||||
self.current_config[section] = {}
|
||||
|
||||
self.current_config[section].update(config_data)
|
||||
self.config_state["is_dirty"] = True
|
||||
self.config_stats["updates"] += 1
|
||||
|
||||
# 通知配置监听器
|
||||
for key, value in config_data.items():
|
||||
self._notify_config_listeners(section, key, value)
|
||||
|
||||
# 触发配置更新回调
|
||||
self._trigger_config_callback("config_updated", {
|
||||
"section": section,
|
||||
"config_data": config_data,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 更新配置节失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def reset_config(self) -> bool:
|
||||
"""
|
||||
重置配置为默认值
|
||||
|
||||
Returns:
|
||||
是否重置成功
|
||||
"""
|
||||
try:
|
||||
self.current_config = self.default_config.copy()
|
||||
self.config_state["is_dirty"] = True
|
||||
|
||||
# 通知所有配置监听器
|
||||
for section_name, section_data in self.current_config.items():
|
||||
if isinstance(section_data, dict):
|
||||
for key, value in section_data.items():
|
||||
self._notify_config_listeners(section_name, key, value)
|
||||
|
||||
print("✓ 配置已重置为默认值")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置重置失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def register_config_listener(self, section: str, key: str, listener: callable):
|
||||
"""
|
||||
注册配置监听器
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
listener: 监听器函数
|
||||
"""
|
||||
try:
|
||||
listener_key = f"{section}.{key}"
|
||||
if listener_key not in self.config_listeners:
|
||||
self.config_listeners[listener_key] = []
|
||||
|
||||
self.config_listeners[listener_key].append(listener)
|
||||
print(f"✓ 配置监听器已注册: {listener_key}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置监听器注册失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
def unregister_config_listener(self, section: str, key: str, listener: callable):
|
||||
"""
|
||||
注销配置监听器
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
listener: 监听器函数
|
||||
"""
|
||||
try:
|
||||
listener_key = f"{section}.{key}"
|
||||
if listener_key in self.config_listeners:
|
||||
if listener in self.config_listeners[listener_key]:
|
||||
self.config_listeners[listener_key].remove(listener)
|
||||
print(f"✓ 配置监听器已注销: {listener_key}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置监听器注销失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
def _notify_config_listeners(self, section: str, key: str, value: Any):
|
||||
"""
|
||||
通知配置监听器
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
value: 配置值
|
||||
"""
|
||||
try:
|
||||
listener_key = f"{section}.{key}"
|
||||
if listener_key in self.config_listeners:
|
||||
for listener in self.config_listeners[listener_key]:
|
||||
try:
|
||||
listener(section, key, value)
|
||||
except Exception as e:
|
||||
print(f"✗ 配置监听器执行失败: {listener_key} - {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置监听器通知失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
def get_config_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取配置统计信息
|
||||
|
||||
Returns:
|
||||
配置统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.config_state.copy(),
|
||||
"stats": self.config_stats.copy(),
|
||||
"config_sections": list(self.current_config.keys())
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置配置统计信息"""
|
||||
try:
|
||||
self.config_stats = {
|
||||
"loads": 0,
|
||||
"saves": 0,
|
||||
"updates": 0,
|
||||
"config_errors": 0
|
||||
}
|
||||
print("✓ 配置统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 配置统计信息重置失败: {e}")
|
||||
|
||||
def validate_config(self) -> bool:
|
||||
"""
|
||||
验证配置
|
||||
|
||||
Returns:
|
||||
配置是否有效
|
||||
"""
|
||||
try:
|
||||
# 检查必需的配置项
|
||||
required_sections = ["system", "queue", "matching", "room", "monitoring", "events"]
|
||||
for section in required_sections:
|
||||
if section not in self.current_config:
|
||||
print(f"✗ 缺少必需的配置节: {section}")
|
||||
return False
|
||||
|
||||
# 检查系统配置
|
||||
system_config = self.current_config["system"]
|
||||
if "max_concurrent_matches" not in system_config or not isinstance(system_config["max_concurrent_matches"], int):
|
||||
print("✗ 无效的最大并发匹配数配置")
|
||||
return False
|
||||
|
||||
# 检查队列配置
|
||||
queue_config = self.current_config["queue"]
|
||||
if "max_players_per_match" not in queue_config or not isinstance(queue_config["max_players_per_match"], int):
|
||||
print("✗ 无效的最大玩家数配置")
|
||||
return False
|
||||
|
||||
print("✓ 配置验证通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置验证失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def export_config(self, file_path: str) -> bool:
|
||||
"""
|
||||
导出配置到文件
|
||||
|
||||
Args:
|
||||
file_path: 导出文件路径
|
||||
|
||||
Returns:
|
||||
是否导出成功
|
||||
"""
|
||||
try:
|
||||
# 创建导出目录
|
||||
export_dir = os.path.dirname(file_path)
|
||||
if not os.path.exists(export_dir):
|
||||
os.makedirs(export_dir)
|
||||
|
||||
# 导出配置
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.current_config, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print(f"✓ 配置已导出到: {file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置导出失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def import_config(self, file_path: str) -> bool:
|
||||
"""
|
||||
从文件导入配置
|
||||
|
||||
Args:
|
||||
file_path: 导入文件路径
|
||||
|
||||
Returns:
|
||||
是否导入成功
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists(file_path):
|
||||
print(f"✗ 配置文件不存在: {file_path}")
|
||||
return False
|
||||
|
||||
# 读取配置文件
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
imported_config = json.load(f)
|
||||
|
||||
# 验证配置
|
||||
if not isinstance(imported_config, dict):
|
||||
print("✗ 无效的配置文件格式")
|
||||
return False
|
||||
|
||||
# 合并配置
|
||||
self.current_config = self._merge_config(self.default_config, imported_config)
|
||||
self.config_state["is_dirty"] = True
|
||||
|
||||
# 通知配置监听器
|
||||
for section_name, section_data in self.current_config.items():
|
||||
if isinstance(section_data, dict):
|
||||
for key, value in section_data.items():
|
||||
self._notify_config_listeners(section_name, key, value)
|
||||
|
||||
print(f"✓ 配置已从文件导入: {file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置导入失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def _trigger_config_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发配置回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.config_callbacks:
|
||||
for callback in self.config_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 配置回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 配置回调触发失败: {e}")
|
||||
|
||||
def register_config_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册配置回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.config_callbacks:
|
||||
self.config_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 配置回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 配置回调注册失败: {e}")
|
||||
|
||||
def unregister_config_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销配置回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.config_callbacks:
|
||||
if callback in self.config_callbacks[callback_type]:
|
||||
self.config_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 配置回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 配置回调注销失败: {e}")
|
||||
417
plugins/user/matchmaking_system/core/match_manager.py
Normal file
417
plugins/user/matchmaking_system/core/match_manager.py
Normal file
@ -0,0 +1,417 @@
|
||||
"""
|
||||
匹配管理器模块
|
||||
管理匹配过程和规则
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class MatchManager:
|
||||
"""
|
||||
匹配管理器
|
||||
管理匹配过程和规则
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化匹配管理器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 匹配配置
|
||||
self.match_config = {
|
||||
"enable_matchmaking": True,
|
||||
"matchmaking_interval": 1.0,
|
||||
"max_match_attempts": 3,
|
||||
"match_timeout": 30.0,
|
||||
"enable_skill_based_matching": True,
|
||||
"enable_team_balancing": True,
|
||||
"enable_cross_platform_matching": True
|
||||
}
|
||||
|
||||
# 匹配状态
|
||||
self.match_state = {
|
||||
"is_matching": False,
|
||||
"active_matches": 0,
|
||||
"successful_matches": 0,
|
||||
"failed_matches": 0,
|
||||
"last_match_time": 0.0
|
||||
}
|
||||
|
||||
# 匹配统计
|
||||
self.match_stats = {
|
||||
"matches_started": 0,
|
||||
"matches_completed": 0,
|
||||
"matches_cancelled": 0,
|
||||
"average_match_time": 0.0,
|
||||
"match_errors": 0
|
||||
}
|
||||
|
||||
# 匹配锁
|
||||
self.match_lock = threading.RLock()
|
||||
|
||||
# 回调函数
|
||||
self.match_callbacks = {
|
||||
"match_started": [],
|
||||
"match_completed": [],
|
||||
"match_cancelled": [],
|
||||
"match_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_matchmaking_run = 0.0
|
||||
self.last_stats_reset = 0.0
|
||||
|
||||
print("✓ 匹配管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化匹配管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化匹配管理器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 匹配管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配管理器初始化失败: {e}")
|
||||
self.match_stats["match_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用匹配管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 匹配管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 匹配管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配管理器启用失败: {e}")
|
||||
self.match_stats["match_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用匹配管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
print("✓ 匹配管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配管理器禁用失败: {e}")
|
||||
self.match_stats["match_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理匹配管理器资源"""
|
||||
try:
|
||||
# 禁用匹配管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.match_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 匹配管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新匹配管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期运行匹配算法
|
||||
if current_time - self.last_matchmaking_run >= self.match_config["matchmaking_interval"]:
|
||||
self._run_matchmaking()
|
||||
self.last_matchmaking_run = current_time
|
||||
|
||||
self.match_state["last_match_time"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配管理器更新失败: {e}")
|
||||
self.match_stats["match_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _run_matchmaking(self):
|
||||
"""运行匹配算法"""
|
||||
try:
|
||||
if not self.match_config["enable_matchmaking"]:
|
||||
return
|
||||
|
||||
# 通知队列管理器运行匹配
|
||||
if self.plugin.queue_manager:
|
||||
self.plugin.queue_manager.process_queues()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配算法运行失败: {e}")
|
||||
self.match_stats["match_errors"] += 1
|
||||
|
||||
def start_matchmaking(self, player_ids: List[str], match_params: Dict[str, Any] = None) -> str:
|
||||
"""
|
||||
开始匹配
|
||||
|
||||
Args:
|
||||
player_ids: 玩家ID列表
|
||||
match_params: 匹配参数
|
||||
|
||||
Returns:
|
||||
匹配ID
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
raise Exception("匹配管理器未启用")
|
||||
|
||||
# 生成匹配ID
|
||||
match_id = f"match_{int(time.time() * 1000000)}"
|
||||
|
||||
# 添加玩家到队列
|
||||
if self.plugin.queue_manager:
|
||||
queue_success = self.plugin.queue_manager.add_players_to_queue(
|
||||
player_ids, match_params or {})
|
||||
|
||||
if queue_success:
|
||||
self.match_stats["matches_started"] += 1
|
||||
self.match_state["active_matches"] += 1
|
||||
|
||||
# 触发匹配开始回调
|
||||
self._trigger_match_callback("match_started", {
|
||||
"match_id": match_id,
|
||||
"player_ids": player_ids,
|
||||
"match_params": match_params,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 匹配已开始: {match_id}")
|
||||
return match_id
|
||||
else:
|
||||
raise Exception("添加玩家到队列失败")
|
||||
else:
|
||||
raise Exception("队列管理器不可用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配开始失败: {e}")
|
||||
self.match_stats["match_errors"] += 1
|
||||
|
||||
# 触发匹配错误回调
|
||||
self._trigger_match_callback("match_error", {
|
||||
"player_ids": player_ids,
|
||||
"error": str(e),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return ""
|
||||
|
||||
def cancel_matchmaking(self, match_id: str) -> bool:
|
||||
"""
|
||||
取消匹配
|
||||
|
||||
Args:
|
||||
match_id: 匹配ID
|
||||
|
||||
Returns:
|
||||
是否取消成功
|
||||
"""
|
||||
try:
|
||||
# 从队列中移除玩家
|
||||
if self.plugin.queue_manager:
|
||||
cancel_success = self.plugin.queue_manager.remove_players_from_queue(match_id)
|
||||
|
||||
if cancel_success:
|
||||
self.match_stats["matches_cancelled"] += 1
|
||||
if self.match_state["active_matches"] > 0:
|
||||
self.match_state["active_matches"] -= 1
|
||||
|
||||
# 触发匹配取消回调
|
||||
self._trigger_match_callback("match_cancelled", {
|
||||
"match_id": match_id,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 匹配已取消: {match_id}")
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配取消失败: {e}")
|
||||
self.match_stats["match_errors"] += 1
|
||||
return False
|
||||
|
||||
def complete_match(self, match_id: str, room_id: str) -> bool:
|
||||
"""
|
||||
完成匹配
|
||||
|
||||
Args:
|
||||
match_id: 匹配ID
|
||||
room_id: 房间ID
|
||||
|
||||
Returns:
|
||||
是否完成成功
|
||||
"""
|
||||
try:
|
||||
self.match_stats["matches_completed"] += 1
|
||||
self.match_state["successful_matches"] += 1
|
||||
if self.match_state["active_matches"] > 0:
|
||||
self.match_state["active_matches"] -= 1
|
||||
|
||||
# 触发匹配完成回调
|
||||
self._trigger_match_callback("match_completed", {
|
||||
"match_id": match_id,
|
||||
"room_id": room_id,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 匹配已完成: {match_id} -> 房间: {room_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配完成失败: {e}")
|
||||
self.match_stats["match_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_match_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取匹配统计信息
|
||||
|
||||
Returns:
|
||||
匹配统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.match_state.copy(),
|
||||
"stats": self.match_stats.copy(),
|
||||
"config": self.match_config.copy()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置匹配统计信息"""
|
||||
try:
|
||||
self.match_stats = {
|
||||
"matches_started": 0,
|
||||
"matches_completed": 0,
|
||||
"matches_cancelled": 0,
|
||||
"average_match_time": 0.0,
|
||||
"match_errors": 0
|
||||
}
|
||||
print("✓ 匹配统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配统计信息重置失败: {e}")
|
||||
|
||||
def set_match_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置匹配配置
|
||||
|
||||
Args:
|
||||
config: 匹配配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.match_config.update(config)
|
||||
print(f"✓ 匹配配置已更新: {self.match_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_match_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取匹配配置
|
||||
|
||||
Returns:
|
||||
匹配配置字典
|
||||
"""
|
||||
return self.match_config.copy()
|
||||
|
||||
def _trigger_match_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发匹配回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.match_callbacks:
|
||||
for callback in self.match_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配回调触发失败: {e}")
|
||||
|
||||
def register_match_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册匹配回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.match_callbacks:
|
||||
self.match_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 匹配回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配回调注册失败: {e}")
|
||||
|
||||
def unregister_match_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销匹配回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.match_callbacks:
|
||||
if callback in self.match_callbacks[callback_type]:
|
||||
self.match_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 匹配回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配回调注销失败: {e}")
|
||||
606
plugins/user/matchmaking_system/editor/match_editor.py
Normal file
606
plugins/user/matchmaking_system/editor/match_editor.py
Normal file
@ -0,0 +1,606 @@
|
||||
"""
|
||||
匹配编辑器模块
|
||||
提供图形界面配置匹配参数
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class MatchEditor:
|
||||
"""
|
||||
匹配编辑器
|
||||
提供图形界面配置匹配参数
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化匹配编辑器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 编辑器配置
|
||||
self.editor_config = {
|
||||
"enable_editor": True,
|
||||
"enable_realtime_monitoring": True,
|
||||
"enable_performance_display": True,
|
||||
"enable_config_editor": True,
|
||||
"enable_statistics_display": True,
|
||||
"refresh_interval": 1.0,
|
||||
"max_data_points": 100
|
||||
}
|
||||
|
||||
# 编辑器状态
|
||||
self.editor_state = {
|
||||
"is_visible": False,
|
||||
"last_update": 0.0,
|
||||
"active_tab": "overview",
|
||||
"selected_queue": None,
|
||||
"selected_algorithm": None
|
||||
}
|
||||
|
||||
# UI组件
|
||||
self.ui_components = {
|
||||
"main_window": None,
|
||||
"tabs": {},
|
||||
"panels": {},
|
||||
"charts": {},
|
||||
"controls": {}
|
||||
}
|
||||
|
||||
# 编辑器统计
|
||||
self.editor_stats = {
|
||||
"updates": 0,
|
||||
"ui_refreshes": 0,
|
||||
"data_points": 0,
|
||||
"editor_errors": 0
|
||||
}
|
||||
|
||||
# 实时数据缓存
|
||||
self.realtime_data = {
|
||||
"performance_metrics": {},
|
||||
"queue_data": {},
|
||||
"match_data": {},
|
||||
"algorithm_stats": {},
|
||||
"system_stats": {}
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.editor_callbacks = {
|
||||
"ui_updated": [],
|
||||
"data_refreshed": [],
|
||||
"config_changed": [],
|
||||
"editor_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_ui_update = 0.0
|
||||
self.last_data_refresh = 0.0
|
||||
|
||||
print("✓ 匹配编辑器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化匹配编辑器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化匹配编辑器...")
|
||||
|
||||
# 初始化UI组件(模拟)
|
||||
self._initialize_ui_components()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 匹配编辑器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配编辑器初始化失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _initialize_ui_components(self):
|
||||
"""初始化UI组件"""
|
||||
try:
|
||||
# 创建主窗口
|
||||
self.ui_components["main_window"] = {
|
||||
"title": "匹配系统编辑器",
|
||||
"size": (1200, 800),
|
||||
"position": (100, 100)
|
||||
}
|
||||
|
||||
# 创建标签页
|
||||
self.ui_components["tabs"] = {
|
||||
"overview": {"name": "概览", "icon": "dashboard"},
|
||||
"queues": {"name": "队列", "icon": "queue"},
|
||||
"matches": {"name": "匹配", "icon": "gamepad"},
|
||||
"algorithms": {"name": "算法", "icon": "calculate"},
|
||||
"rooms": {"name": "房间", "icon": "meeting_room"},
|
||||
"config": {"name": "配置", "icon": "settings"},
|
||||
"statistics": {"name": "统计", "icon": "bar_chart"}
|
||||
}
|
||||
|
||||
# 创建面板
|
||||
self.ui_components["panels"] = {
|
||||
"system_status": {"title": "系统状态", "visible": True},
|
||||
"performance": {"title": "性能指标", "visible": True},
|
||||
"queues_list": {"title": "队列列表", "visible": True},
|
||||
"matches_list": {"title": "匹配列表", "visible": True},
|
||||
"algorithm_stats": {"title": "算法统计", "visible": True}
|
||||
}
|
||||
|
||||
print("✓ UI组件已初始化")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ UI组件初始化失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用匹配编辑器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 匹配编辑器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 匹配编辑器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配编辑器启用失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用匹配编辑器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 隐藏UI
|
||||
self.hide_editor()
|
||||
|
||||
print("✓ 匹配编辑器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配编辑器禁用失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理匹配编辑器资源"""
|
||||
try:
|
||||
# 禁用匹配编辑器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.editor_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 匹配编辑器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配编辑器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新匹配编辑器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期刷新UI
|
||||
if current_time - self.last_ui_update >= self.editor_config["refresh_interval"]:
|
||||
self._refresh_ui()
|
||||
self.last_ui_update = current_time
|
||||
|
||||
# 定期更新数据
|
||||
if current_time - self.last_data_refresh >= 0.5: # 每0.5秒更新一次数据
|
||||
self._update_realtime_data()
|
||||
self.last_data_refresh = current_time
|
||||
|
||||
self.editor_state["last_update"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配编辑器更新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _refresh_ui(self):
|
||||
"""刷新UI"""
|
||||
try:
|
||||
# 更新UI组件状态
|
||||
self._update_ui_components()
|
||||
|
||||
# 更新统计信息
|
||||
self.editor_stats["ui_refreshes"] += 1
|
||||
|
||||
# 触发UI更新回调
|
||||
self._trigger_editor_callback("ui_updated", {
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ UI刷新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def _update_ui_components(self):
|
||||
"""更新UI组件"""
|
||||
try:
|
||||
# 更新系统状态面板
|
||||
system_stats = {}
|
||||
if self.plugin.match_manager:
|
||||
system_stats.update(self.plugin.match_manager.get_match_stats())
|
||||
if self.plugin.queue_manager:
|
||||
system_stats.update(self.plugin.queue_manager.get_queue_stats())
|
||||
if self.plugin.algorithm_manager:
|
||||
system_stats.update(self.plugin.algorithm_manager.get_algorithm_stats())
|
||||
|
||||
self.ui_components["panels"]["system_status"]["data"] = system_stats
|
||||
|
||||
# 更新队列列表面板
|
||||
if self.plugin.queue_manager:
|
||||
queues = self.plugin.queue_manager.get_queue_info()
|
||||
self.ui_components["panels"]["queues_list"]["data"] = queues
|
||||
|
||||
# 更新匹配列表面板
|
||||
if self.plugin.match_manager:
|
||||
match_stats = self.plugin.match_manager.get_match_stats()
|
||||
self.ui_components["panels"]["matches_list"]["data"] = match_stats
|
||||
|
||||
# 更新算法统计面板
|
||||
if self.plugin.algorithm_manager:
|
||||
algorithm_stats = self.plugin.algorithm_manager.get_algorithm_stats()
|
||||
self.ui_components["panels"]["algorithm_stats"]["data"] = algorithm_stats
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ UI组件更新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def _update_realtime_data(self):
|
||||
"""更新实时数据"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
|
||||
# 更新性能指标
|
||||
if self.plugin.monitor:
|
||||
metrics = self.plugin.monitor.get_performance_metrics()
|
||||
self.realtime_data["performance_metrics"] = metrics
|
||||
|
||||
# 更新队列数据
|
||||
if self.plugin.queue_manager:
|
||||
queue_info = self.plugin.queue_manager.get_queue_info()
|
||||
self.realtime_data["queue_data"] = queue_info
|
||||
|
||||
# 更新匹配数据
|
||||
if self.plugin.match_manager:
|
||||
match_stats = self.plugin.match_manager.get_match_stats()
|
||||
self.realtime_data["match_data"] = match_stats
|
||||
|
||||
# 更新算法统计
|
||||
if self.plugin.algorithm_manager:
|
||||
algorithm_stats = self.plugin.algorithm_manager.get_algorithm_stats()
|
||||
self.realtime_data["algorithm_stats"] = algorithm_stats
|
||||
|
||||
# 更新系统统计
|
||||
system_stats = {}
|
||||
if self.plugin.config_manager:
|
||||
system_stats["config"] = self.plugin.config_manager.get_config_stats()
|
||||
if self.plugin.event_handler:
|
||||
system_stats["events"] = self.plugin.event_handler.get_event_stats()
|
||||
|
||||
self.realtime_data["system_stats"] = system_stats
|
||||
|
||||
# 触发数据刷新回调
|
||||
self._trigger_editor_callback("data_refreshed", {
|
||||
"data": self.realtime_data,
|
||||
"timestamp": current_time
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 实时数据更新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def show_editor(self):
|
||||
"""显示编辑器"""
|
||||
try:
|
||||
self.editor_state["is_visible"] = True
|
||||
print("✓ 匹配编辑器已显示")
|
||||
|
||||
# 刷新数据
|
||||
self._update_realtime_data()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器显示失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def hide_editor(self):
|
||||
"""隐藏编辑器"""
|
||||
try:
|
||||
self.editor_state["is_visible"] = False
|
||||
print("✓ 匹配编辑器已隐藏")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器隐藏失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def switch_tab(self, tab_name: str):
|
||||
"""
|
||||
切换标签页
|
||||
|
||||
Args:
|
||||
tab_name: 标签页名称
|
||||
"""
|
||||
try:
|
||||
if tab_name in self.ui_components["tabs"]:
|
||||
self.editor_state["active_tab"] = tab_name
|
||||
print(f"✓ 切换到标签页: {tab_name}")
|
||||
else:
|
||||
print(f"✗ 无效的标签页: {tab_name}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 标签页切换失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def select_queue(self, queue_name: str):
|
||||
"""
|
||||
选择队列
|
||||
|
||||
Args:
|
||||
queue_name: 队列名称
|
||||
"""
|
||||
try:
|
||||
self.editor_state["selected_queue"] = queue_name
|
||||
print(f"✓ 选择队列: {queue_name}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列选择失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def select_algorithm(self, algorithm_name: str):
|
||||
"""
|
||||
选择算法
|
||||
|
||||
Args:
|
||||
algorithm_name: 算法名称
|
||||
"""
|
||||
try:
|
||||
self.editor_state["selected_algorithm"] = algorithm_name
|
||||
print(f"✓ 选择算法: {algorithm_name}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 算法选择失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def update_config(self, section: str, key: str, value: Any) -> bool:
|
||||
"""
|
||||
更新配置
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
value: 配置值
|
||||
|
||||
Returns:
|
||||
是否更新成功
|
||||
"""
|
||||
try:
|
||||
# 通过配置管理器更新配置
|
||||
if self.plugin.config_manager:
|
||||
result = self.plugin.config_manager.set_config(section, key, value)
|
||||
|
||||
if result:
|
||||
self.editor_stats["updates"] += 1
|
||||
|
||||
# 触发配置更改回调
|
||||
self._trigger_editor_callback("config_changed", {
|
||||
"section": section,
|
||||
"key": key,
|
||||
"value": value,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 配置已更新: {section}.{key} = {value}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 配置更新失败: {section}.{key}")
|
||||
return False
|
||||
else:
|
||||
print("✗ 配置管理器不可用")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置更新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_editor_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取编辑器统计信息
|
||||
|
||||
Returns:
|
||||
编辑器统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.editor_state.copy(),
|
||||
"stats": self.editor_stats.copy(),
|
||||
"config": self.editor_config.copy(),
|
||||
"ui_components": len(self.ui_components["tabs"])
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置编辑器统计信息"""
|
||||
try:
|
||||
self.editor_stats = {
|
||||
"updates": 0,
|
||||
"ui_refreshes": 0,
|
||||
"data_points": 0,
|
||||
"editor_errors": 0
|
||||
}
|
||||
print("✓ 编辑器统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器统计信息重置失败: {e}")
|
||||
|
||||
def set_editor_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置编辑器配置
|
||||
|
||||
Args:
|
||||
config: 编辑器配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.editor_config.update(config)
|
||||
print(f"✓ 编辑器配置已更新: {self.editor_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_editor_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取编辑器配置
|
||||
|
||||
Returns:
|
||||
编辑器配置字典
|
||||
"""
|
||||
return self.editor_config.copy()
|
||||
|
||||
def get_realtime_data(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取实时数据
|
||||
|
||||
Returns:
|
||||
实时数据字典
|
||||
"""
|
||||
return self.realtime_data.copy()
|
||||
|
||||
def export_data(self, data_type: str, file_path: str) -> bool:
|
||||
"""
|
||||
导出数据
|
||||
|
||||
Args:
|
||||
data_type: 数据类型
|
||||
file_path: 导出文件路径
|
||||
|
||||
Returns:
|
||||
是否导出成功
|
||||
"""
|
||||
try:
|
||||
import json
|
||||
import os
|
||||
|
||||
# 创建导出目录
|
||||
export_dir = os.path.dirname(file_path)
|
||||
if not os.path.exists(export_dir):
|
||||
os.makedirs(export_dir)
|
||||
|
||||
# 获取要导出的数据
|
||||
export_data = None
|
||||
if data_type == "performance":
|
||||
export_data = self.realtime_data["performance_metrics"]
|
||||
elif data_type == "queues":
|
||||
export_data = self.realtime_data["queue_data"]
|
||||
elif data_type == "matches":
|
||||
export_data = self.realtime_data["match_data"]
|
||||
elif data_type == "algorithms":
|
||||
export_data = self.realtime_data["algorithm_stats"]
|
||||
elif data_type == "system":
|
||||
export_data = self.realtime_data["system_stats"]
|
||||
elif data_type == "all":
|
||||
export_data = self.realtime_data
|
||||
else:
|
||||
print(f"✗ 不支持的数据类型: {data_type}")
|
||||
return False
|
||||
|
||||
# 导出数据
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(export_data, f, indent=2, ensure_ascii=False, default=str)
|
||||
|
||||
print(f"✓ 数据已导出到: {file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 数据导出失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
return False
|
||||
|
||||
def _trigger_editor_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发编辑器回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.editor_callbacks:
|
||||
for callback in self.editor_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器回调触发失败: {e}")
|
||||
|
||||
def register_editor_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册编辑器回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.editor_callbacks:
|
||||
self.editor_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 编辑器回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器回调注册失败: {e}")
|
||||
|
||||
def unregister_editor_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销编辑器回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.editor_callbacks:
|
||||
if callback in self.editor_callbacks[callback_type]:
|
||||
self.editor_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 编辑器回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器回调注销失败: {e}")
|
||||
699
plugins/user/matchmaking_system/events/event_handler.py
Normal file
699
plugins/user/matchmaking_system/events/event_handler.py
Normal file
@ -0,0 +1,699 @@
|
||||
"""
|
||||
事件处理器模块
|
||||
处理匹配相关的事件
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import queue
|
||||
from typing import Dict, Any, List, Optional, Callable
|
||||
|
||||
class EventHandler:
|
||||
"""
|
||||
事件处理器
|
||||
处理匹配相关的事件
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化事件处理器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 事件配置
|
||||
self.event_config = {
|
||||
"enable_event_system": True,
|
||||
"max_event_queue_size": 10000,
|
||||
"enable_event_filtering": True,
|
||||
"event_processing_interval": 0.01, # 10ms
|
||||
"enable_async_processing": True,
|
||||
"max_concurrent_events": 100,
|
||||
"enable_event_prioritization": True
|
||||
}
|
||||
|
||||
# 事件状态
|
||||
self.event_state = {
|
||||
"is_processing": False,
|
||||
"pending_events": 0,
|
||||
"processed_events": 0,
|
||||
"dropped_events": 0,
|
||||
"last_event_time": 0.0
|
||||
}
|
||||
|
||||
# 事件队列
|
||||
self.event_queue = queue.Queue(maxsize=self.event_config["max_event_queue_size"])
|
||||
|
||||
# 事件处理器存储
|
||||
self.event_handlers = {}
|
||||
|
||||
# 事件统计
|
||||
self.event_stats = {
|
||||
"events_received": 0,
|
||||
"events_processed": 0,
|
||||
"events_dropped": 0,
|
||||
"handler_errors": 0,
|
||||
"async_events": 0
|
||||
}
|
||||
|
||||
# 事件过滤器
|
||||
self.event_filters = {}
|
||||
|
||||
# 回调函数
|
||||
self.event_callbacks = {
|
||||
"event_received": [],
|
||||
"event_processed": [],
|
||||
"event_dropped": [],
|
||||
"event_error": []
|
||||
}
|
||||
|
||||
# 事件处理线程
|
||||
self.event_thread = None
|
||||
self.event_thread_running = False
|
||||
|
||||
# 时间戳记录
|
||||
self.last_event_process = 0.0
|
||||
self.last_stats_reset = 0.0
|
||||
|
||||
print("✓ 事件处理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化事件处理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化事件处理器...")
|
||||
|
||||
# 注册默认事件处理器
|
||||
self._register_default_handlers()
|
||||
|
||||
# 启动事件处理线程
|
||||
self._start_event_thread()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 事件处理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器初始化失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _register_default_handlers(self):
|
||||
"""注册默认事件处理器"""
|
||||
try:
|
||||
# 注册系统事件处理器
|
||||
self.register_event_handler("player_queued", self._handle_player_queued)
|
||||
self.register_event_handler("player_dequeued", self._handle_player_dequeued)
|
||||
self.register_event_handler("match_found", self._handle_match_found)
|
||||
self.register_event_handler("match_completed", self._handle_match_completed)
|
||||
self.register_event_handler("match_cancelled", self._handle_match_cancelled)
|
||||
self.register_event_handler("queue_timeout", self._handle_queue_timeout)
|
||||
|
||||
print("✓ 默认事件处理器已注册")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 默认事件处理器注册失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _start_event_thread(self):
|
||||
"""启动事件处理线程"""
|
||||
try:
|
||||
self.event_thread_running = True
|
||||
self.event_thread = threading.Thread(target=self._event_loop, daemon=True)
|
||||
self.event_thread.start()
|
||||
print("✓ 事件处理线程已启动")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理线程启动失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _event_loop(self):
|
||||
"""事件处理循环"""
|
||||
try:
|
||||
while self.event_thread_running:
|
||||
try:
|
||||
if self.enabled and self.event_config["enable_event_system"]:
|
||||
# 处理事件队列
|
||||
self._process_event_queue()
|
||||
|
||||
# 短暂休眠
|
||||
time.sleep(self.event_config["event_processing_interval"])
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理循环错误: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
time.sleep(1.0) # 出错时延长休眠
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理线程失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用事件处理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 事件处理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 事件处理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器启用失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用事件处理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 停止事件处理线程
|
||||
if self.event_thread_running:
|
||||
self.event_thread_running = False
|
||||
if self.event_thread and self.event_thread.is_alive():
|
||||
self.event_thread.join(timeout=5.0)
|
||||
|
||||
print("✓ 事件处理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器禁用失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理事件处理器资源"""
|
||||
try:
|
||||
# 禁用事件处理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调和处理器
|
||||
self.event_callbacks.clear()
|
||||
self.event_handlers.clear()
|
||||
self.event_filters.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 事件处理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新事件处理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
self.event_state["last_event_time"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器更新失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _process_event_queue(self):
|
||||
"""处理事件队列"""
|
||||
try:
|
||||
processed_count = 0
|
||||
max_process_per_loop = 100 # 每次循环最多处理100个事件
|
||||
|
||||
while not self.event_queue.empty() and processed_count < max_process_per_loop:
|
||||
try:
|
||||
# 从队列获取事件
|
||||
event_data = self.event_queue.get_nowait()
|
||||
|
||||
# 处理事件
|
||||
self._handle_event_internal(event_data)
|
||||
|
||||
processed_count += 1
|
||||
self.event_stats["events_processed"] += 1
|
||||
|
||||
except queue.Empty:
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"✗ 事件队列处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
self.event_state["pending_events"] = self.event_queue.qsize()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件队列处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_event_internal(self, event_data: Dict[str, Any]):
|
||||
"""
|
||||
内部事件处理
|
||||
|
||||
Args:
|
||||
event_data: 事件数据
|
||||
"""
|
||||
try:
|
||||
event_type = event_data.get("type")
|
||||
event_payload = event_data.get("payload", {})
|
||||
event_priority = event_data.get("priority", 0)
|
||||
event_timestamp = event_data.get("timestamp", time.time())
|
||||
|
||||
# 应用事件过滤器
|
||||
if self.event_config["enable_event_filtering"]:
|
||||
if not self._apply_event_filters(event_type, event_payload):
|
||||
# 事件被过滤掉
|
||||
return
|
||||
|
||||
# 查找事件处理器
|
||||
if event_type in self.event_handlers:
|
||||
handlers = self.event_handlers[event_type]
|
||||
|
||||
# 按优先级排序处理器
|
||||
if self.event_config["enable_event_prioritization"]:
|
||||
handlers = sorted(handlers, key=lambda x: x.get("priority", 0), reverse=True)
|
||||
|
||||
# 调用所有处理器
|
||||
for handler_info in handlers:
|
||||
try:
|
||||
handler_func = handler_info["function"]
|
||||
handler_result = handler_func(event_payload)
|
||||
|
||||
# 检查是否需要停止传播
|
||||
if handler_result is False:
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器执行失败: {event_type} - {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
# 触发事件处理回调
|
||||
self._trigger_event_callback("event_processed", {
|
||||
"event_type": event_type,
|
||||
"event_payload": event_payload,
|
||||
"processing_time": time.time() - event_timestamp,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 内部事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _apply_event_filters(self, event_type: str, event_payload: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
应用事件过滤器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
event_payload: 事件载荷
|
||||
|
||||
Returns:
|
||||
是否通过过滤器
|
||||
"""
|
||||
try:
|
||||
if event_type in self.event_filters:
|
||||
filters = self.event_filters[event_type]
|
||||
for filter_func in filters:
|
||||
if not filter_func(event_payload):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件过滤器应用失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
return True
|
||||
|
||||
def emit_event(self, event_type: str, event_payload: Dict[str, Any] = None,
|
||||
priority: int = 0, async_process: bool = None) -> bool:
|
||||
"""
|
||||
发出事件
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
event_payload: 事件载荷
|
||||
priority: 事件优先级
|
||||
async_process: 是否异步处理
|
||||
|
||||
Returns:
|
||||
是否发出成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled or not self.event_config["enable_event_system"]:
|
||||
return False
|
||||
|
||||
# 使用默认异步处理设置或指定设置
|
||||
if async_process is None:
|
||||
async_process = self.event_config["enable_async_processing"]
|
||||
|
||||
event_data = {
|
||||
"type": event_type,
|
||||
"payload": event_payload or {},
|
||||
"priority": priority,
|
||||
"timestamp": time.time(),
|
||||
"async": async_process
|
||||
}
|
||||
|
||||
# 触发事件接收回调
|
||||
self._trigger_event_callback("event_received", {
|
||||
"event_type": event_type,
|
||||
"event_payload": event_payload,
|
||||
"priority": priority,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 更新统计
|
||||
self.event_stats["events_received"] += 1
|
||||
|
||||
if async_process:
|
||||
# 异步处理:添加到队列
|
||||
try:
|
||||
self.event_queue.put_nowait(event_data)
|
||||
self.event_stats["async_events"] += 1
|
||||
return True
|
||||
except queue.Full:
|
||||
# 队列已满,丢弃事件
|
||||
self.event_stats["events_dropped"] += 1
|
||||
self.event_state["dropped_events"] += 1
|
||||
|
||||
# 触发事件丢弃回调
|
||||
self._trigger_event_callback("event_dropped", {
|
||||
"event_type": event_type,
|
||||
"event_payload": event_payload,
|
||||
"reason": "queue_full",
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return False
|
||||
else:
|
||||
# 同步处理:立即处理
|
||||
self._handle_event_internal(event_data)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件发出失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
return False
|
||||
|
||||
def register_event_handler(self, event_type: str, handler: Callable, priority: int = 0):
|
||||
"""
|
||||
注册事件处理器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
handler: 处理器函数
|
||||
priority: 处理器优先级
|
||||
"""
|
||||
try:
|
||||
if event_type not in self.event_handlers:
|
||||
self.event_handlers[event_type] = []
|
||||
|
||||
handler_info = {
|
||||
"function": handler,
|
||||
"priority": priority
|
||||
}
|
||||
|
||||
self.event_handlers[event_type].append(handler_info)
|
||||
print(f"✓ 事件处理器已注册: {event_type} (优先级: {priority})")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器注册失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def unregister_event_handler(self, event_type: str, handler: Callable):
|
||||
"""
|
||||
注销事件处理器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
handler: 处理器函数
|
||||
"""
|
||||
try:
|
||||
if event_type in self.event_handlers:
|
||||
handlers = self.event_handlers[event_type]
|
||||
for i, handler_info in enumerate(handlers):
|
||||
if handler_info["function"] == handler:
|
||||
del handlers[i]
|
||||
print(f"✓ 事件处理器已注销: {event_type}")
|
||||
return
|
||||
|
||||
print(f"✗ 事件处理器不存在: {event_type}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器注销失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def register_event_filter(self, event_type: str, filter_func: Callable):
|
||||
"""
|
||||
注册事件过滤器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
filter_func: 过滤器函数
|
||||
"""
|
||||
try:
|
||||
if event_type not in self.event_filters:
|
||||
self.event_filters[event_type] = []
|
||||
|
||||
self.event_filters[event_type].append(filter_func)
|
||||
print(f"✓ 事件过滤器已注册: {event_type}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件过滤器注册失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def unregister_event_filter(self, event_type: str, filter_func: Callable):
|
||||
"""
|
||||
注销事件过滤器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
filter_func: 过滤器函数
|
||||
"""
|
||||
try:
|
||||
if event_type in self.event_filters:
|
||||
filters = self.event_filters[event_type]
|
||||
if filter_func in filters:
|
||||
filters.remove(filter_func)
|
||||
print(f"✓ 事件过滤器已注销: {event_type}")
|
||||
return
|
||||
|
||||
print(f"✗ 事件过滤器不存在: {event_type}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件过滤器注销失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
# 默认事件处理器
|
||||
def _handle_player_queued(self, payload: Dict[str, Any]):
|
||||
"""处理玩家排队事件"""
|
||||
try:
|
||||
player_ids = payload.get("player_ids", [])
|
||||
queue_name = payload.get("queue_name", "default")
|
||||
|
||||
print(f".players queued: {len(player_ids)} players in queue '{queue_name}'")
|
||||
|
||||
# 可以在这里添加额外的处理逻辑
|
||||
# 例如:记录排队时间、更新统计等
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家排队事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_player_dequeued(self, payload: Dict[str, Any]):
|
||||
"""处理玩家离队事件"""
|
||||
try:
|
||||
player_ids = payload.get("player_ids", [])
|
||||
match_id = payload.get("match_id")
|
||||
|
||||
print(f".players dequeued: {len(player_ids)} players")
|
||||
|
||||
# 可以在这里添加额外的处理逻辑
|
||||
# 例如:更新统计、清理资源等
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家离队事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_match_found(self, payload: Dict[str, Any]):
|
||||
"""处理匹配找到事件"""
|
||||
try:
|
||||
match_id = payload.get("match_id")
|
||||
room_id = payload.get("room_id")
|
||||
player_ids = payload.get("player_ids", [])
|
||||
queue_name = payload.get("queue_name", "default")
|
||||
|
||||
print(f"🎉 Match found: {match_id} with {len(player_ids)} players in queue '{queue_name}' -> Room: {room_id}")
|
||||
|
||||
# 记录匹配队列时间
|
||||
if self.plugin.monitor:
|
||||
queue_time = time.time() - payload.get("timestamp", time.time())
|
||||
self.plugin.monitor.record_match_queue_time(queue_time)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配找到事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_match_completed(self, payload: Dict[str, Any]):
|
||||
"""处理匹配完成事件"""
|
||||
try:
|
||||
match_id = payload.get("match_id")
|
||||
room_id = payload.get("room_id")
|
||||
|
||||
print(f"✅ Match completed: {match_id} -> Room: {room_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配完成事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_match_cancelled(self, payload: Dict[str, Any]):
|
||||
"""处理匹配取消事件"""
|
||||
try:
|
||||
match_id = payload.get("match_id")
|
||||
|
||||
print(f"❌ Match cancelled: {match_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配取消事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_queue_timeout(self, payload: Dict[str, Any]):
|
||||
"""处理队列超时事件"""
|
||||
try:
|
||||
player_id = payload.get("player_id")
|
||||
|
||||
print(f"⏰ Queue timeout for player: {player_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列超时事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def get_event_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取事件统计信息
|
||||
|
||||
Returns:
|
||||
事件统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.event_state.copy(),
|
||||
"stats": self.event_stats.copy(),
|
||||
"config": self.event_config.copy(),
|
||||
"pending_events": self.event_queue.qsize()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置事件统计信息"""
|
||||
try:
|
||||
self.event_stats = {
|
||||
"events_received": 0,
|
||||
"events_processed": 0,
|
||||
"events_dropped": 0,
|
||||
"handler_errors": 0,
|
||||
"async_events": 0
|
||||
}
|
||||
print("✓ 事件统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件统计信息重置失败: {e}")
|
||||
|
||||
def set_event_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置事件配置
|
||||
|
||||
Args:
|
||||
config: 事件配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.event_config.update(config)
|
||||
print(f"✓ 事件配置已更新: {self.event_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 事件配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_event_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取事件配置
|
||||
|
||||
Returns:
|
||||
事件配置字典
|
||||
"""
|
||||
return self.event_config.copy()
|
||||
|
||||
def _trigger_event_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发事件回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.event_callbacks:
|
||||
for callback in self.event_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 事件回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件回调触发失败: {e}")
|
||||
|
||||
def register_event_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册事件回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.event_callbacks:
|
||||
self.event_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 事件回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件回调注册失败: {e}")
|
||||
|
||||
def unregister_event_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销事件回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.event_callbacks:
|
||||
if callback in self.event_callbacks[callback_type]:
|
||||
self.event_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 事件回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件回调注销失败: {e}")
|
||||
600
plugins/user/matchmaking_system/monitoring/match_monitor.py
Normal file
600
plugins/user/matchmaking_system/monitoring/match_monitor.py
Normal file
@ -0,0 +1,600 @@
|
||||
"""
|
||||
匹配监控系统模块
|
||||
监控匹配过程和性能
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict, Any, List, Optional
|
||||
from collections import deque
|
||||
|
||||
class MatchMonitor:
|
||||
"""
|
||||
匹配监控器
|
||||
监控匹配过程和性能
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化匹配监控器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 监控配置
|
||||
self.monitor_config = {
|
||||
"enable_monitoring": True,
|
||||
"monitoring_interval": 5.0,
|
||||
"log_level": "INFO",
|
||||
"enable_performance_monitoring": True,
|
||||
"enable_alerts": True,
|
||||
"alert_thresholds": {
|
||||
"match_queue_time": 60.0,
|
||||
"match_failure_rate": 10.0,
|
||||
"system_latency": 100.0
|
||||
},
|
||||
"enable_metrics_collection": True,
|
||||
"metrics_retention_period": 3600 # 1小时
|
||||
}
|
||||
|
||||
# 性能指标存储
|
||||
self.performance_metrics = {
|
||||
"match_queue_times": deque(maxlen=1000),
|
||||
"match_success_rates": deque(maxlen=1000),
|
||||
"system_latencies": deque(maxlen=1000),
|
||||
"player_wait_times": deque(maxlen=1000),
|
||||
"algorithm_performance": deque(maxlen=1000)
|
||||
}
|
||||
|
||||
# 监控状态
|
||||
self.monitor_state = {
|
||||
"last_monitoring_update": 0.0,
|
||||
"last_performance_check": 0.0,
|
||||
"total_monitored_matches": 0,
|
||||
"active_alerts": 0
|
||||
}
|
||||
|
||||
# 警报系统
|
||||
self.active_alerts = {}
|
||||
self.alert_history = deque(maxlen=1000)
|
||||
|
||||
# 监控统计
|
||||
self.monitor_stats = {
|
||||
"metrics_collected": 0,
|
||||
"alerts_generated": 0,
|
||||
"alerts_resolved": 0,
|
||||
"performance_checks": 0,
|
||||
"monitor_errors": 0
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.monitor_callbacks = {
|
||||
"metric_collected": [],
|
||||
"alert_triggered": [],
|
||||
"alert_resolved": [],
|
||||
"performance_degraded": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_metric_collection = 0.0
|
||||
self.last_alert_check = 0.0
|
||||
|
||||
print("✓ 匹配监控器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化匹配监控器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化匹配监控器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 匹配监控器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配监控器初始化失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用匹配监控器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 匹配监控器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 匹配监控器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配监控器启用失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用匹配监控器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
print("✓ 匹配监控器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配监控器禁用失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理匹配监控器资源"""
|
||||
try:
|
||||
# 禁用匹配监控器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.monitor_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 匹配监控器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配监控器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新匹配监控器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
self.monitor_state["last_monitoring_update"] = current_time
|
||||
|
||||
# 定期收集性能指标
|
||||
if current_time - self.last_metric_collection >= self.monitor_config["monitoring_interval"]:
|
||||
self._collect_performance_metrics()
|
||||
self.last_metric_collection = current_time
|
||||
|
||||
# 定期检查警报
|
||||
if current_time - self.last_alert_check >= self.monitor_config["monitoring_interval"]:
|
||||
self._check_alerts()
|
||||
self.last_alert_check = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配监控器更新失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _collect_performance_metrics(self):
|
||||
"""收集性能指标"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
metrics = {}
|
||||
|
||||
# 收集匹配管理器指标
|
||||
if self.plugin.match_manager:
|
||||
match_stats = self.plugin.match_manager.get_match_stats()
|
||||
match_state = match_stats.get("state", {})
|
||||
|
||||
metrics["active_matches"] = match_state.get("active_matches", 0)
|
||||
metrics["successful_matches"] = match_state.get("successful_matches", 0)
|
||||
metrics["failed_matches"] = match_state.get("failed_matches", 0)
|
||||
|
||||
# 计算成功率
|
||||
total_matches = metrics["successful_matches"] + metrics["failed_matches"]
|
||||
if total_matches > 0:
|
||||
success_rate = (metrics["successful_matches"] / total_matches) * 100
|
||||
metrics["match_success_rate"] = success_rate
|
||||
self.performance_metrics["match_success_rates"].append((current_time, success_rate))
|
||||
|
||||
# 收集队列管理器指标
|
||||
if self.plugin.queue_manager:
|
||||
queue_stats = self.plugin.queue_manager.get_queue_stats()
|
||||
queue_state = queue_stats.get("state", {})
|
||||
|
||||
metrics["total_players"] = queue_state.get("total_players", 0)
|
||||
metrics["players_matched"] = queue_state.get("players_matched", 0)
|
||||
metrics["players_timed_out"] = queue_state.get("players_timed_out", 0)
|
||||
|
||||
# 计算超时率
|
||||
total_players = metrics["players_matched"] + metrics["players_timed_out"]
|
||||
if total_players > 0:
|
||||
timeout_rate = (metrics["players_timed_out"] / total_players) * 100
|
||||
metrics["queue_timeout_rate"] = timeout_rate
|
||||
|
||||
# 收集算法管理器指标
|
||||
if self.plugin.algorithm_manager:
|
||||
algorithm_stats = self.plugin.algorithm_manager.get_algorithm_stats()
|
||||
algorithm_state = algorithm_stats.get("state", {})
|
||||
|
||||
metrics["total_algorithms"] = algorithm_state.get("total_matches", 0)
|
||||
metrics["successful_algorithms"] = algorithm_state.get("successful_matches", 0)
|
||||
metrics["average_match_quality"] = algorithm_state.get("average_match_quality", 0)
|
||||
|
||||
self.performance_metrics["algorithm_performance"].append(
|
||||
(current_time, metrics["average_match_quality"])
|
||||
)
|
||||
|
||||
# 收集房间分配器指标
|
||||
if self.plugin.room_allocator:
|
||||
room_stats = self.plugin.room_allocator.get_room_stats()
|
||||
room_state = room_stats.get("state", {})
|
||||
|
||||
metrics["active_rooms"] = room_state.get("active_rooms", 0)
|
||||
metrics["total_rooms"] = room_state.get("total_rooms", 0)
|
||||
|
||||
# 更新统计
|
||||
self.monitor_stats["metrics_collected"] += 1
|
||||
self.monitor_state["total_monitored_matches"] += 1
|
||||
|
||||
# 触发指标收集回调
|
||||
self._trigger_monitor_callback("metric_collected", {
|
||||
"metrics": metrics,
|
||||
"timestamp": current_time
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 性能指标收集失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _check_alerts(self):
|
||||
"""检查警报条件"""
|
||||
try:
|
||||
if not self.monitor_config["enable_alerts"]:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
thresholds = self.monitor_config["alert_thresholds"]
|
||||
|
||||
# 检查匹配队列时间
|
||||
if self.performance_metrics["match_queue_times"]:
|
||||
latest_queue_time = self.performance_metrics["match_queue_times"][-1][1]
|
||||
if latest_queue_time > thresholds["match_queue_time"]:
|
||||
self._trigger_alert("high_queue_time", f"匹配队列时间过长: {latest_queue_time:.2f}秒", current_time)
|
||||
|
||||
# 检查匹配失败率
|
||||
if self.performance_metrics["match_success_rates"]:
|
||||
latest_success_rate = self.performance_metrics["match_success_rates"][-1][1]
|
||||
failure_rate = 100 - latest_success_rate
|
||||
if failure_rate > thresholds["match_failure_rate"]:
|
||||
self._trigger_alert("high_failure_rate", f"匹配失败率过高: {failure_rate:.2f}%", current_time)
|
||||
|
||||
# 检查系统延迟
|
||||
if self.performance_metrics["system_latencies"]:
|
||||
latest_latency = self.performance_metrics["system_latencies"][-1][1]
|
||||
if latest_latency > thresholds["system_latency"]:
|
||||
self._trigger_alert("high_latency", f"系统延迟过高: {latest_latency:.2f}ms", current_time)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 警报检查失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _trigger_alert(self, alert_type: str, message: str, timestamp: float = None):
|
||||
"""
|
||||
触发警报
|
||||
|
||||
Args:
|
||||
alert_type: 警报类型
|
||||
message: 警报消息
|
||||
timestamp: 时间戳
|
||||
"""
|
||||
try:
|
||||
if timestamp is None:
|
||||
timestamp = time.time()
|
||||
|
||||
alert_id = f"{alert_type}_{int(timestamp)}"
|
||||
|
||||
# 检查是否已存在相同类型的活动警报
|
||||
if alert_type in self.active_alerts:
|
||||
# 更新现有警报
|
||||
self.active_alerts[alert_type]["count"] += 1
|
||||
self.active_alerts[alert_type]["last_triggered"] = timestamp
|
||||
else:
|
||||
# 创建新警报
|
||||
self.active_alerts[alert_type] = {
|
||||
"id": alert_id,
|
||||
"type": alert_type,
|
||||
"message": message,
|
||||
"first_triggered": timestamp,
|
||||
"last_triggered": timestamp,
|
||||
"count": 1,
|
||||
"resolved": False
|
||||
}
|
||||
|
||||
self.monitor_state["active_alerts"] += 1
|
||||
self.monitor_stats["alerts_generated"] += 1
|
||||
|
||||
# 添加到警报历史
|
||||
self.alert_history.append({
|
||||
"id": alert_id,
|
||||
"type": alert_type,
|
||||
"message": message,
|
||||
"timestamp": timestamp,
|
||||
"resolved": False
|
||||
})
|
||||
|
||||
# 触发警报回调
|
||||
self._trigger_monitor_callback("alert_triggered", {
|
||||
"alert_id": alert_id,
|
||||
"alert_type": alert_type,
|
||||
"message": message,
|
||||
"timestamp": timestamp
|
||||
})
|
||||
|
||||
print(f"⚠️ 警报触发 [{alert_type}]: {message}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 警报触发失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def resolve_alert(self, alert_type: str):
|
||||
"""
|
||||
解决警报
|
||||
|
||||
Args:
|
||||
alert_type: 警报类型
|
||||
"""
|
||||
try:
|
||||
if alert_type in self.active_alerts:
|
||||
alert_data = self.active_alerts[alert_type]
|
||||
alert_data["resolved"] = True
|
||||
alert_data["resolved_time"] = time.time()
|
||||
|
||||
self.monitor_state["active_alerts"] -= 1
|
||||
self.monitor_stats["alerts_resolved"] += 1
|
||||
|
||||
# 触发警报解决回调
|
||||
self._trigger_monitor_callback("alert_resolved", {
|
||||
"alert_type": alert_type,
|
||||
"alert_data": alert_data
|
||||
})
|
||||
|
||||
# 从活动警报中移除
|
||||
del self.active_alerts[alert_type]
|
||||
|
||||
print(f"✅ 警报已解决: {alert_type}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 警报解决失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def record_match_queue_time(self, queue_time: float):
|
||||
"""
|
||||
记录匹配队列时间
|
||||
|
||||
Args:
|
||||
queue_time: 队列时间(秒)
|
||||
"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
self.performance_metrics["match_queue_times"].append((current_time, queue_time))
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配队列时间记录失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def record_player_wait_time(self, wait_time: float):
|
||||
"""
|
||||
记录玩家等待时间
|
||||
|
||||
Args:
|
||||
wait_time: 等待时间(秒)
|
||||
"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
self.performance_metrics["player_wait_times"].append((current_time, wait_time))
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家等待时间记录失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def record_system_latency(self, latency: float):
|
||||
"""
|
||||
记录系统延迟
|
||||
|
||||
Args:
|
||||
latency: 延迟(毫秒)
|
||||
"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
self.performance_metrics["system_latencies"].append((current_time, latency))
|
||||
except Exception as e:
|
||||
print(f"✗ 系统延迟记录失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def get_performance_metrics(self, metric_name: str = None, limit: int = 100) -> Any:
|
||||
"""
|
||||
获取性能指标
|
||||
|
||||
Args:
|
||||
metric_name: 指标名称(可选)
|
||||
limit: 限制返回的数量
|
||||
|
||||
Returns:
|
||||
性能指标数据
|
||||
"""
|
||||
try:
|
||||
if metric_name:
|
||||
if metric_name in self.performance_metrics:
|
||||
metrics = list(self.performance_metrics[metric_name])
|
||||
return metrics[-limit:] if len(metrics) > limit else metrics
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
# 返回所有指标
|
||||
result = {}
|
||||
for name, metrics in self.performance_metrics.items():
|
||||
metric_list = list(metrics)
|
||||
result[name] = metric_list[-limit:] if len(metric_list) > limit else metric_list
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取性能指标失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
return {}
|
||||
|
||||
def get_active_alerts(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取活动警报
|
||||
|
||||
Returns:
|
||||
活动警报字典
|
||||
"""
|
||||
try:
|
||||
return self.active_alerts.copy()
|
||||
except Exception as e:
|
||||
print(f"✗ 获取活动警报失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
return {}
|
||||
|
||||
def get_alert_history(self, limit: int = 100) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取警报历史
|
||||
|
||||
Args:
|
||||
limit: 限制返回的数量
|
||||
|
||||
Returns:
|
||||
警报历史列表
|
||||
"""
|
||||
try:
|
||||
history = list(self.alert_history)
|
||||
return history[-limit:] if len(history) > limit else history
|
||||
except Exception as e:
|
||||
print(f"✗ 获取警报历史失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
return []
|
||||
|
||||
def get_monitor_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取监控统计信息
|
||||
|
||||
Returns:
|
||||
监控统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.monitor_state.copy(),
|
||||
"stats": self.monitor_stats.copy(),
|
||||
"config": self.monitor_config.copy(),
|
||||
"active_alerts_count": len(self.active_alerts),
|
||||
"alert_history_count": len(self.alert_history)
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置监控统计信息"""
|
||||
try:
|
||||
self.monitor_stats = {
|
||||
"metrics_collected": 0,
|
||||
"alerts_generated": 0,
|
||||
"alerts_resolved": 0,
|
||||
"performance_checks": 0,
|
||||
"monitor_errors": 0
|
||||
}
|
||||
|
||||
self.monitor_state["total_monitored_matches"] = 0
|
||||
self.monitor_state["active_alerts"] = 0
|
||||
|
||||
print("✓ 监控统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控统计信息重置失败: {e}")
|
||||
|
||||
def set_monitor_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置监控配置
|
||||
|
||||
Args:
|
||||
config: 监控配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.monitor_config.update(config)
|
||||
print(f"✓ 监控配置已更新: {self.monitor_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 监控配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_monitor_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取监控配置
|
||||
|
||||
Returns:
|
||||
监控配置字典
|
||||
"""
|
||||
return self.monitor_config.copy()
|
||||
|
||||
def _trigger_monitor_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发监控回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.monitor_callbacks:
|
||||
for callback in self.monitor_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 监控回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控回调触发失败: {e}")
|
||||
|
||||
def register_monitor_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册监控回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.monitor_callbacks:
|
||||
self.monitor_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 监控回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控回调注册失败: {e}")
|
||||
|
||||
def unregister_monitor_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销监控回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.monitor_callbacks:
|
||||
if callback in self.monitor_callbacks[callback_type]:
|
||||
self.monitor_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 监控回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控回调注销失败: {e}")
|
||||
225
plugins/user/matchmaking_system/plugin.py
Normal file
225
plugins/user/matchmaking_system/plugin.py
Normal file
@ -0,0 +1,225 @@
|
||||
"""
|
||||
匹配系统插件主文件
|
||||
"""
|
||||
|
||||
class MatchmakingSystemPlugin:
|
||||
"""
|
||||
匹配系统插件
|
||||
为EG引擎提供玩家匹配功能
|
||||
"""
|
||||
|
||||
def __init__(self, engine):
|
||||
"""
|
||||
初始化匹配系统插件
|
||||
|
||||
Args:
|
||||
engine: EG引擎实例
|
||||
"""
|
||||
self.engine = engine
|
||||
self.name = "MatchmakingSystem"
|
||||
self.version = "1.0.0"
|
||||
|
||||
# 插件组件
|
||||
self.match_manager = None
|
||||
self.queue_manager = None
|
||||
self.algorithm_manager = None
|
||||
self.room_allocator = None
|
||||
self.rule_manager = None
|
||||
self.monitor = None
|
||||
self.event_handler = None
|
||||
self.config_manager = None
|
||||
self.editor = None
|
||||
self.stats_manager = None
|
||||
|
||||
print("✓ 匹配系统插件已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化插件
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化匹配系统插件...")
|
||||
|
||||
# 导入模块
|
||||
from .core.match_manager import MatchManager
|
||||
from .queue.queue_manager import QueueManager
|
||||
from .algorithms.algorithm_manager import AlgorithmManager
|
||||
from .rooms.room_allocator import RoomAllocator
|
||||
from .rules.rule_manager import RuleManager
|
||||
from .monitoring.match_monitor import MatchMonitor
|
||||
from .events.event_handler import EventHandler
|
||||
from .config.match_config import MatchConfig
|
||||
from .editor.match_editor import MatchEditor
|
||||
from .stats.stats_manager import StatsManager
|
||||
|
||||
# 创建组件
|
||||
self.config_manager = MatchConfig(self)
|
||||
self.event_handler = EventHandler(self)
|
||||
self.rule_manager = RuleManager(self)
|
||||
self.algorithm_manager = AlgorithmManager(self)
|
||||
self.queue_manager = QueueManager(self)
|
||||
self.room_allocator = RoomAllocator(self)
|
||||
self.match_manager = MatchManager(self)
|
||||
self.monitor = MatchMonitor(self)
|
||||
self.editor = MatchEditor(self)
|
||||
self.stats_manager = StatsManager(self)
|
||||
|
||||
# 初始化组件
|
||||
components = [
|
||||
self.config_manager,
|
||||
self.event_handler,
|
||||
self.rule_manager,
|
||||
self.algorithm_manager,
|
||||
self.queue_manager,
|
||||
self.room_allocator,
|
||||
self.match_manager,
|
||||
self.monitor,
|
||||
self.editor,
|
||||
self.stats_manager
|
||||
]
|
||||
|
||||
for component in components:
|
||||
if hasattr(component, 'initialize') and not component.initialize():
|
||||
print(f"✗ 组件初始化失败: {component.__class__.__name__}")
|
||||
return False
|
||||
|
||||
print("✓ 匹配系统插件初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配系统插件初始化失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用插件
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
print("正在启用匹配系统插件...")
|
||||
|
||||
# 启用组件
|
||||
components = [
|
||||
self.config_manager,
|
||||
self.event_handler,
|
||||
self.rule_manager,
|
||||
self.algorithm_manager,
|
||||
self.queue_manager,
|
||||
self.room_allocator,
|
||||
self.match_manager,
|
||||
self.monitor,
|
||||
self.editor,
|
||||
self.stats_manager
|
||||
]
|
||||
|
||||
for component in components:
|
||||
if hasattr(component, 'enable') and not component.enable():
|
||||
print(f"✗ 组件启用失败: {component.__class__.__name__}")
|
||||
return False
|
||||
|
||||
print("✓ 匹配系统插件已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配系统插件启用失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用插件"""
|
||||
try:
|
||||
print("正在禁用匹配系统插件...")
|
||||
|
||||
# 禁用组件
|
||||
components = [
|
||||
self.stats_manager,
|
||||
self.editor,
|
||||
self.monitor,
|
||||
self.match_manager,
|
||||
self.room_allocator,
|
||||
self.queue_manager,
|
||||
self.algorithm_manager,
|
||||
self.rule_manager,
|
||||
self.event_handler,
|
||||
self.config_manager
|
||||
]
|
||||
|
||||
for component in components:
|
||||
if hasattr(component, 'disable'):
|
||||
component.disable()
|
||||
|
||||
print("✓ 匹配系统插件已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配系统插件禁用失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理插件资源"""
|
||||
try:
|
||||
print("正在清理匹配系统插件资源...")
|
||||
|
||||
# 清理组件
|
||||
components = [
|
||||
self.stats_manager,
|
||||
self.editor,
|
||||
self.monitor,
|
||||
self.match_manager,
|
||||
self.room_allocator,
|
||||
self.queue_manager,
|
||||
self.algorithm_manager,
|
||||
self.rule_manager,
|
||||
self.event_handler,
|
||||
self.config_manager
|
||||
]
|
||||
|
||||
for component in components:
|
||||
if hasattr(component, 'finalize'):
|
||||
component.finalize()
|
||||
|
||||
print("✓ 匹配系统插件资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配系统插件资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新插件状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
# 更新组件
|
||||
components = [
|
||||
self.config_manager,
|
||||
self.event_handler,
|
||||
self.rule_manager,
|
||||
self.algorithm_manager,
|
||||
self.queue_manager,
|
||||
self.room_allocator,
|
||||
self.match_manager,
|
||||
self.monitor,
|
||||
self.editor,
|
||||
self.stats_manager
|
||||
]
|
||||
|
||||
for component in components:
|
||||
if hasattr(component, 'update'):
|
||||
component.update(dt)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配系统插件更新失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
664
plugins/user/matchmaking_system/queue/queue_manager.py
Normal file
664
plugins/user/matchmaking_system/queue/queue_manager.py
Normal file
@ -0,0 +1,664 @@
|
||||
"""
|
||||
队列管理器模块
|
||||
管理等待匹配的玩家队列
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import uuid
|
||||
from typing import Dict, Any, List, Optional
|
||||
from collections import deque
|
||||
|
||||
class QueueManager:
|
||||
"""
|
||||
队列管理器
|
||||
管理等待匹配的玩家队列
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化队列管理器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 队列配置
|
||||
self.queue_config = {
|
||||
"default_queue_timeout": 300.0, # 5分钟
|
||||
"queue_processing_interval": 2.0,
|
||||
"max_players_per_match": 100,
|
||||
"min_players_per_match": 2,
|
||||
"enable_queue_prioritization": True,
|
||||
"enable_skill_based_queue": True,
|
||||
"enable_region_based_queue": True
|
||||
}
|
||||
|
||||
# 队列状态
|
||||
self.queue_state = {
|
||||
"total_players": 0,
|
||||
"active_queues": 0,
|
||||
"players_matched": 0,
|
||||
"players_timed_out": 0
|
||||
}
|
||||
|
||||
# 队列存储
|
||||
self.queues = {} # 按游戏模式分类的队列
|
||||
self.player_queues = {} # 玩家所在的队列映射
|
||||
self.queue_lock = threading.RLock()
|
||||
|
||||
# 队列统计
|
||||
self.queue_stats = {
|
||||
"players_added": 0,
|
||||
"players_removed": 0,
|
||||
"matches_created": 0,
|
||||
"queue_timeouts": 0,
|
||||
"queue_errors": 0
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.queue_callbacks = {
|
||||
"player_queued": [],
|
||||
"player_dequeued": [],
|
||||
"match_found": [],
|
||||
"queue_timeout": [],
|
||||
"queue_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_queue_process = 0.0
|
||||
self.last_cleanup = 0.0
|
||||
|
||||
print("✓ 队列管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化队列管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化队列管理器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 队列管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列管理器初始化失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用队列管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 队列管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 队列管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列管理器启用失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用队列管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 清空所有队列
|
||||
with self.queue_lock:
|
||||
self.queues.clear()
|
||||
self.player_queues.clear()
|
||||
|
||||
print("✓ 队列管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列管理器禁用失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理队列管理器资源"""
|
||||
try:
|
||||
# 禁用队列管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.queue_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 队列管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新队列管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期处理队列
|
||||
if current_time - self.last_queue_process >= self.queue_config["queue_processing_interval"]:
|
||||
self.process_queues()
|
||||
self.last_queue_process = current_time
|
||||
|
||||
# 定期清理
|
||||
if current_time - self.last_cleanup >= 60.0: # 每分钟清理一次
|
||||
self._cleanup_expired_players(current_time)
|
||||
self.last_cleanup = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列管理器更新失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _cleanup_expired_players(self, current_time: float):
|
||||
"""清理过期玩家"""
|
||||
try:
|
||||
expired_players = []
|
||||
with self.queue_lock:
|
||||
for player_id, queue_info in self.player_queues.items():
|
||||
join_time = queue_info["join_time"]
|
||||
timeout = queue_info.get("timeout", self.queue_config["default_queue_timeout"])
|
||||
|
||||
if current_time - join_time > timeout:
|
||||
expired_players.append(player_id)
|
||||
|
||||
# 移除过期玩家
|
||||
for player_id in expired_players:
|
||||
self._remove_player_from_queue(player_id, "timeout")
|
||||
self.queue_stats["queue_timeouts"] += 1
|
||||
|
||||
# 触发队列超时回调
|
||||
self._trigger_queue_callback("queue_timeout", {
|
||||
"player_id": player_id,
|
||||
"timestamp": current_time
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 过期玩家清理失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
|
||||
def add_players_to_queue(self, player_ids: List[str], queue_params: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
添加玩家到队列
|
||||
|
||||
Args:
|
||||
player_ids: 玩家ID列表
|
||||
queue_params: 队列参数
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
queue_name = queue_params.get("queue_name", "default")
|
||||
game_mode = queue_params.get("game_mode", "default")
|
||||
region = queue_params.get("region", "global")
|
||||
skill_level = queue_params.get("skill_level", 0)
|
||||
timeout = queue_params.get("timeout", self.queue_config["default_queue_timeout"])
|
||||
|
||||
with self.queue_lock:
|
||||
# 创建队列(如果不存在)
|
||||
if queue_name not in self.queues:
|
||||
self.queues[queue_name] = {
|
||||
"name": queue_name,
|
||||
"game_mode": game_mode,
|
||||
"region": region,
|
||||
"players": deque(),
|
||||
"created_time": time.time()
|
||||
}
|
||||
self.queue_state["active_queues"] += 1
|
||||
|
||||
# 添加玩家到队列
|
||||
queue = self.queues[queue_name]
|
||||
for player_id in player_ids:
|
||||
player_info = {
|
||||
"player_id": player_id,
|
||||
"skill_level": skill_level,
|
||||
"region": region,
|
||||
"join_time": time.time(),
|
||||
"timeout": timeout,
|
||||
"queue_params": queue_params
|
||||
}
|
||||
|
||||
queue["players"].append(player_info)
|
||||
self.player_queues[player_id] = {
|
||||
"queue_name": queue_name,
|
||||
"join_time": time.time(),
|
||||
"timeout": timeout
|
||||
}
|
||||
|
||||
self.queue_state["total_players"] += len(player_ids)
|
||||
self.queue_stats["players_added"] += len(player_ids)
|
||||
|
||||
# 触发玩家入队回调
|
||||
self._trigger_queue_callback("player_queued", {
|
||||
"player_ids": player_ids,
|
||||
"queue_name": queue_name,
|
||||
"game_mode": game_mode,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ {len(player_ids)}名玩家已添加到队列: {queue_name}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家添加到队列失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_players_from_queue(self, match_id: str = None, player_ids: List[str] = None) -> bool:
|
||||
"""
|
||||
从队列移除玩家
|
||||
|
||||
Args:
|
||||
match_id: 匹配ID(可选)
|
||||
player_ids: 玩家ID列表(可选)
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
removed_count = 0
|
||||
|
||||
if player_ids:
|
||||
# 移除指定玩家
|
||||
for player_id in player_ids:
|
||||
if self._remove_player_from_queue(player_id):
|
||||
removed_count += 1
|
||||
else:
|
||||
# 移除所有玩家(这种情况较少使用)
|
||||
with self.queue_lock:
|
||||
player_ids = list(self.player_queues.keys())
|
||||
for player_id in player_ids:
|
||||
if self._remove_player_from_queue(player_id):
|
||||
removed_count += 1
|
||||
|
||||
self.queue_stats["players_removed"] += removed_count
|
||||
|
||||
# 触发玩家离队回调
|
||||
if player_ids:
|
||||
self._trigger_queue_callback("player_dequeued", {
|
||||
"player_ids": player_ids,
|
||||
"match_id": match_id,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ {removed_count}名玩家已从队列移除")
|
||||
return removed_count > 0
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家从队列移除失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
return False
|
||||
|
||||
def _remove_player_from_queue(self, player_id: str, reason: str = "manual") -> bool:
|
||||
"""
|
||||
从队列移除单个玩家
|
||||
|
||||
Args:
|
||||
player_id: 玩家ID
|
||||
reason: 移除原因
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
with self.queue_lock:
|
||||
if player_id not in self.player_queues:
|
||||
return False
|
||||
|
||||
queue_name = self.player_queues[player_id]["queue_name"]
|
||||
del self.player_queues[player_id]
|
||||
|
||||
# 从队列中移除玩家
|
||||
if queue_name in self.queues:
|
||||
queue = self.queues[queue_name]
|
||||
players = queue["players"]
|
||||
|
||||
# 查找并移除玩家
|
||||
player_found = False
|
||||
for i, player_info in enumerate(list(players)):
|
||||
if player_info["player_id"] == player_id:
|
||||
del players[i]
|
||||
player_found = True
|
||||
break
|
||||
|
||||
# 如果队列为空,移除队列
|
||||
if len(players) == 0:
|
||||
del self.queues[queue_name]
|
||||
self.queue_state["active_queues"] -= 1
|
||||
|
||||
if player_found:
|
||||
self.queue_state["total_players"] -= 1
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家从队列移除失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
return False
|
||||
|
||||
def process_queues(self):
|
||||
"""处理队列(寻找匹配)"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
with self.queue_lock:
|
||||
queue_names = list(self.queues.keys())
|
||||
|
||||
for queue_name in queue_names:
|
||||
self._process_queue(queue_name)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列处理失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
|
||||
def _process_queue(self, queue_name: str):
|
||||
"""
|
||||
处理单个队列
|
||||
|
||||
Args:
|
||||
queue_name: 队列名称
|
||||
"""
|
||||
try:
|
||||
with self.queue_lock:
|
||||
if queue_name not in self.queues:
|
||||
return
|
||||
|
||||
queue = self.queues[queue_name]
|
||||
players = list(queue["players"])
|
||||
|
||||
# 检查是否有足够的玩家进行匹配
|
||||
min_players = self.queue_config["min_players_per_match"]
|
||||
max_players = self.queue_config["max_players_per_match"]
|
||||
|
||||
if len(players) >= min_players:
|
||||
# 确定匹配的玩家数量
|
||||
match_player_count = min(len(players), max_players)
|
||||
|
||||
# 选择玩家(简化实现,实际中可能需要考虑技能匹配等因素)
|
||||
selected_players = players[:match_player_count]
|
||||
|
||||
# 创建匹配
|
||||
if self._create_match(selected_players, queue):
|
||||
# 从队列中移除已匹配的玩家
|
||||
for player_info in selected_players:
|
||||
self._remove_player_from_queue(player_info["player_id"])
|
||||
|
||||
self.queue_state["players_matched"] += len(selected_players)
|
||||
self.queue_stats["matches_created"] += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列处理失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
|
||||
def _create_match(self, players: List[Dict[str, Any]], queue: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
创建匹配
|
||||
|
||||
Args:
|
||||
players: 玩家列表
|
||||
queue: 队列信息
|
||||
|
||||
Returns:
|
||||
是否创建成功
|
||||
"""
|
||||
try:
|
||||
# 生成匹配ID
|
||||
match_id = f"match_{int(time.time() * 1000000)}"
|
||||
|
||||
# 提取玩家ID
|
||||
player_ids = [player["player_id"] for player in players]
|
||||
|
||||
# 创建房间
|
||||
room_id = None
|
||||
if self.plugin.room_allocator:
|
||||
room_settings = {
|
||||
"game_mode": queue["game_mode"],
|
||||
"region": queue["region"],
|
||||
"max_players": len(players)
|
||||
}
|
||||
|
||||
room_id = self.plugin.room_allocator.create_room(
|
||||
room_name=f"Match_{match_id[:8]}",
|
||||
room_settings=room_settings
|
||||
)
|
||||
|
||||
# 添加玩家到房间
|
||||
if room_id and self.plugin.room_allocator:
|
||||
for player_id in player_ids:
|
||||
self.plugin.room_allocator.add_client_to_room(room_id, player_id)
|
||||
|
||||
# 通知匹配管理器匹配完成
|
||||
if self.plugin.match_manager:
|
||||
self.plugin.match_manager.complete_match(match_id, room_id or "")
|
||||
|
||||
# 触发匹配找到回调
|
||||
self._trigger_queue_callback("match_found", {
|
||||
"match_id": match_id,
|
||||
"room_id": room_id,
|
||||
"player_ids": player_ids,
|
||||
"queue_name": queue["name"],
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 匹配已创建: {match_id} ({len(player_ids)}名玩家)")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配创建失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_queue_info(self, queue_name: str = None) -> Dict[str, Any]:
|
||||
"""
|
||||
获取队列信息
|
||||
|
||||
Args:
|
||||
queue_name: 队列名称(可选,如果未指定则返回所有队列信息)
|
||||
|
||||
Returns:
|
||||
队列信息字典
|
||||
"""
|
||||
try:
|
||||
with self.queue_lock:
|
||||
if queue_name:
|
||||
if queue_name in self.queues:
|
||||
queue = self.queues[queue_name]
|
||||
return {
|
||||
"name": queue["name"],
|
||||
"game_mode": queue["game_mode"],
|
||||
"region": queue["region"],
|
||||
"player_count": len(queue["players"]),
|
||||
"created_time": queue["created_time"]
|
||||
}
|
||||
else:
|
||||
return {}
|
||||
else:
|
||||
# 返回所有队列信息
|
||||
queue_info = {}
|
||||
for name, queue in self.queues.items():
|
||||
queue_info[name] = {
|
||||
"name": queue["name"],
|
||||
"game_mode": queue["game_mode"],
|
||||
"region": queue["region"],
|
||||
"player_count": len(queue["players"]),
|
||||
"created_time": queue["created_time"]
|
||||
}
|
||||
return queue_info
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列信息获取失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
return {}
|
||||
|
||||
def get_player_queue_info(self, player_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取玩家队列信息
|
||||
|
||||
Args:
|
||||
player_id: 玩家ID
|
||||
|
||||
Returns:
|
||||
玩家队列信息或None
|
||||
"""
|
||||
try:
|
||||
with self.queue_lock:
|
||||
if player_id in self.player_queues:
|
||||
return self.player_queues[player_id].copy()
|
||||
else:
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家队列信息获取失败: {e}")
|
||||
self.queue_stats["queue_errors"] += 1
|
||||
return None
|
||||
|
||||
def get_queue_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取队列统计信息
|
||||
|
||||
Returns:
|
||||
队列统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.queue_state.copy(),
|
||||
"stats": self.queue_stats.copy(),
|
||||
"config": self.queue_config.copy(),
|
||||
"current_queues": len(self.queues),
|
||||
"current_players": len(self.player_queues)
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置队列统计信息"""
|
||||
try:
|
||||
self.queue_stats = {
|
||||
"players_added": 0,
|
||||
"players_removed": 0,
|
||||
"matches_created": 0,
|
||||
"queue_timeouts": 0,
|
||||
"queue_errors": 0
|
||||
}
|
||||
print("✓ 队列统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 队列统计信息重置失败: {e}")
|
||||
|
||||
def set_queue_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置队列配置
|
||||
|
||||
Args:
|
||||
config: 队列配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.queue_config.update(config)
|
||||
print(f"✓ 队列配置已更新: {self.queue_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 队列配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_queue_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取队列配置
|
||||
|
||||
Returns:
|
||||
队列配置字典
|
||||
"""
|
||||
return self.queue_config.copy()
|
||||
|
||||
def _trigger_queue_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发队列回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.queue_callbacks:
|
||||
for callback in self.queue_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 队列回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 队列回调触发失败: {e}")
|
||||
|
||||
def register_queue_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册队列回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.queue_callbacks:
|
||||
self.queue_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 队列回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 队列回调注册失败: {e}")
|
||||
|
||||
def unregister_queue_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销队列回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.queue_callbacks:
|
||||
if callback in self.queue_callbacks[callback_type]:
|
||||
self.queue_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 队列回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 队列回调注销失败: {e}")
|
||||
752
plugins/user/matchmaking_system/rooms/room_allocator.py
Normal file
752
plugins/user/matchmaking_system/rooms/room_allocator.py
Normal file
@ -0,0 +1,752 @@
|
||||
"""
|
||||
房间分配器模块
|
||||
为匹配成功的玩家创建和分配房间
|
||||
"""
|
||||
|
||||
import time
|
||||
import uuid
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class RoomAllocator:
|
||||
"""
|
||||
房间分配器
|
||||
为匹配成功的玩家创建和分配房间
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化房间分配器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 房间配置
|
||||
self.room_config = {
|
||||
"default_max_players": 8,
|
||||
"enable_room_passwords": True,
|
||||
"enable_room_visibility": True,
|
||||
"room_timeout": 3600, # 1小时无活动房间自动关闭
|
||||
"max_rooms": 1000,
|
||||
"enable_persistent_rooms": False
|
||||
}
|
||||
|
||||
# 房间状态
|
||||
self.room_state = {
|
||||
"total_rooms": 0,
|
||||
"active_rooms": 0,
|
||||
"occupied_rooms": 0,
|
||||
"available_rooms": 0
|
||||
}
|
||||
|
||||
# 房间存储
|
||||
self.rooms = {} # 房间数据
|
||||
self.player_rooms = {} # 玩家所在房间映射
|
||||
|
||||
# 房间统计
|
||||
self.room_stats = {
|
||||
"rooms_created": 0,
|
||||
"rooms_destroyed": 0,
|
||||
"players_added": 0,
|
||||
"players_removed": 0,
|
||||
"room_errors": 0
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.room_callbacks = {
|
||||
"room_created": [],
|
||||
"room_destroyed": [],
|
||||
"player_added": [],
|
||||
"player_removed": [],
|
||||
"room_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_cleanup = 0.0
|
||||
self.last_stats_reset = 0.0
|
||||
|
||||
print("✓ 房间分配器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化房间分配器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化房间分配器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 房间分配器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间分配器初始化失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用房间分配器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 房间分配器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 房间分配器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间分配器启用失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用房间分配器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 销毁所有房间
|
||||
self._destroy_all_rooms()
|
||||
|
||||
print("✓ 房间分配器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间分配器禁用失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理房间分配器资源"""
|
||||
try:
|
||||
# 禁用房间分配器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.room_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 房间分配器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间分配器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新房间分配器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期清理过期房间
|
||||
if current_time - self.last_cleanup >= 300.0: # 每5分钟清理一次
|
||||
self._cleanup_expired_rooms(current_time)
|
||||
self.last_cleanup = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间分配器更新失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _cleanup_expired_rooms(self, current_time: float):
|
||||
"""清理过期房间"""
|
||||
try:
|
||||
expired_rooms = []
|
||||
for room_id, room_data in self.rooms.items():
|
||||
# 检查房间是否超时
|
||||
if current_time - room_data.get("last_activity", 0) > self.room_config["room_timeout"]:
|
||||
# 检查房间是否为空
|
||||
if len(room_data.get("players", {})) == 0:
|
||||
expired_rooms.append(room_id)
|
||||
|
||||
# 销毁过期房间
|
||||
for room_id in expired_rooms:
|
||||
self.destroy_room(room_id)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 过期房间清理失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
|
||||
def _destroy_all_rooms(self):
|
||||
"""销毁所有房间"""
|
||||
try:
|
||||
room_ids = list(self.rooms.keys())
|
||||
for room_id in room_ids:
|
||||
self.destroy_room(room_id)
|
||||
except Exception as e:
|
||||
print(f"✗ 所有房间销毁失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
|
||||
def create_room(self, room_name: str = None, room_settings: Dict[str, Any] = None,
|
||||
room_password: str = None) -> Optional[str]:
|
||||
"""
|
||||
创建房间
|
||||
|
||||
Args:
|
||||
room_name: 房间名称
|
||||
room_settings: 房间设置
|
||||
room_password: 房间密码
|
||||
|
||||
Returns:
|
||||
房间ID或None
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
# 检查房间数量限制
|
||||
if len(self.rooms) >= self.room_config["max_rooms"]:
|
||||
print("✗ 房间数量已达上限")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return None
|
||||
|
||||
# 生成房间ID
|
||||
room_id = f"room_{int(time.time() * 1000000)}"
|
||||
|
||||
# 使用默认设置或传入设置
|
||||
settings = {
|
||||
"max_players": self.room_config["default_max_players"],
|
||||
"is_public": True,
|
||||
"allow_spectators": True
|
||||
}
|
||||
|
||||
if room_settings:
|
||||
settings.update(room_settings)
|
||||
|
||||
# 创建房间数据
|
||||
room_data = {
|
||||
"room_id": room_id,
|
||||
"room_name": room_name or f"房间-{room_id[:8]}",
|
||||
"settings": settings,
|
||||
"password": room_password,
|
||||
"players": {}, # 玩家ID到玩家数据的映射
|
||||
"host_player_id": None,
|
||||
"created_time": time.time(),
|
||||
"last_activity": time.time(),
|
||||
"room_state": {}, # 房间状态数据
|
||||
"custom_data": {} # 自定义房间数据
|
||||
}
|
||||
|
||||
# 添加到房间列表
|
||||
self.rooms[room_id] = room_data
|
||||
|
||||
self.room_state["total_rooms"] += 1
|
||||
self.room_state["active_rooms"] += 1
|
||||
self.room_stats["rooms_created"] += 1
|
||||
|
||||
# 触发房间创建回调
|
||||
self._trigger_room_callback("room_created", {
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"settings": settings,
|
||||
"timestamp": room_data["created_time"]
|
||||
})
|
||||
|
||||
print(f"✓ 房间已创建: {room_id} ({room_data['room_name']})")
|
||||
return room_id
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间创建失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return None
|
||||
|
||||
def destroy_room(self, room_id: str) -> bool:
|
||||
"""
|
||||
销毁房间
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
|
||||
Returns:
|
||||
是否销毁成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 检查房间是否存在
|
||||
if room_id not in self.rooms:
|
||||
print(f"✗ 房间不存在: {room_id}")
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
|
||||
# 通知房间内所有玩家
|
||||
player_ids = list(room_data["players"].keys())
|
||||
for player_id in player_ids:
|
||||
self._notify_player_room_destroyed(player_id, room_id)
|
||||
|
||||
# 移除房间
|
||||
del self.rooms[room_id]
|
||||
|
||||
self.room_state["active_rooms"] -= 1
|
||||
self.room_stats["rooms_destroyed"] += 1
|
||||
|
||||
# 触发房间销毁回调
|
||||
self._trigger_room_callback("room_destroyed", {
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 房间已销毁: {room_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间销毁失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return False
|
||||
|
||||
def _notify_player_room_destroyed(self, player_id: str, room_id: str):
|
||||
"""
|
||||
通知玩家房间被销毁
|
||||
|
||||
Args:
|
||||
player_id: 玩家ID
|
||||
room_id: 房间ID
|
||||
"""
|
||||
try:
|
||||
# 从玩家房间映射中移除
|
||||
if player_id in self.player_rooms:
|
||||
del self.player_rooms[player_id]
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家房间销毁通知失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
|
||||
def add_client_to_room(self, room_id: str, player_id: str, player_data: Dict[str, Any] = None) -> bool:
|
||||
"""
|
||||
添加玩家到房间
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
player_id: 玩家ID
|
||||
player_data: 玩家数据
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 检查房间是否存在
|
||||
if room_id not in self.rooms:
|
||||
print(f"✗ 房间不存在: {room_id}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
|
||||
# 检查房间是否已满
|
||||
if len(room_data["players"]) >= room_data["settings"]["max_players"]:
|
||||
print(f"✗ 房间已满: {room_id}")
|
||||
return False
|
||||
|
||||
# 检查房间密码
|
||||
if room_data["password"] and not self._verify_room_password(room_id, player_data):
|
||||
print(f"✗ 房间密码错误: {room_id}")
|
||||
return False
|
||||
|
||||
# 添加玩家到房间
|
||||
player_info = player_data or {}
|
||||
player_info["join_time"] = time.time()
|
||||
player_info["last_activity"] = time.time()
|
||||
|
||||
room_data["players"][player_id] = player_info
|
||||
room_data["last_activity"] = time.time()
|
||||
|
||||
# 设置房间主机(如果是第一个玩家)
|
||||
if room_data["host_player_id"] is None:
|
||||
room_data["host_player_id"] = player_id
|
||||
|
||||
# 更新玩家房间映射
|
||||
self.player_rooms[player_id] = room_id
|
||||
|
||||
self.room_stats["players_added"] += 1
|
||||
|
||||
# 触发玩家添加回调
|
||||
self._trigger_room_callback("player_added", {
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"player_id": player_id,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 玩家已加入房间: {player_id} -> {room_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家加入房间失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_client_from_room(self, room_id: str, player_id: str) -> bool:
|
||||
"""
|
||||
从房间移除玩家
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
player_id: 玩家ID
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 检查房间是否存在
|
||||
if room_id not in self.rooms:
|
||||
print(f"✗ 房间不存在: {room_id}")
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
|
||||
# 检查玩家是否在房间中
|
||||
if player_id not in room_data["players"]:
|
||||
print(f"✗ 玩家不在房间中: {player_id}")
|
||||
return False
|
||||
|
||||
# 移除玩家
|
||||
del room_data["players"][player_id]
|
||||
room_data["last_activity"] = time.time()
|
||||
|
||||
# 更新主机(如果移除的是主机)
|
||||
if room_data["host_player_id"] == player_id:
|
||||
if room_data["players"]:
|
||||
# 选择第一个玩家作为新主机
|
||||
room_data["host_player_id"] = next(iter(room_data["players"]))
|
||||
else:
|
||||
room_data["host_player_id"] = None
|
||||
|
||||
# 移除玩家房间映射
|
||||
if player_id in self.player_rooms:
|
||||
del self.player_rooms[player_id]
|
||||
|
||||
self.room_stats["players_removed"] += 1
|
||||
|
||||
# 触发玩家移除回调
|
||||
self._trigger_room_callback("player_removed", {
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"player_id": player_id,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 如果房间为空,销毁房间
|
||||
if len(room_data["players"]) == 0:
|
||||
self.destroy_room(room_id)
|
||||
|
||||
print(f"✓ 玩家已离开房间: {player_id} <- {room_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 玩家离开房间失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return False
|
||||
|
||||
def _verify_room_password(self, room_id: str, player_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
验证房间密码
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
player_data: 玩家数据
|
||||
|
||||
Returns:
|
||||
密码是否正确
|
||||
"""
|
||||
try:
|
||||
if not self.room_config["enable_room_passwords"]:
|
||||
return True
|
||||
|
||||
if room_id not in self.rooms:
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
if not room_data["password"]:
|
||||
return True
|
||||
|
||||
player_password = player_data.get("password") if player_data else None
|
||||
return player_password == room_data["password"]
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间密码验证失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_room_info(self, room_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取房间信息
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
|
||||
Returns:
|
||||
房间信息或None
|
||||
"""
|
||||
try:
|
||||
if room_id in self.rooms:
|
||||
room_data = self.rooms[room_id]
|
||||
# 返回不包含敏感信息的房间信息
|
||||
safe_room_data = {
|
||||
"room_id": room_data["room_id"],
|
||||
"room_name": room_data["room_name"],
|
||||
"settings": room_data["settings"],
|
||||
"player_count": len(room_data["players"]),
|
||||
"has_password": bool(room_data["password"]),
|
||||
"host_player_id": room_data["host_player_id"],
|
||||
"created_time": room_data["created_time"],
|
||||
"last_activity": room_data["last_activity"]
|
||||
}
|
||||
return safe_room_data
|
||||
else:
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取房间信息失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return None
|
||||
|
||||
def get_player_room(self, player_id: str) -> Optional[str]:
|
||||
"""
|
||||
获取玩家所在房间
|
||||
|
||||
Args:
|
||||
player_id: 玩家ID
|
||||
|
||||
Returns:
|
||||
房间ID或None
|
||||
"""
|
||||
try:
|
||||
return self.player_rooms.get(player_id)
|
||||
except Exception as e:
|
||||
print(f"✗ 获取玩家房间失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return None
|
||||
|
||||
def get_room_players(self, room_id: str) -> List[str]:
|
||||
"""
|
||||
获取房间内所有玩家
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
|
||||
Returns:
|
||||
玩家ID列表
|
||||
"""
|
||||
try:
|
||||
if room_id in self.rooms:
|
||||
return list(self.rooms[room_id]["players"].keys())
|
||||
else:
|
||||
return []
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取房间玩家失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return []
|
||||
|
||||
def update_room_state(self, room_id: str, state_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
更新房间状态
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
state_data: 状态数据
|
||||
|
||||
Returns:
|
||||
是否更新成功
|
||||
"""
|
||||
try:
|
||||
if room_id not in self.rooms:
|
||||
return False
|
||||
|
||||
self.rooms[room_id]["room_state"].update(state_data)
|
||||
self.rooms[room_id]["last_activity"] = time.time()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 更新房间状态失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return False
|
||||
|
||||
def set_room_custom_data(self, room_id: str, key: str, value: Any) -> bool:
|
||||
"""
|
||||
设置房间自定义数据
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
key: 数据键
|
||||
value: 数据值
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
if room_id not in self.rooms:
|
||||
return False
|
||||
|
||||
self.rooms[room_id]["custom_data"][key] = value
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 设置房间自定义数据失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_room_custom_data(self, room_id: str, key: str, default: Any = None) -> Any:
|
||||
"""
|
||||
获取房间自定义数据
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
key: 数据键
|
||||
default: 默认值
|
||||
|
||||
Returns:
|
||||
数据值或默认值
|
||||
"""
|
||||
try:
|
||||
if room_id not in self.rooms:
|
||||
return default
|
||||
|
||||
return self.rooms[room_id]["custom_data"].get(key, default)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取房间自定义数据失败: {e}")
|
||||
self.room_stats["room_errors"] += 1
|
||||
return default
|
||||
|
||||
def get_room_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取房间统计信息
|
||||
|
||||
Returns:
|
||||
房间统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.room_state.copy(),
|
||||
"stats": self.room_stats.copy(),
|
||||
"config": self.room_config.copy(),
|
||||
"current_rooms": len(self.rooms),
|
||||
"current_players": len(self.player_rooms)
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置房间统计信息"""
|
||||
try:
|
||||
self.room_stats = {
|
||||
"rooms_created": 0,
|
||||
"rooms_destroyed": 0,
|
||||
"players_added": 0,
|
||||
"players_removed": 0,
|
||||
"room_errors": 0
|
||||
}
|
||||
print("✓ 房间统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 房间统计信息重置失败: {e}")
|
||||
|
||||
def set_room_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置房间配置
|
||||
|
||||
Args:
|
||||
config: 房间配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.room_config.update(config)
|
||||
print(f"✓ 房间配置已更新: {self.room_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 房间配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_room_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取房间配置
|
||||
|
||||
Returns:
|
||||
房间配置字典
|
||||
"""
|
||||
return self.room_config.copy()
|
||||
|
||||
def _trigger_room_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发房间回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.room_callbacks:
|
||||
for callback in self.room_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 房间回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 房间回调触发失败: {e}")
|
||||
|
||||
def register_room_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册房间回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.room_callbacks:
|
||||
self.room_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 房间回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 房间回调注册失败: {e}")
|
||||
|
||||
def unregister_room_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销房间回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.room_callbacks:
|
||||
if callback in self.room_callbacks[callback_type]:
|
||||
self.room_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 房间回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 房间回调注销失败: {e}")
|
||||
633
plugins/user/matchmaking_system/rules/rule_manager.py
Normal file
633
plugins/user/matchmaking_system/rules/rule_manager.py
Normal file
@ -0,0 +1,633 @@
|
||||
"""
|
||||
匹配规则管理器模块
|
||||
管理匹配规则和参数
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class RuleManager:
|
||||
"""
|
||||
匹配规则管理器
|
||||
管理匹配规则和参数
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化匹配规则管理器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 规则配置
|
||||
self.rule_config = {
|
||||
"default_rules": {
|
||||
"min_players": 2,
|
||||
"max_players": 8,
|
||||
"skill_range": 100,
|
||||
"max_wait_time": 120.0,
|
||||
"region_matching": True,
|
||||
"platform_matching": True,
|
||||
"language_matching": True
|
||||
},
|
||||
"game_mode_rules": {}, # 不同游戏模式的规则
|
||||
"custom_rules": {}, # 自定义规则
|
||||
"enable_rule_validation": True,
|
||||
"enable_dynamic_rules": True
|
||||
}
|
||||
|
||||
# 规则状态
|
||||
self.rule_state = {
|
||||
"active_rules": "default",
|
||||
"total_rules": 1, # 默认规则
|
||||
"custom_rules_count": 0,
|
||||
"rules_modified": 0
|
||||
}
|
||||
|
||||
# 规则统计
|
||||
self.rule_stats = {
|
||||
"rules_applied": 0,
|
||||
"rules_violated": 0,
|
||||
"rule_errors": 0
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.rule_callbacks = {
|
||||
"rule_applied": [],
|
||||
"rule_violated": [],
|
||||
"rule_updated": [],
|
||||
"rule_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_rule_application = 0.0
|
||||
self.last_stats_reset = 0.0
|
||||
|
||||
print("✓ 匹配规则管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化匹配规则管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化匹配规则管理器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 匹配规则管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配规则管理器初始化失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用匹配规则管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 匹配规则管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 匹配规则管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配规则管理器启用失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用匹配规则管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
print("✓ 匹配规则管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配规则管理器禁用失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理匹配规则管理器资源"""
|
||||
try:
|
||||
# 禁用匹配规则管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.rule_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 匹配规则管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配规则管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新匹配规则管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
self.last_rule_application = time.time()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配规则管理器更新失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def apply_rules(self, players: List[Dict[str, Any]], game_mode: str = "default") -> bool:
|
||||
"""
|
||||
应用匹配规则
|
||||
|
||||
Args:
|
||||
players: 玩家列表
|
||||
game_mode: 游戏模式
|
||||
|
||||
Returns:
|
||||
是否符合规则
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return True # 如果未启用,跳过规则检查
|
||||
|
||||
self.rule_stats["rules_applied"] += 1
|
||||
|
||||
# 获取适用的规则
|
||||
rules = self.get_active_rules(game_mode)
|
||||
|
||||
# 检查玩家数量
|
||||
min_players = rules.get("min_players", 2)
|
||||
max_players = rules.get("max_players", 8)
|
||||
|
||||
if len(players) < min_players:
|
||||
print(f"✗ 玩家数量不足: {len(players)} < {min_players}")
|
||||
self.rule_stats["rules_violated"] += 1
|
||||
|
||||
# 触发规则违反回调
|
||||
self._trigger_rule_callback("rule_violated", {
|
||||
"rule": "min_players",
|
||||
"required": min_players,
|
||||
"actual": len(players),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return False
|
||||
|
||||
if len(players) > max_players:
|
||||
print(f"✗ 玩家数量超限: {len(players)} > {max_players}")
|
||||
self.rule_stats["rules_violated"] += 1
|
||||
|
||||
# 触发规则违反回调
|
||||
self._trigger_rule_callback("rule_violated", {
|
||||
"rule": "max_players",
|
||||
"required": max_players,
|
||||
"actual": len(players),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return False
|
||||
|
||||
# 检查技能范围
|
||||
if rules.get("skill_range") is not None:
|
||||
skill_range = rules["skill_range"]
|
||||
skills = [p.get("skill_level", 0) for p in players]
|
||||
min_skill = min(skills)
|
||||
max_skill = max(skills)
|
||||
|
||||
if max_skill - min_skill > skill_range:
|
||||
print(f"✗ 技能范围超限: {max_skill - min_skill} > {skill_range}")
|
||||
self.rule_stats["rules_violated"] += 1
|
||||
|
||||
# 触发规则违反回调
|
||||
self._trigger_rule_callback("rule_violated", {
|
||||
"rule": "skill_range",
|
||||
"required": skill_range,
|
||||
"actual": max_skill - min_skill,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return False
|
||||
|
||||
# 检查区域匹配
|
||||
if rules.get("region_matching", False):
|
||||
regions = [p.get("region", "global") for p in players]
|
||||
if len(set(regions)) > 1:
|
||||
print(f"✗ 区域不匹配: {set(regions)}")
|
||||
self.rule_stats["rules_violated"] += 1
|
||||
|
||||
# 触发规则违反回调
|
||||
self._trigger_rule_callback("rule_violated", {
|
||||
"rule": "region_matching",
|
||||
"regions": list(set(regions)),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return False
|
||||
|
||||
# 检查平台匹配
|
||||
if rules.get("platform_matching", False):
|
||||
platforms = [p.get("platform", "pc") for p in players]
|
||||
if len(set(platforms)) > 1:
|
||||
print(f"✗ 平台不匹配: {set(platforms)}")
|
||||
self.rule_stats["rules_violated"] += 1
|
||||
|
||||
# 触发规则违反回调
|
||||
self._trigger_rule_callback("rule_violated", {
|
||||
"rule": "platform_matching",
|
||||
"platforms": list(set(platforms)),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return False
|
||||
|
||||
# 检查语言匹配
|
||||
if rules.get("language_matching", False):
|
||||
languages = [p.get("language", "en") for p in players]
|
||||
if len(set(languages)) > 1:
|
||||
print(f"✗ 语言不匹配: {set(languages)}")
|
||||
self.rule_stats["rules_violated"] += 1
|
||||
|
||||
# 触发规则违反回调
|
||||
self._trigger_rule_callback("rule_violated", {
|
||||
"rule": "language_matching",
|
||||
"languages": list(set(languages)),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return False
|
||||
|
||||
# 触发规则应用回调
|
||||
self._trigger_rule_callback("rule_applied", {
|
||||
"players": len(players),
|
||||
"game_mode": game_mode,
|
||||
"rules": rules,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 规则检查通过: {len(players)}名玩家, 游戏模式: {game_mode}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 规则应用失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_active_rules(self, game_mode: str = "default") -> Dict[str, Any]:
|
||||
"""
|
||||
获取活动规则
|
||||
|
||||
Args:
|
||||
game_mode: 游戏模式
|
||||
|
||||
Returns:
|
||||
规则字典
|
||||
"""
|
||||
try:
|
||||
# 检查是否有特定游戏模式的规则
|
||||
if game_mode in self.rule_config["game_mode_rules"]:
|
||||
return self.rule_config["game_mode_rules"][game_mode]
|
||||
|
||||
# 检查是否有自定义规则
|
||||
if self.rule_state["active_rules"] in self.rule_config["custom_rules"]:
|
||||
return self.rule_config["custom_rules"][self.rule_state["active_rules"]]
|
||||
|
||||
# 返回默认规则
|
||||
return self.rule_config["default_rules"]
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取活动规则失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return self.rule_config["default_rules"]
|
||||
|
||||
def set_active_rules(self, rule_set_name: str) -> bool:
|
||||
"""
|
||||
设置活动规则集
|
||||
|
||||
Args:
|
||||
rule_set_name: 规则集名称
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
# 验证规则集存在
|
||||
if (rule_set_name != "default" and
|
||||
rule_set_name not in self.rule_config["custom_rules"] and
|
||||
rule_set_name not in self.rule_config["game_mode_rules"]):
|
||||
print(f"✗ 规则集不存在: {rule_set_name}")
|
||||
return False
|
||||
|
||||
self.rule_state["active_rules"] = rule_set_name
|
||||
|
||||
# 触发规则更新回调
|
||||
self._trigger_rule_callback("rule_updated", {
|
||||
"rule_set": rule_set_name,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 活动规则集已设置为: {rule_set_name}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 活动规则集设置失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
def add_custom_rule_set(self, rule_set_name: str, rules: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
添加自定义规则集
|
||||
|
||||
Args:
|
||||
rule_set_name: 规则集名称
|
||||
rules: 规则字典
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 验证规则
|
||||
if self.rule_config["enable_rule_validation"]:
|
||||
if not self._validate_rules(rules):
|
||||
print(f"✗ 规则验证失败: {rule_set_name}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
self.rule_config["custom_rules"][rule_set_name] = rules
|
||||
self.rule_state["custom_rules_count"] = len(self.rule_config["custom_rules"])
|
||||
self.rule_state["total_rules"] += 1
|
||||
self.rule_state["rules_modified"] += 1
|
||||
|
||||
print(f"✓ 自定义规则集已添加: {rule_set_name}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 自定义规则集添加失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_custom_rule_set(self, rule_set_name: str) -> bool:
|
||||
"""
|
||||
移除自定义规则集
|
||||
|
||||
Args:
|
||||
rule_set_name: 规则集名称
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
if rule_set_name in self.rule_config["custom_rules"]:
|
||||
del self.rule_config["custom_rules"][rule_set_name]
|
||||
self.rule_state["custom_rules_count"] = len(self.rule_config["custom_rules"])
|
||||
self.rule_state["total_rules"] -= 1
|
||||
self.rule_state["rules_modified"] += 1
|
||||
|
||||
# 如果删除的是活动规则集,切换回默认规则
|
||||
if self.rule_state["active_rules"] == rule_set_name:
|
||||
self.rule_state["active_rules"] = "default"
|
||||
|
||||
print(f"✓ 自定义规则集已移除: {rule_set_name}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 自定义规则集不存在: {rule_set_name}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 自定义规则集移除失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
def _validate_rules(self, rules: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
验证规则
|
||||
|
||||
Args:
|
||||
rules: 规则字典
|
||||
|
||||
Returns:
|
||||
是否验证通过
|
||||
"""
|
||||
try:
|
||||
# 检查基本规则参数
|
||||
if "min_players" in rules:
|
||||
if not isinstance(rules["min_players"], int) or rules["min_players"] < 1:
|
||||
return False
|
||||
|
||||
if "max_players" in rules:
|
||||
if not isinstance(rules["max_players"], int) or rules["max_players"] < 1:
|
||||
return False
|
||||
|
||||
if "min_players" in rules and "max_players" in rules:
|
||||
if rules["min_players"] > rules["max_players"]:
|
||||
return False
|
||||
|
||||
if "skill_range" in rules:
|
||||
if not isinstance(rules["skill_range"], (int, float)) or rules["skill_range"] < 0:
|
||||
return False
|
||||
|
||||
if "max_wait_time" in rules:
|
||||
if not isinstance(rules["max_wait_time"], (int, float)) or rules["max_wait_time"] < 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 规则验证失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
def add_game_mode_rules(self, game_mode: str, rules: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
添加游戏模式规则
|
||||
|
||||
Args:
|
||||
game_mode: 游戏模式
|
||||
rules: 规则字典
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 验证规则
|
||||
if self.rule_config["enable_rule_validation"]:
|
||||
if not self._validate_rules(rules):
|
||||
print(f"✗ 游戏模式规则验证失败: {game_mode}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
self.rule_config["game_mode_rules"][game_mode] = rules
|
||||
self.rule_state["total_rules"] += 1
|
||||
self.rule_state["rules_modified"] += 1
|
||||
|
||||
print(f"✓ 游戏模式规则已添加: {game_mode}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 游戏模式规则添加失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_game_mode_rules(self, game_mode: str) -> bool:
|
||||
"""
|
||||
移除游戏模式规则
|
||||
|
||||
Args:
|
||||
game_mode: 游戏模式
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
if game_mode in self.rule_config["game_mode_rules"]:
|
||||
del self.rule_config["game_mode_rules"][game_mode]
|
||||
self.rule_state["total_rules"] -= 1
|
||||
self.rule_state["rules_modified"] += 1
|
||||
|
||||
print(f"✓ 游戏模式规则已移除: {game_mode}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 游戏模式规则不存在: {game_mode}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 游戏模式规则移除失败: {e}")
|
||||
self.rule_stats["rule_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_rule_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取规则统计信息
|
||||
|
||||
Returns:
|
||||
规则统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.rule_state.copy(),
|
||||
"stats": self.rule_stats.copy(),
|
||||
"config": self.rule_config.copy()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置规则统计信息"""
|
||||
try:
|
||||
self.rule_stats = {
|
||||
"rules_applied": 0,
|
||||
"rules_violated": 0,
|
||||
"rule_errors": 0
|
||||
}
|
||||
print("✓ 规则统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 规则统计信息重置失败: {e}")
|
||||
|
||||
def set_rule_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置规则配置
|
||||
|
||||
Args:
|
||||
config: 规则配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.rule_config.update(config)
|
||||
print(f"✓ 规则配置已更新: {self.rule_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 规则配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_rule_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取规则配置
|
||||
|
||||
Returns:
|
||||
规则配置字典
|
||||
"""
|
||||
return self.rule_config.copy()
|
||||
|
||||
def _trigger_rule_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发规则回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.rule_callbacks:
|
||||
for callback in self.rule_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 规则回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 规则回调触发失败: {e}")
|
||||
|
||||
def register_rule_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册规则回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.rule_callbacks:
|
||||
self.rule_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 规则回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 规则回调注册失败: {e}")
|
||||
|
||||
def unregister_rule_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销规则回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.rule_callbacks:
|
||||
if callback in self.rule_callbacks[callback_type]:
|
||||
self.rule_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 规则回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 规则回调注销失败: {e}")
|
||||
657
plugins/user/matchmaking_system/stats/stats_manager.py
Normal file
657
plugins/user/matchmaking_system/stats/stats_manager.py
Normal file
@ -0,0 +1,657 @@
|
||||
"""
|
||||
统计数据管理器模块
|
||||
收集和分析匹配数据
|
||||
"""
|
||||
|
||||
import time
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional
|
||||
from collections import defaultdict, deque
|
||||
|
||||
class StatsManager:
|
||||
"""
|
||||
统计数据管理器
|
||||
收集和分析匹配数据
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化统计数据管理器
|
||||
|
||||
Args:
|
||||
plugin: 匹配系统插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 统计配置
|
||||
self.stats_config = {
|
||||
"enable_statistics": True,
|
||||
"data_retention_period": 86400, # 24小时
|
||||
"max_data_points": 10000,
|
||||
"enable_realtime_stats": True,
|
||||
"stats_collection_interval": 10.0,
|
||||
"enable_export": True,
|
||||
"export_format": "json"
|
||||
}
|
||||
|
||||
# 统计数据存储
|
||||
self.statistics = {
|
||||
"match_times": deque(maxlen=1000),
|
||||
"queue_times": deque(maxlen=1000),
|
||||
"success_rates": deque(maxlen=1000),
|
||||
"player_counts": deque(maxlen=1000),
|
||||
"algorithm_performance": deque(maxlen=1000),
|
||||
"system_performance": deque(maxlen=1000)
|
||||
}
|
||||
|
||||
# 统计状态
|
||||
self.stats_state = {
|
||||
"total_matches": 0,
|
||||
"successful_matches": 0,
|
||||
"failed_matches": 0,
|
||||
"total_players": 0,
|
||||
"matched_players": 0,
|
||||
"last_stats_update": 0.0
|
||||
}
|
||||
|
||||
# 历史统计数据
|
||||
self.historical_stats = {
|
||||
"daily": defaultdict(dict),
|
||||
"weekly": defaultdict(dict),
|
||||
"monthly": defaultdict(dict)
|
||||
}
|
||||
|
||||
# 统计报告
|
||||
self.stat_reports = {
|
||||
"last_report": None,
|
||||
"report_cache": {}
|
||||
}
|
||||
|
||||
# 统计回调
|
||||
self.stats_callbacks = {
|
||||
"stats_updated": [],
|
||||
"report_generated": [],
|
||||
"data_exported": [],
|
||||
"stats_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_stats_collection = 0.0
|
||||
self.last_report_generation = 0.0
|
||||
|
||||
print("✓ 统计数据管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化统计数据管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化统计数据管理器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 统计数据管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 统计数据管理器初始化失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用统计数据管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 统计数据管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 统计数据管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 统计数据管理器启用失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用统计数据管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
print("✓ 统计数据管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 统计数据管理器禁用失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理统计数据管理器资源"""
|
||||
try:
|
||||
# 禁用统计数据管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.stats_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 统计数据管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 统计数据管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新统计数据管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期收集统计数据
|
||||
if current_time - self.last_stats_collection >= self.stats_config["stats_collection_interval"]:
|
||||
self._collect_statistics()
|
||||
self.last_stats_collection = current_time
|
||||
|
||||
self.stats_state["last_stats_update"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 统计数据管理器更新失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _collect_statistics(self):
|
||||
"""收集统计数据"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
stats_data = {}
|
||||
|
||||
# 收集匹配管理器统计数据
|
||||
if self.plugin.match_manager:
|
||||
match_stats = self.plugin.match_manager.get_match_stats()
|
||||
match_state = match_stats.get("state", {})
|
||||
|
||||
stats_data["active_matches"] = match_state.get("active_matches", 0)
|
||||
stats_data["successful_matches"] = match_state.get("successful_matches", 0)
|
||||
stats_data["failed_matches"] = match_state.get("failed_matches", 0)
|
||||
|
||||
# 更新总计数
|
||||
self.stats_state["total_matches"] = (
|
||||
match_state.get("successful_matches", 0) +
|
||||
match_state.get("failed_matches", 0)
|
||||
)
|
||||
self.stats_state["successful_matches"] = match_state.get("successful_matches", 0)
|
||||
self.stats_state["failed_matches"] = match_state.get("failed_matches", 0)
|
||||
|
||||
# 收集队列管理器统计数据
|
||||
if self.plugin.queue_manager:
|
||||
queue_stats = self.plugin.queue_manager.get_queue_stats()
|
||||
queue_state = queue_stats.get("state", {})
|
||||
|
||||
stats_data["total_players"] = queue_state.get("total_players", 0)
|
||||
stats_data["players_matched"] = queue_state.get("players_matched", 0)
|
||||
stats_data["players_timed_out"] = queue_state.get("players_timed_out", 0)
|
||||
|
||||
# 更新总计数
|
||||
self.stats_state["total_players"] = queue_state.get("total_players", 0)
|
||||
self.stats_state["matched_players"] = queue_state.get("players_matched", 0)
|
||||
|
||||
# 收集算法管理器统计数据
|
||||
if self.plugin.algorithm_manager:
|
||||
algorithm_stats = self.plugin.algorithm_manager.get_algorithm_stats()
|
||||
algorithm_state = algorithm_stats.get("state", {})
|
||||
|
||||
stats_data["total_algorithms"] = algorithm_state.get("total_matches", 0)
|
||||
stats_data["successful_algorithms"] = algorithm_state.get("successful_matches", 0)
|
||||
stats_data["average_match_quality"] = algorithm_state.get("average_match_quality", 0)
|
||||
|
||||
# 记录算法性能
|
||||
self.statistics["algorithm_performance"].append(
|
||||
(current_time, stats_data["average_match_quality"])
|
||||
)
|
||||
|
||||
# 收集房间分配器统计数据
|
||||
if self.plugin.room_allocator:
|
||||
room_stats = self.plugin.room_allocator.get_room_stats()
|
||||
room_state = room_stats.get("state", {})
|
||||
|
||||
stats_data["active_rooms"] = room_state.get("active_rooms", 0)
|
||||
stats_data["total_rooms"] = room_state.get("total_rooms", 0)
|
||||
|
||||
# 记录统计数据
|
||||
self.statistics["player_counts"].append((current_time, stats_data.get("total_players", 0)))
|
||||
|
||||
# 触发统计更新回调
|
||||
self._trigger_stats_callback("stats_updated", {
|
||||
"stats_data": stats_data,
|
||||
"timestamp": current_time
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 统计数据收集失败: {e}")
|
||||
self._trigger_stats_callback("stats_error", {
|
||||
"error": str(e),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
def record_match_time(self, match_time: float):
|
||||
"""
|
||||
记录匹配时间
|
||||
|
||||
Args:
|
||||
match_time: 匹配时间(秒)
|
||||
"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
self.statistics["match_times"].append((current_time, match_time))
|
||||
except Exception as e:
|
||||
print(f"✗ 匹配时间记录失败: {e}")
|
||||
|
||||
def record_queue_time(self, queue_time: float):
|
||||
"""
|
||||
记录队列时间
|
||||
|
||||
Args:
|
||||
queue_time: 队列时间(秒)
|
||||
"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
self.statistics["queue_times"].append((current_time, queue_time))
|
||||
except Exception as e:
|
||||
print(f"✗ 队列时间记录失败: {e}")
|
||||
|
||||
def record_success_rate(self, success_rate: float):
|
||||
"""
|
||||
记录成功率
|
||||
|
||||
Args:
|
||||
success_rate: 成功率(百分比)
|
||||
"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
self.statistics["success_rates"].append((current_time, success_rate))
|
||||
except Exception as e:
|
||||
print(f"✗ 成功率记录失败: {e}")
|
||||
|
||||
def get_realtime_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取实时统计数据
|
||||
|
||||
Returns:
|
||||
实时统计数据字典
|
||||
"""
|
||||
try:
|
||||
realtime_stats = {
|
||||
"current_time": time.time(),
|
||||
"state": self.stats_state.copy(),
|
||||
"statistics": {}
|
||||
}
|
||||
|
||||
# 获取最新的统计数据
|
||||
for stat_name, stat_data in self.statistics.items():
|
||||
if stat_data:
|
||||
realtime_stats["statistics"][stat_name] = list(stat_data)[-10:] # 最近10个数据点
|
||||
else:
|
||||
realtime_stats["statistics"][stat_name] = []
|
||||
|
||||
return realtime_stats
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 实时统计数据获取失败: {e}")
|
||||
return {}
|
||||
|
||||
def generate_report(self, report_type: str = "summary", time_range: str = "24h") -> Dict[str, Any]:
|
||||
"""
|
||||
生成统计报告
|
||||
|
||||
Args:
|
||||
report_type: 报告类型(summary, detailed, custom)
|
||||
time_range: 时间范围(24h, 7d, 30d)
|
||||
|
||||
Returns:
|
||||
统计报告字典
|
||||
"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
report = {
|
||||
"report_type": report_type,
|
||||
"time_range": time_range,
|
||||
"generated_time": current_time,
|
||||
"data": {}
|
||||
}
|
||||
|
||||
# 根据报告类型生成不同内容
|
||||
if report_type == "summary":
|
||||
report["data"] = self._generate_summary_report()
|
||||
elif report_type == "detailed":
|
||||
report["data"] = self._generate_detailed_report()
|
||||
else:
|
||||
report["data"] = self._generate_custom_report(report_type)
|
||||
|
||||
self.stat_reports["last_report"] = report
|
||||
self.stat_reports["report_cache"][f"{report_type}_{time_range}"] = report
|
||||
|
||||
# 触发报告生成回调
|
||||
self._trigger_stats_callback("report_generated", {
|
||||
"report": report,
|
||||
"timestamp": current_time
|
||||
})
|
||||
|
||||
return report
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 统计报告生成失败: {e}")
|
||||
self._trigger_stats_callback("stats_error", {
|
||||
"error": str(e),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
return {}
|
||||
|
||||
def _generate_summary_report(self) -> Dict[str, Any]:
|
||||
"""生成摘要报告"""
|
||||
try:
|
||||
summary = {
|
||||
"total_matches": self.stats_state["total_matches"],
|
||||
"successful_matches": self.stats_state["successful_matches"],
|
||||
"failed_matches": self.stats_state["failed_matches"],
|
||||
"match_success_rate": 0.0,
|
||||
"total_players": self.stats_state["total_players"],
|
||||
"matched_players": self.stats_state["matched_players"],
|
||||
"player_match_rate": 0.0,
|
||||
"average_match_time": 0.0,
|
||||
"average_queue_time": 0.0
|
||||
}
|
||||
|
||||
# 计算成功率
|
||||
if self.stats_state["total_matches"] > 0:
|
||||
summary["match_success_rate"] = (
|
||||
self.stats_state["successful_matches"] / self.stats_state["total_matches"]
|
||||
) * 100
|
||||
|
||||
# 计算玩家匹配率
|
||||
if self.stats_state["total_players"] > 0:
|
||||
summary["player_match_rate"] = (
|
||||
self.stats_state["matched_players"] / self.stats_state["total_players"]
|
||||
) * 100
|
||||
|
||||
# 计算平均匹配时间
|
||||
if self.statistics["match_times"]:
|
||||
times = [t[1] for t in self.statistics["match_times"]]
|
||||
summary["average_match_time"] = sum(times) / len(times)
|
||||
|
||||
# 计算平均队列时间
|
||||
if self.statistics["queue_times"]:
|
||||
times = [t[1] for t in self.statistics["queue_times"]]
|
||||
summary["average_queue_time"] = sum(times) / len(times)
|
||||
|
||||
return summary
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 摘要报告生成失败: {e}")
|
||||
return {}
|
||||
|
||||
def _generate_detailed_report(self) -> Dict[str, Any]:
|
||||
"""生成详细报告"""
|
||||
try:
|
||||
detailed = {
|
||||
"summary": self._generate_summary_report(),
|
||||
"trends": self._generate_trend_data(),
|
||||
"performance": self._generate_performance_data(),
|
||||
"historical": self._get_historical_data()
|
||||
}
|
||||
|
||||
return detailed
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 详细报告生成失败: {e}")
|
||||
return {}
|
||||
|
||||
def _generate_custom_report(self, report_type: str) -> Dict[str, Any]:
|
||||
"""生成自定义报告"""
|
||||
try:
|
||||
# 简化实现,返回摘要报告
|
||||
return self._generate_summary_report()
|
||||
except Exception as e:
|
||||
print(f"✗ 自定义报告生成失败: {e}")
|
||||
return {}
|
||||
|
||||
def _generate_trend_data(self) -> Dict[str, Any]:
|
||||
"""生成趋势数据"""
|
||||
try:
|
||||
trends = {}
|
||||
|
||||
# 匹配趋势
|
||||
if self.statistics["match_times"]:
|
||||
recent_matches = list(self.statistics["match_times"])[-100:] # 最近100个数据点
|
||||
trends["match_times"] = [t[1] for t in recent_matches]
|
||||
|
||||
# 成功率趋势
|
||||
if self.statistics["success_rates"]:
|
||||
recent_rates = list(self.statistics["success_rates"])[-100:]
|
||||
trends["success_rates"] = [r[1] for r in recent_rates]
|
||||
|
||||
# 玩家数量趋势
|
||||
if self.statistics["player_counts"]:
|
||||
recent_players = list(self.statistics["player_counts"])[-100:]
|
||||
trends["player_counts"] = [p[1] for p in recent_players]
|
||||
|
||||
return trends
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 趋势数据生成失败: {e}")
|
||||
return {}
|
||||
|
||||
def _generate_performance_data(self) -> Dict[str, Any]:
|
||||
"""生成性能数据"""
|
||||
try:
|
||||
performance = {}
|
||||
|
||||
# 算法性能
|
||||
if self.statistics["algorithm_performance"]:
|
||||
recent_performance = list(self.statistics["algorithm_performance"])[-100:]
|
||||
performance["algorithm_performance"] = [p[1] for p in recent_performance]
|
||||
|
||||
# 系统性能
|
||||
if self.statistics["system_performance"]:
|
||||
recent_system = list(self.statistics["system_performance"])[-100:]
|
||||
performance["system_performance"] = [s[1] for s in recent_system]
|
||||
|
||||
return performance
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 性能数据生成失败: {e}")
|
||||
return {}
|
||||
|
||||
def _get_historical_data(self) -> Dict[str, Any]:
|
||||
"""获取历史数据"""
|
||||
try:
|
||||
return {
|
||||
"daily": dict(self.historical_stats["daily"]),
|
||||
"weekly": dict(self.historical_stats["weekly"]),
|
||||
"monthly": dict(self.historical_stats["monthly"])
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"✗ 历史数据获取失败: {e}")
|
||||
return {}
|
||||
|
||||
def export_stats(self, file_path: str, format: str = "json") -> bool:
|
||||
"""
|
||||
导出统计数据
|
||||
|
||||
Args:
|
||||
file_path: 导出文件路径
|
||||
format: 导出格式(json, csv)
|
||||
|
||||
Returns:
|
||||
是否导出成功
|
||||
"""
|
||||
try:
|
||||
import os
|
||||
|
||||
# 创建导出目录
|
||||
export_dir = os.path.dirname(file_path)
|
||||
if not os.path.exists(export_dir):
|
||||
os.makedirs(export_dir)
|
||||
|
||||
# 生成统计数据
|
||||
stats_data = {
|
||||
"statistics": self.get_realtime_stats(),
|
||||
"reports": self.stat_reports,
|
||||
"config": self.stats_config
|
||||
}
|
||||
|
||||
if format.lower() == "json":
|
||||
# 导出为JSON格式
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(stats_data, f, indent=2, ensure_ascii=False, default=str)
|
||||
else:
|
||||
# 默认导出为JSON格式
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(stats_data, f, indent=2, ensure_ascii=False, default=str)
|
||||
|
||||
# 触发数据导出回调
|
||||
self._trigger_stats_callback("data_exported", {
|
||||
"file_path": file_path,
|
||||
"format": format,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 统计数据已导出到: {file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 统计数据导出失败: {e}")
|
||||
self._trigger_stats_callback("stats_error", {
|
||||
"error": str(e),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
return False
|
||||
|
||||
def get_stats_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取统计配置
|
||||
|
||||
Returns:
|
||||
统计配置字典
|
||||
"""
|
||||
return self.stats_config.copy()
|
||||
|
||||
def set_stats_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置统计配置
|
||||
|
||||
Args:
|
||||
config: 统计配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.stats_config.update(config)
|
||||
print(f"✓ 统计配置已更新: {self.stats_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 统计配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_stats_state(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取统计状态
|
||||
|
||||
Returns:
|
||||
统计状态字典
|
||||
"""
|
||||
return self.stats_state.copy()
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置统计数据"""
|
||||
try:
|
||||
# 重置统计数据
|
||||
for stat_name in self.statistics:
|
||||
self.statistics[stat_name].clear()
|
||||
|
||||
# 重置状态
|
||||
self.stats_state = {
|
||||
"total_matches": 0,
|
||||
"successful_matches": 0,
|
||||
"failed_matches": 0,
|
||||
"total_players": 0,
|
||||
"matched_players": 0,
|
||||
"last_stats_update": 0.0
|
||||
}
|
||||
|
||||
print("✓ 统计数据已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 统计数据重置失败: {e}")
|
||||
|
||||
def _trigger_stats_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发统计回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.stats_callbacks:
|
||||
for callback in self.stats_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 统计回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 统计回调触发失败: {e}")
|
||||
|
||||
def register_stats_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册统计回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.stats_callbacks:
|
||||
self.stats_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 统计回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 统计回调注册失败: {e}")
|
||||
|
||||
def unregister_stats_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销统计回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.stats_callbacks:
|
||||
if callback in self.stats_callbacks[callback_type]:
|
||||
self.stats_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 统计回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 统计回调注销失败: {e}")
|
||||
331
plugins/user/realtime_communication/README.md
Normal file
331
plugins/user/realtime_communication/README.md
Normal file
@ -0,0 +1,331 @@
|
||||
# 实时通信插件
|
||||
|
||||
为EG引擎提供完整的实时通信功能,支持WebSocket双向通信、客户端管理、消息路由、房间系统等功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. WebSocket服务器
|
||||
- 实时双向通信支持
|
||||
- SSL/TLS加密连接
|
||||
- 心跳检测和连接管理
|
||||
- 消息压缩和优化
|
||||
|
||||
### 2. 客户端管理
|
||||
- 客户端连接和断开管理
|
||||
- 认证和授权系统
|
||||
- 黑名单和速率限制
|
||||
- 客户端状态跟踪
|
||||
|
||||
### 3. 消息路由
|
||||
- 智能消息分发
|
||||
- 房间内消息广播
|
||||
- 点对点消息传递
|
||||
- 消息过滤和验证
|
||||
|
||||
### 4. 房间系统
|
||||
- 动态房间创建和销毁
|
||||
- 房间密码保护
|
||||
- 客户端加入/离开管理
|
||||
- 房间状态同步
|
||||
|
||||
### 5. 协议处理
|
||||
- 多协议支持(JSON、二进制等)
|
||||
- 消息压缩和解压缩
|
||||
- 数据序列化和反序列化
|
||||
- 消息分片和重组
|
||||
|
||||
### 6. 安全认证
|
||||
- Token认证机制
|
||||
- 密码哈希和验证
|
||||
- 会话管理
|
||||
- IP过滤和阻止
|
||||
|
||||
### 7. 监控系统
|
||||
- 实时性能监控
|
||||
- 日志记录和分析
|
||||
- 警报系统
|
||||
- 指标收集和展示
|
||||
|
||||
### 8. 配置管理
|
||||
- 灵活的配置系统
|
||||
- 实时配置更新
|
||||
- 配置导入导出
|
||||
- 默认配置模板
|
||||
|
||||
### 9. 事件系统
|
||||
- 事件驱动架构
|
||||
- 异步事件处理
|
||||
- 事件过滤和优先级
|
||||
- 事件监听器系统
|
||||
|
||||
### 10. 可视化编辑器
|
||||
- 实时数据监控
|
||||
- 配置界面
|
||||
- 统计信息展示
|
||||
- 数据导出功能
|
||||
|
||||
## 系统架构
|
||||
|
||||
```
|
||||
实时通信插件
|
||||
├── 核心模块
|
||||
│ └── WebSocket服务器 (core/websocket_server.py)
|
||||
├── 客户端管理
|
||||
│ └── 客户端管理器 (clients/client_manager.py)
|
||||
├── 消息处理
|
||||
│ ├── 消息路由器 (messaging/message_router.py)
|
||||
│ ├── 协议处理器 (protocol/protocol_handler.py)
|
||||
│ └── 数据序列化器 (serialization/data_serializer.py)
|
||||
├── 房间系统
|
||||
│ └── 房间管理器 (rooms/room_manager.py)
|
||||
├── 安全系统
|
||||
│ └── 认证管理器 (auth/auth_manager.py)
|
||||
├── 监控系统
|
||||
│ └── 通信监控器 (monitoring/communication_monitor.py)
|
||||
├── 配置管理
|
||||
│ └── 通信配置器 (config/comm_config.py)
|
||||
├── 事件系统
|
||||
│ └── 事件处理器 (events/event_handler.py)
|
||||
├── 编辑器接口
|
||||
│ └── 通信编辑器 (editor/comm_editor.py)
|
||||
└── 工具模块
|
||||
└── 通信工具类 (utils/comm_utils.py)
|
||||
```
|
||||
|
||||
## 安装和使用
|
||||
|
||||
### 安装依赖
|
||||
|
||||
```bash
|
||||
# 安装必要的Python包
|
||||
pip install psutil
|
||||
```
|
||||
|
||||
### 配置插件
|
||||
|
||||
插件配置文件位于 `config/communication_config.json`,包含以下主要配置项:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"enable_ssl": false
|
||||
},
|
||||
"client": {
|
||||
"max_clients": 1000,
|
||||
"enable_authentication": true
|
||||
},
|
||||
"message": {
|
||||
"max_message_size": 65536,
|
||||
"enable_message_compression": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 启动插件
|
||||
|
||||
```python
|
||||
# 初始化插件
|
||||
plugin = RealtimeCommunicationPlugin(engine)
|
||||
plugin.initialize()
|
||||
plugin.enable()
|
||||
|
||||
# 启动WebSocket服务器
|
||||
plugin.websocket_server.start_server()
|
||||
|
||||
# 插件会自动处理客户端连接、消息路由等操作
|
||||
```
|
||||
|
||||
## API参考
|
||||
|
||||
### WebSocket服务器
|
||||
|
||||
```python
|
||||
# 发送消息到客户端
|
||||
plugin.websocket_server.send_message_to_client(client_id, message)
|
||||
|
||||
# 广播消息
|
||||
plugin.websocket_server.broadcast_message(message)
|
||||
|
||||
# 断开客户端连接
|
||||
plugin.websocket_server.disconnect_client(client_id, reason)
|
||||
```
|
||||
|
||||
### 客户端管理
|
||||
|
||||
```python
|
||||
# 添加客户端
|
||||
plugin.client_manager.add_client(client_id, client_info)
|
||||
|
||||
# 认证客户端
|
||||
plugin.client_manager.authenticate_client(client_id, auth_data)
|
||||
|
||||
# 禁止客户端
|
||||
plugin.client_manager.ban_client(client_id, reason)
|
||||
```
|
||||
|
||||
### 消息路由
|
||||
|
||||
```python
|
||||
# 路由消息
|
||||
plugin.message_router.route_message(client_id, message)
|
||||
|
||||
# 发送直接消息
|
||||
plugin.message_router.send_direct_message(from_client_id, to_client_id, message)
|
||||
|
||||
# 房间广播
|
||||
plugin.message_router.broadcast_to_room(room_id, message)
|
||||
```
|
||||
|
||||
### 房间管理
|
||||
|
||||
```python
|
||||
# 创建房间
|
||||
room_id = plugin.room_manager.create_room(room_name, settings)
|
||||
|
||||
# 添加客户端到房间
|
||||
plugin.room_manager.add_client_to_room(room_id, client_id)
|
||||
|
||||
# 从房间移除客户端
|
||||
plugin.room_manager.remove_client_from_room(room_id, client_id)
|
||||
|
||||
# 销毁房间
|
||||
plugin.room_manager.destroy_room(room_id)
|
||||
```
|
||||
|
||||
## 消息格式
|
||||
|
||||
### 系统消息
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "ping",
|
||||
"timestamp": 1234567890.123
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "pong",
|
||||
"timestamp": 1234567890.123,
|
||||
"ping_timestamp": 1234567890.120
|
||||
}
|
||||
```
|
||||
|
||||
### 聊天消息
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "chat",
|
||||
"content": "Hello, world!",
|
||||
"sender": "user123"
|
||||
}
|
||||
```
|
||||
|
||||
### 房间消息
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "join_room",
|
||||
"room_id": "room123"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "leave_room",
|
||||
"room_id": "room123"
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
1. **连接管理**:使用连接池和复用机制减少资源消耗
|
||||
2. **消息压缩**:对大数据消息进行自动压缩
|
||||
3. **异步处理**:采用多线程和异步I/O提高并发性能
|
||||
4. **缓存机制**:对频繁访问的数据进行缓存
|
||||
5. **内存优化**:及时清理无用对象和连接
|
||||
|
||||
## 安全特性
|
||||
|
||||
1. **认证机制**:支持Token和密码认证
|
||||
2. **权限控制**:基于角色的访问控制
|
||||
3. **数据加密**:支持SSL/TLS传输加密
|
||||
4. **防攻击**:IP过滤、速率限制、防DDoS
|
||||
5. **审计日志**:完整操作日志记录
|
||||
|
||||
## 监控和调试
|
||||
|
||||
### 实时监控
|
||||
- CPU和内存使用率
|
||||
- 网络流量统计
|
||||
- 连接数和消息数
|
||||
- 错误率和响应时间
|
||||
|
||||
### 日志系统
|
||||
- 详细的操作日志
|
||||
- 错误和异常记录
|
||||
- 性能指标日志
|
||||
- 安全审计日志
|
||||
|
||||
## 扩展开发
|
||||
|
||||
### 添加新的消息类型
|
||||
|
||||
```python
|
||||
# 在消息路由器中注册新的处理器
|
||||
plugin.message_router.register_message_handler("custom_type", custom_handler)
|
||||
|
||||
def custom_handler(client_id, message):
|
||||
# 处理自定义消息
|
||||
pass
|
||||
```
|
||||
|
||||
### 添加新的协议
|
||||
|
||||
```python
|
||||
# 在协议处理器中注册新的协议
|
||||
plugin.protocol_handler.add_protocol_handler("custom", encode_func, decode_func)
|
||||
```
|
||||
|
||||
### 添加事件监听器
|
||||
|
||||
```python
|
||||
# 注册事件监听器
|
||||
plugin.event_handler.register_event_handler("client_connected", on_client_connected)
|
||||
|
||||
def on_client_connected(payload):
|
||||
# 处理客户端连接事件
|
||||
pass
|
||||
```
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **连接失败**:检查端口是否被占用,防火墙设置
|
||||
2. **认证失败**:检查认证配置和凭证
|
||||
3. **性能问题**:检查系统资源使用情况,优化配置
|
||||
4. **消息丢失**:检查网络连接,调整消息队列大小
|
||||
|
||||
### 日志分析
|
||||
|
||||
查看日志文件以诊断问题:
|
||||
```
|
||||
logs/communication_monitor.log
|
||||
```
|
||||
|
||||
## 版本信息
|
||||
|
||||
- 版本:1.0.0
|
||||
- 作者:EG Plugin System
|
||||
- 许可证:MIT
|
||||
|
||||
## 贡献指南
|
||||
|
||||
欢迎提交Issue和Pull Request来改进这个插件。
|
||||
|
||||
## 支持
|
||||
|
||||
如需技术支持,请联系插件维护团队或查看相关文档。
|
||||
900
plugins/user/realtime_communication/auth/auth_manager.py
Normal file
900
plugins/user/realtime_communication/auth/auth_manager.py
Normal file
@ -0,0 +1,900 @@
|
||||
"""
|
||||
认证管理器模块
|
||||
确保通信安全
|
||||
"""
|
||||
|
||||
import time
|
||||
import hashlib
|
||||
import secrets
|
||||
import hmac
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class AuthManager:
|
||||
"""
|
||||
认证管理器
|
||||
确保通信安全
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化认证管理器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 认证配置
|
||||
self.auth_config = {
|
||||
"enable_authentication": True,
|
||||
"auth_timeout": 30.0,
|
||||
"enable_token_auth": True,
|
||||
"enable_password_auth": True,
|
||||
"token_lifetime": 86400, # 24小时
|
||||
"enable_session_management": True,
|
||||
"session_timeout": 3600, # 1小时
|
||||
"enable_two_factor_auth": False,
|
||||
"max_login_attempts": 5,
|
||||
"login_lockout_duration": 900, # 15分钟
|
||||
"enable_ip_filtering": True,
|
||||
"enable_audit_logging": True
|
||||
}
|
||||
|
||||
# 认证状态
|
||||
self.auth_state = {
|
||||
"active_sessions": 0,
|
||||
"total_authentications": 0,
|
||||
"successful_authentications": 0,
|
||||
"failed_authentications": 0
|
||||
}
|
||||
|
||||
# 认证存储
|
||||
self.sessions = {}
|
||||
self.tokens = {}
|
||||
self.login_attempts = {}
|
||||
self.blocked_ips = {}
|
||||
|
||||
# 认证统计
|
||||
self.auth_stats = {
|
||||
"tokens_generated": 0,
|
||||
"sessions_created": 0,
|
||||
"sessions_expired": 0,
|
||||
"users_banned": 0,
|
||||
"auth_errors": 0
|
||||
}
|
||||
|
||||
# 密钥管理
|
||||
self.secret_key = self._generate_secret_key()
|
||||
|
||||
# 回调函数
|
||||
self.auth_callbacks = {
|
||||
"auth_success": [],
|
||||
"auth_failed": [],
|
||||
"session_created": [],
|
||||
"session_expired": [],
|
||||
"user_banned": [],
|
||||
"auth_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_session_cleanup = 0.0
|
||||
self.last_auth_event = 0.0
|
||||
|
||||
print("✓ 认证管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化认证管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化认证管理器...")
|
||||
|
||||
# 生成密钥
|
||||
self.secret_key = self._generate_secret_key()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 认证管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 认证管理器初始化失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _generate_secret_key(self) -> str:
|
||||
"""
|
||||
生成密钥
|
||||
|
||||
Returns:
|
||||
生成的密钥
|
||||
"""
|
||||
try:
|
||||
return secrets.token_hex(32)
|
||||
except Exception as e:
|
||||
print(f"✗ 密钥生成失败: {e}")
|
||||
# 使用默认密钥(仅用于开发环境)
|
||||
return "default_secret_key_for_development_purposes_only"
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用认证管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 认证管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 认证管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 认证管理器启用失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用认证管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 清理会话和令牌
|
||||
self.sessions.clear()
|
||||
self.tokens.clear()
|
||||
|
||||
print("✓ 认证管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 认证管理器禁用失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理认证管理器资源"""
|
||||
try:
|
||||
# 禁用认证管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.auth_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 认证管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 认证管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新认证管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期清理过期会话
|
||||
if current_time - self.last_session_cleanup > 300: # 每5分钟清理一次
|
||||
self._cleanup_expired_sessions(current_time)
|
||||
self.last_session_cleanup = current_time
|
||||
|
||||
# 定期清理登录尝试记录
|
||||
self._cleanup_login_attempts(current_time)
|
||||
|
||||
self.last_auth_event = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 认证管理器更新失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _cleanup_expired_sessions(self, current_time: float):
|
||||
"""清理过期会话"""
|
||||
try:
|
||||
expired_sessions = []
|
||||
for session_id, session_data in self.sessions.items():
|
||||
if current_time - session_data["login_time"] > self.auth_config["session_timeout"]:
|
||||
expired_sessions.append(session_id)
|
||||
|
||||
for session_id in expired_sessions:
|
||||
del self.sessions[session_id]
|
||||
self.auth_state["active_sessions"] -= 1
|
||||
self.auth_stats["sessions_expired"] += 1
|
||||
|
||||
# 触发会话过期回调
|
||||
self._trigger_auth_callback("session_expired", {
|
||||
"session_id": session_id,
|
||||
"timestamp": current_time
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 过期会话清理失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
|
||||
def _cleanup_login_attempts(self, current_time: float):
|
||||
"""清理登录尝试记录"""
|
||||
try:
|
||||
expired_attempts = []
|
||||
for ip_address, attempt_data in self.login_attempts.items():
|
||||
if current_time - attempt_data["last_attempt"] > self.auth_config["login_lockout_duration"]:
|
||||
expired_attempts.append(ip_address)
|
||||
|
||||
for ip_address in expired_attempts:
|
||||
del self.login_attempts[ip_address]
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 登录尝试记录清理失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
|
||||
def authenticate_client(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
认证客户端
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
auth_data: 认证数据
|
||||
|
||||
Returns:
|
||||
是否认证成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled or not self.auth_config["enable_authentication"]:
|
||||
# 如果未启用认证,直接通过
|
||||
return True
|
||||
|
||||
# 检查IP是否被阻止
|
||||
client_ip = auth_data.get("client_ip", "")
|
||||
if self._is_ip_blocked(client_ip):
|
||||
self.auth_stats["failed_authentications"] += 1
|
||||
return False
|
||||
|
||||
# 检查登录尝试次数
|
||||
if self._is_login_blocked(client_ip):
|
||||
self.auth_stats["failed_authentications"] += 1
|
||||
return False
|
||||
|
||||
# 执行认证
|
||||
auth_result = self._perform_authentication(client_id, auth_data)
|
||||
|
||||
if auth_result:
|
||||
self.auth_state["successful_authentications"] += 1
|
||||
self.auth_state["total_authentications"] += 1
|
||||
|
||||
# 触发认证成功回调
|
||||
self._trigger_auth_callback("auth_success", {
|
||||
"client_id": client_id,
|
||||
"auth_data": auth_data,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 记录审计日志
|
||||
if self.auth_config["enable_audit_logging"]:
|
||||
self._log_auth_event("auth_success", client_id, client_ip)
|
||||
|
||||
else:
|
||||
self.auth_state["failed_authentications"] += 1
|
||||
self.auth_state["total_authentications"] += 1
|
||||
|
||||
# 记录失败的登录尝试
|
||||
self._record_failed_login(client_ip)
|
||||
|
||||
# 触发认证失败回调
|
||||
self._trigger_auth_callback("auth_failed", {
|
||||
"client_id": client_id,
|
||||
"auth_data": auth_data,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 记录审计日志
|
||||
if self.auth_config["enable_audit_logging"]:
|
||||
self._log_auth_event("auth_failed", client_id, client_ip)
|
||||
|
||||
return auth_result
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端认证失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _is_ip_blocked(self, client_ip: str) -> bool:
|
||||
"""
|
||||
检查IP是否被阻止
|
||||
|
||||
Args:
|
||||
client_ip: 客户端IP
|
||||
|
||||
Returns:
|
||||
IP是否被阻止
|
||||
"""
|
||||
try:
|
||||
if not self.auth_config["enable_ip_filtering"]:
|
||||
return False
|
||||
|
||||
if client_ip in self.blocked_ips:
|
||||
block_data = self.blocked_ips[client_ip]
|
||||
if time.time() - block_data["block_time"] < block_data["duration"]:
|
||||
return True
|
||||
else:
|
||||
# 阻止时间已过期,移除
|
||||
del self.blocked_ips[client_ip]
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ IP阻止检查失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _is_login_blocked(self, client_ip: str) -> bool:
|
||||
"""
|
||||
检查登录是否被阻止
|
||||
|
||||
Args:
|
||||
client_ip: 客户端IP
|
||||
|
||||
Returns:
|
||||
登录是否被阻止
|
||||
"""
|
||||
try:
|
||||
if client_ip in self.login_attempts:
|
||||
attempts = self.login_attempts[client_ip]
|
||||
if (attempts["count"] >= self.auth_config["max_login_attempts"] and
|
||||
time.time() - attempts["last_attempt"] < self.auth_config["login_lockout_duration"]):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 登录阻止检查失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _record_failed_login(self, client_ip: str):
|
||||
"""
|
||||
记录失败的登录尝试
|
||||
|
||||
Args:
|
||||
client_ip: 客户端IP
|
||||
"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
|
||||
if client_ip not in self.login_attempts:
|
||||
self.login_attempts[client_ip] = {
|
||||
"count": 1,
|
||||
"last_attempt": current_time
|
||||
}
|
||||
else:
|
||||
self.login_attempts[client_ip]["count"] += 1
|
||||
self.login_attempts[client_ip]["last_attempt"] = current_time
|
||||
|
||||
# 如果超过最大尝试次数,阻止IP
|
||||
if (self.login_attempts[client_ip]["count"] >=
|
||||
self.auth_config["max_login_attempts"]):
|
||||
self._block_ip(client_ip, self.auth_config["login_lockout_duration"])
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 失败登录记录失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
|
||||
def _perform_authentication(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
执行认证
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
auth_data: 认证数据
|
||||
|
||||
Returns:
|
||||
是否认证成功
|
||||
"""
|
||||
try:
|
||||
# 检查认证类型
|
||||
auth_type = auth_data.get("auth_type", "token")
|
||||
|
||||
if auth_type == "token":
|
||||
return self._authenticate_with_token(client_id, auth_data)
|
||||
elif auth_type == "password":
|
||||
return self._authenticate_with_password(client_id, auth_data)
|
||||
elif auth_type == "session":
|
||||
return self._authenticate_with_session(client_id, auth_data)
|
||||
else:
|
||||
# 默认认证方式
|
||||
return self._authenticate_with_token(client_id, auth_data)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 认证执行失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _authenticate_with_token(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
使用令牌认证
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
auth_data: 认证数据
|
||||
|
||||
Returns:
|
||||
是否认证成功
|
||||
"""
|
||||
try:
|
||||
token = auth_data.get("token")
|
||||
if not token:
|
||||
return False
|
||||
|
||||
# 验证令牌
|
||||
if token in self.tokens:
|
||||
token_data = self.tokens[token]
|
||||
if time.time() - token_data["created_time"] < self.auth_config["token_lifetime"]:
|
||||
# 令牌有效,创建会话
|
||||
self._create_session(client_id, auth_data)
|
||||
return True
|
||||
else:
|
||||
# 令牌过期,移除
|
||||
del self.tokens[token]
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 令牌认证失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _authenticate_with_password(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
使用密码认证
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
auth_data: 认证数据
|
||||
|
||||
Returns:
|
||||
是否认证成功
|
||||
"""
|
||||
try:
|
||||
username = auth_data.get("username")
|
||||
password = auth_data.get("password")
|
||||
|
||||
if not username or not password:
|
||||
return False
|
||||
|
||||
# 验证密码(简化实现)
|
||||
# 在实际应用中,这里应该连接到用户数据库验证用户名和密码
|
||||
if username == "test_user" and password == "test_password":
|
||||
# 创建会话
|
||||
self._create_session(client_id, auth_data)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 密码认证失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _authenticate_with_session(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
使用会话认证
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
auth_data: 认证数据
|
||||
|
||||
Returns:
|
||||
是否认证成功
|
||||
"""
|
||||
try:
|
||||
session_id = auth_data.get("session_id")
|
||||
if not session_id:
|
||||
return False
|
||||
|
||||
# 检查会话是否存在且有效
|
||||
if session_id in self.sessions:
|
||||
session_data = self.sessions[session_id]
|
||||
if time.time() - session_data["login_time"] < self.auth_config["session_timeout"]:
|
||||
# 更新会话最后活动时间
|
||||
session_data["last_activity"] = time.time()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 会话认证失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _create_session(self, client_id: str, auth_data: Dict[str, Any]):
|
||||
"""
|
||||
创建会话
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
auth_data: 认证数据
|
||||
"""
|
||||
try:
|
||||
session_id = self._generate_session_id()
|
||||
|
||||
session_data = {
|
||||
"client_id": client_id,
|
||||
"login_time": time.time(),
|
||||
"last_activity": time.time(),
|
||||
"user_id": auth_data.get("user_id", ""),
|
||||
"username": auth_data.get("username", ""),
|
||||
"permissions": auth_data.get("permissions", [])
|
||||
}
|
||||
|
||||
self.sessions[session_id] = session_data
|
||||
self.auth_state["active_sessions"] += 1
|
||||
self.auth_stats["sessions_created"] += 1
|
||||
|
||||
# 触发会话创建回调
|
||||
self._trigger_auth_callback("session_created", {
|
||||
"session_id": session_id,
|
||||
"client_id": client_id,
|
||||
"auth_data": auth_data,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 会话创建失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
|
||||
def _generate_session_id(self) -> str:
|
||||
"""
|
||||
生成会话ID
|
||||
|
||||
Returns:
|
||||
生成的会话ID
|
||||
"""
|
||||
try:
|
||||
return secrets.token_urlsafe(32)
|
||||
except Exception as e:
|
||||
print(f"✗ 会话ID生成失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return f"session_{int(time.time() * 1000000)}"
|
||||
|
||||
def generate_token(self, user_id: str, permissions: List[str] = None) -> str:
|
||||
"""
|
||||
生成令牌
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
permissions: 权限列表
|
||||
|
||||
Returns:
|
||||
生成的令牌
|
||||
"""
|
||||
try:
|
||||
token = secrets.token_urlsafe(64)
|
||||
|
||||
self.tokens[token] = {
|
||||
"user_id": user_id,
|
||||
"permissions": permissions or [],
|
||||
"created_time": time.time()
|
||||
}
|
||||
|
||||
self.auth_stats["tokens_generated"] += 1
|
||||
|
||||
return token
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 令牌生成失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return ""
|
||||
|
||||
def validate_token(self, token: str) -> bool:
|
||||
"""
|
||||
验证令牌
|
||||
|
||||
Args:
|
||||
token: 令牌
|
||||
|
||||
Returns:
|
||||
令牌是否有效
|
||||
"""
|
||||
try:
|
||||
if not token:
|
||||
return False
|
||||
|
||||
if token in self.tokens:
|
||||
token_data = self.tokens[token]
|
||||
if time.time() - token_data["created_time"] < self.auth_config["token_lifetime"]:
|
||||
return True
|
||||
else:
|
||||
# 令牌过期,移除
|
||||
del self.tokens[token]
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 令牌验证失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def hash_password(self, password: str, salt: str = None) -> Dict[str, str]:
|
||||
"""
|
||||
哈希密码
|
||||
|
||||
Args:
|
||||
password: 密码
|
||||
salt: 盐值(可选)
|
||||
|
||||
Returns:
|
||||
包含哈希值和盐值的字典
|
||||
"""
|
||||
try:
|
||||
if salt is None:
|
||||
salt = secrets.token_hex(16)
|
||||
|
||||
# 使用PBKDF2哈希密码
|
||||
password_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 100000)
|
||||
return {
|
||||
"hash": password_hash.hex(),
|
||||
"salt": salt
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 密码哈希失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return {}
|
||||
|
||||
def verify_password(self, password: str, password_hash: str, salt: str) -> bool:
|
||||
"""
|
||||
验证密码
|
||||
|
||||
Args:
|
||||
password: 密码
|
||||
password_hash: 密码哈希值
|
||||
salt: 盐值
|
||||
|
||||
Returns:
|
||||
密码是否正确
|
||||
"""
|
||||
try:
|
||||
# 重新哈希密码
|
||||
new_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 100000)
|
||||
return hmac.compare_digest(new_hash.hex(), password_hash)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 密码验证失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _block_ip(self, client_ip: str, duration: float):
|
||||
"""
|
||||
阻止IP地址
|
||||
|
||||
Args:
|
||||
client_ip: 客户端IP
|
||||
duration: 阻止持续时间(秒)
|
||||
"""
|
||||
try:
|
||||
self.blocked_ips[client_ip] = {
|
||||
"block_time": time.time(),
|
||||
"duration": duration
|
||||
}
|
||||
|
||||
# 触发用户禁止回调
|
||||
self._trigger_auth_callback("user_banned", {
|
||||
"ip_address": client_ip,
|
||||
"duration": duration,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 记录审计日志
|
||||
if self.auth_config["enable_audit_logging"]:
|
||||
self._log_auth_event("ip_blocked", None, client_ip)
|
||||
|
||||
print(f"✓ IP地址已被阻止: {client_ip} (持续 {duration} 秒)")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ IP阻止失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
|
||||
def unblock_ip(self, client_ip: str) -> bool:
|
||||
"""
|
||||
解除IP阻止
|
||||
|
||||
Args:
|
||||
client_ip: 客户端IP
|
||||
|
||||
Returns:
|
||||
是否解除成功
|
||||
"""
|
||||
try:
|
||||
if client_ip in self.blocked_ips:
|
||||
del self.blocked_ips[client_ip]
|
||||
print(f"✓ IP地址阻止已解除: {client_ip}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ IP地址未被阻止: {client_ip}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ IP阻止解除失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return False
|
||||
|
||||
def _log_auth_event(self, event_type: str, client_id: str = None, client_ip: str = None):
|
||||
"""
|
||||
记录认证事件
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
client_id: 客户端ID(可选)
|
||||
client_ip: 客户端IP(可选)
|
||||
"""
|
||||
try:
|
||||
if not self.auth_config["enable_audit_logging"]:
|
||||
return
|
||||
|
||||
event = {
|
||||
"event_type": event_type,
|
||||
"client_id": client_id,
|
||||
"client_ip": client_ip,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
# 在实际实现中,这里会将事件记录到日志文件或数据库
|
||||
print(f"[认证日志] {event_type} - 客户端: {client_id}, IP: {client_ip}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 认证事件记录失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
|
||||
def get_active_sessions(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取活跃会话
|
||||
|
||||
Returns:
|
||||
活跃会话字典
|
||||
"""
|
||||
try:
|
||||
return self.sessions.copy()
|
||||
except Exception as e:
|
||||
print(f"✗ 获取活跃会话失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return {}
|
||||
|
||||
def get_blocked_ips(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取被阻止的IP地址
|
||||
|
||||
Returns:
|
||||
被阻止的IP地址字典
|
||||
"""
|
||||
try:
|
||||
return self.blocked_ips.copy()
|
||||
except Exception as e:
|
||||
print(f"✗ 获取被阻止的IP地址失败: {e}")
|
||||
self.auth_stats["auth_errors"] += 1
|
||||
return {}
|
||||
|
||||
def get_auth_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取认证统计信息
|
||||
|
||||
Returns:
|
||||
认证统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.auth_state.copy(),
|
||||
"stats": self.auth_stats.copy(),
|
||||
"config": self.auth_config.copy()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置认证统计信息"""
|
||||
try:
|
||||
self.auth_stats = {
|
||||
"tokens_generated": 0,
|
||||
"sessions_created": 0,
|
||||
"sessions_expired": 0,
|
||||
"users_banned": 0,
|
||||
"auth_errors": 0
|
||||
}
|
||||
print("✓ 认证统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 认证统计信息重置失败: {e}")
|
||||
|
||||
def set_auth_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置认证配置
|
||||
|
||||
Args:
|
||||
config: 认证配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.auth_config.update(config)
|
||||
print(f"✓ 认证配置已更新: {self.auth_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 认证配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_auth_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取认证配置
|
||||
|
||||
Returns:
|
||||
认证配置字典
|
||||
"""
|
||||
return self.auth_config.copy()
|
||||
|
||||
def _trigger_auth_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发认证回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.auth_callbacks:
|
||||
for callback in self.auth_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 认证回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 认证回调触发失败: {e}")
|
||||
|
||||
def register_auth_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册认证回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.auth_callbacks:
|
||||
self.auth_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 认证回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 认证回调注册失败: {e}")
|
||||
|
||||
def unregister_auth_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销认证回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.auth_callbacks:
|
||||
if callback in self.auth_callbacks[callback_type]:
|
||||
self.auth_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 认证回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 认证回调注销失败: {e}")
|
||||
724
plugins/user/realtime_communication/clients/client_manager.py
Normal file
724
plugins/user/realtime_communication/clients/client_manager.py
Normal file
@ -0,0 +1,724 @@
|
||||
"""
|
||||
客户端管理器模块
|
||||
管理客户端连接和状态
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import hashlib
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class ClientManager:
|
||||
"""
|
||||
客户端管理器
|
||||
管理客户端连接和状态
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化客户端管理器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 客户端配置
|
||||
self.client_config = {
|
||||
"enable_authentication": True,
|
||||
"auth_timeout": 30.0,
|
||||
"max_clients": 1000,
|
||||
"enable_heartbeat": True,
|
||||
"heartbeat_interval": 30.0,
|
||||
"enable_rate_limiting": True,
|
||||
"max_messages_per_second": 100,
|
||||
"enable_banning": True,
|
||||
"ban_duration": 3600,
|
||||
"client_timeout": 60.0
|
||||
}
|
||||
|
||||
# 客户端状态
|
||||
self.client_state = {
|
||||
"current_clients": 0,
|
||||
"total_clients": 0,
|
||||
"authenticated_clients": 0,
|
||||
"banned_clients": 0
|
||||
}
|
||||
|
||||
# 客户端存储
|
||||
self.clients = {}
|
||||
self.client_lock = threading.RLock()
|
||||
|
||||
# 客户端统计
|
||||
self.client_stats = {
|
||||
"clients_joined": 0,
|
||||
"clients_left": 0,
|
||||
"authentication_success": 0,
|
||||
"authentication_failed": 0,
|
||||
"messages_sent": 0,
|
||||
"messages_received": 0,
|
||||
"banned_clients": 0,
|
||||
"errors": 0
|
||||
}
|
||||
|
||||
# 黑名单管理
|
||||
self.banned_ips = {}
|
||||
self.banned_users = {}
|
||||
|
||||
# 回调函数
|
||||
self.client_callbacks = {
|
||||
"client_joined": [],
|
||||
"client_left": [],
|
||||
"client_authenticated": [],
|
||||
"client_banned": [],
|
||||
"client_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_heartbeat_check = 0.0
|
||||
self.last_cleanup = 0.0
|
||||
|
||||
print("✓ 客户端管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化客户端管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化客户端管理器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 客户端管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端管理器初始化失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用客户端管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 客户端管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 客户端管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端管理器启用失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用客户端管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 断开所有客户端
|
||||
self._disconnect_all_clients()
|
||||
|
||||
print("✓ 客户端管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端管理器禁用失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理客户端管理器资源"""
|
||||
try:
|
||||
# 禁用客户端管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.client_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 客户端管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新客户端管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期检查心跳
|
||||
if current_time - self.last_heartbeat_check > self.client_config["heartbeat_interval"]:
|
||||
self._check_client_heartbeats(current_time)
|
||||
self.last_heartbeat_check = current_time
|
||||
|
||||
# 定期清理
|
||||
if current_time - self.last_cleanup > 60.0: # 每分钟清理一次
|
||||
self._cleanup_banned_clients(current_time)
|
||||
self.last_cleanup = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端管理器更新失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _check_client_heartbeats(self, current_time: float):
|
||||
"""检查客户端心跳"""
|
||||
try:
|
||||
if not self.client_config["enable_heartbeat"]:
|
||||
return
|
||||
|
||||
clients_to_disconnect = []
|
||||
with self.client_lock:
|
||||
for client_id, client_data in self.clients.items():
|
||||
last_heartbeat = client_data.get("last_heartbeat", client_data["connect_time"])
|
||||
if current_time - last_heartbeat > self.client_config["client_timeout"]:
|
||||
clients_to_disconnect.append(client_id)
|
||||
|
||||
for client_id in clients_to_disconnect:
|
||||
self.disconnect_client(client_id, "timeout")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端心跳检查失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
|
||||
def _cleanup_banned_clients(self, current_time: float):
|
||||
"""清理过期的黑名单客户端"""
|
||||
try:
|
||||
expired_bans = []
|
||||
for ip, ban_data in self.banned_ips.items():
|
||||
if current_time - ban_data["ban_time"] > self.client_config["ban_duration"]:
|
||||
expired_bans.append(ip)
|
||||
|
||||
for ip in expired_bans:
|
||||
del self.banned_ips[ip]
|
||||
self.client_state["banned_clients"] -= 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 黑名单清理失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
|
||||
def _disconnect_all_clients(self):
|
||||
"""断开所有客户端连接"""
|
||||
try:
|
||||
with self.client_lock:
|
||||
client_ids = list(self.clients.keys())
|
||||
|
||||
for client_id in client_ids:
|
||||
self.disconnect_client(client_id, "server_shutdown")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 断开所有客户端连接失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
|
||||
def add_client(self, client_id: str, client_info: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
添加客户端
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
client_info: 客户端信息
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 检查客户端数量限制
|
||||
with self.client_lock:
|
||||
if len(self.clients) >= self.client_config["max_clients"]:
|
||||
print("✗ 客户端数量已达上限")
|
||||
return False
|
||||
|
||||
# 检查IP是否被禁止
|
||||
client_ip = client_info.get("ip_address", "")
|
||||
if self._is_ip_banned(client_ip):
|
||||
print(f"✗ IP地址被禁止: {client_ip}")
|
||||
return False
|
||||
|
||||
# 添加客户端
|
||||
client_data = {
|
||||
"client_id": client_id,
|
||||
"client_info": client_info,
|
||||
"connect_time": time.time(),
|
||||
"last_heartbeat": time.time(),
|
||||
"is_authenticated": False,
|
||||
"user_id": "",
|
||||
"username": "",
|
||||
"permissions": [],
|
||||
"messages_sent": 0,
|
||||
"messages_received": 0,
|
||||
"bytes_sent": 0,
|
||||
"bytes_received": 0
|
||||
}
|
||||
|
||||
with self.client_lock:
|
||||
self.clients[client_id] = client_data
|
||||
|
||||
self.client_state["current_clients"] = len(self.clients)
|
||||
self.client_state["total_clients"] += 1
|
||||
self.client_stats["clients_joined"] += 1
|
||||
|
||||
# 触发客户端加入回调
|
||||
self._trigger_client_callback("client_joined", {
|
||||
"client_id": client_id,
|
||||
"client_info": client_info,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 客户端已添加: {client_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 添加客户端失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_client(self, client_id: str, reason: str = "unknown") -> bool:
|
||||
"""
|
||||
移除客户端
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
reason: 移除原因
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
with self.client_lock:
|
||||
if client_id in self.clients:
|
||||
client_data = self.clients[client_id]
|
||||
if client_data["is_authenticated"]:
|
||||
self.client_state["authenticated_clients"] -= 1
|
||||
del self.clients[client_id]
|
||||
|
||||
self.client_state["current_clients"] = len(self.clients)
|
||||
self.client_stats["clients_left"] += 1
|
||||
|
||||
# 触发客户端离开回调
|
||||
self._trigger_client_callback("client_left", {
|
||||
"client_id": client_id,
|
||||
"reason": reason,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 客户端已移除: {client_id} (原因: {reason})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 移除客户端失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def disconnect_client(self, client_id: str, reason: str = "kicked") -> bool:
|
||||
"""
|
||||
断开客户端连接
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
reason: 断开原因
|
||||
|
||||
Returns:
|
||||
是否断开成功
|
||||
"""
|
||||
try:
|
||||
# 通知WebSocket服务器断开连接
|
||||
if self.plugin.websocket_server:
|
||||
self.plugin.websocket_server.disconnect_client(client_id, reason)
|
||||
|
||||
# 移除客户端
|
||||
return self.remove_client(client_id, reason)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 断开客户端连接失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def authenticate_client(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
认证客户端
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
auth_data: 认证数据
|
||||
|
||||
Returns:
|
||||
是否认证成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled or not self.client_config["enable_authentication"]:
|
||||
# 如果未启用认证,直接通过
|
||||
with self.client_lock:
|
||||
if client_id in self.clients:
|
||||
self.clients[client_id]["is_authenticated"] = True
|
||||
return True
|
||||
|
||||
# 使用认证管理器进行认证
|
||||
if self.plugin.auth_manager:
|
||||
auth_result = self.plugin.auth_manager.authenticate_client(client_id, auth_data)
|
||||
if auth_result:
|
||||
# 更新客户端认证状态
|
||||
with self.client_lock:
|
||||
if client_id in self.clients:
|
||||
self.clients[client_id]["is_authenticated"] = True
|
||||
self.clients[client_id]["user_id"] = auth_data.get("user_id", "")
|
||||
self.clients[client_id]["username"] = auth_data.get("username", "")
|
||||
self.clients[client_id]["permissions"] = auth_data.get("permissions", [])
|
||||
|
||||
self.client_state["authenticated_clients"] += 1
|
||||
self.client_stats["authentication_success"] += 1
|
||||
|
||||
# 触发客户端认证回调
|
||||
self._trigger_client_callback("client_authenticated", {
|
||||
"client_id": client_id,
|
||||
"user_id": auth_data.get("user_id", ""),
|
||||
"username": auth_data.get("username", ""),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 客户端认证成功: {client_id}")
|
||||
return True
|
||||
else:
|
||||
self.client_stats["authentication_failed"] += 1
|
||||
print(f"✗ 客户端认证失败: {client_id}")
|
||||
return False
|
||||
else:
|
||||
print("✗ 认证管理器不可用")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端认证失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def update_client_heartbeat(self, client_id: str) -> bool:
|
||||
"""
|
||||
更新客户端心跳
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
|
||||
Returns:
|
||||
是否更新成功
|
||||
"""
|
||||
try:
|
||||
with self.client_lock:
|
||||
if client_id in self.clients:
|
||||
self.clients[client_id]["last_heartbeat"] = time.time()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 更新客户端心跳失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def get_client(self, client_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取客户端信息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
|
||||
Returns:
|
||||
客户端信息或None
|
||||
"""
|
||||
try:
|
||||
with self.client_lock:
|
||||
if client_id in self.clients:
|
||||
return self.clients[client_id].copy()
|
||||
else:
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取客户端信息失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return None
|
||||
|
||||
def get_all_clients(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取所有客户端信息
|
||||
|
||||
Returns:
|
||||
所有客户端信息字典
|
||||
"""
|
||||
try:
|
||||
with self.client_lock:
|
||||
return {k: v.copy() for k, v in self.clients.items()}
|
||||
except Exception as e:
|
||||
print(f"✗ 获取所有客户端信息失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return {}
|
||||
|
||||
def ban_client(self, client_id: str, reason: str = "violation", duration: float = 3600) -> bool:
|
||||
"""
|
||||
禁止客户端
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
reason: 禁止原因
|
||||
duration: 禁止时长(秒)
|
||||
|
||||
Returns:
|
||||
是否禁止成功
|
||||
"""
|
||||
try:
|
||||
if not self.client_config["enable_banning"]:
|
||||
return False
|
||||
|
||||
client_data = self.get_client(client_id)
|
||||
if not client_data:
|
||||
return False
|
||||
|
||||
client_ip = client_data["client_info"].get("ip_address", "")
|
||||
if client_ip:
|
||||
# 添加到IP黑名单
|
||||
self.banned_ips[client_ip] = {
|
||||
"client_id": client_id,
|
||||
"ban_time": time.time(),
|
||||
"reason": reason,
|
||||
"duration": duration
|
||||
}
|
||||
|
||||
self.client_state["banned_clients"] += 1
|
||||
self.client_stats["banned_clients"] += 1
|
||||
|
||||
# 断开客户端连接
|
||||
self.disconnect_client(client_id, f"banned: {reason}")
|
||||
|
||||
# 触发客户端禁止回调
|
||||
self._trigger_client_callback("client_banned", {
|
||||
"client_id": client_id,
|
||||
"ip_address": client_ip,
|
||||
"reason": reason,
|
||||
"duration": duration,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 客户端已被禁止: {client_id} (IP: {client_ip})")
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 禁止客户端失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def _is_ip_banned(self, ip_address: str) -> bool:
|
||||
"""
|
||||
检查IP是否被禁止
|
||||
|
||||
Args:
|
||||
ip_address: IP地址
|
||||
|
||||
Returns:
|
||||
IP是否被禁止
|
||||
"""
|
||||
try:
|
||||
if not self.client_config["enable_banning"]:
|
||||
return False
|
||||
|
||||
if ip_address in self.banned_ips:
|
||||
ban_data = self.banned_ips[ip_address]
|
||||
if time.time() - ban_data["ban_time"] < ban_data["duration"]:
|
||||
return True
|
||||
else:
|
||||
# 禁止时间已过期,移除
|
||||
del self.banned_ips[ip_address]
|
||||
self.client_state["banned_clients"] -= 1
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ IP禁止检查失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def unban_ip(self, ip_address: str) -> bool:
|
||||
"""
|
||||
解除IP禁止
|
||||
|
||||
Args:
|
||||
ip_address: IP地址
|
||||
|
||||
Returns:
|
||||
是否解除成功
|
||||
"""
|
||||
try:
|
||||
if ip_address in self.banned_ips:
|
||||
del self.banned_ips[ip_address]
|
||||
self.client_state["banned_clients"] -= 1
|
||||
print(f"✓ IP禁止已解除: {ip_address}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ IP未被禁止: {ip_address}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 解除IP禁止失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def is_client_authenticated(self, client_id: str) -> bool:
|
||||
"""
|
||||
检查客户端是否已认证
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
|
||||
Returns:
|
||||
客户端是否已认证
|
||||
"""
|
||||
try:
|
||||
with self.client_lock:
|
||||
if client_id in self.clients:
|
||||
return self.clients[client_id]["is_authenticated"]
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端认证检查失败: {e}")
|
||||
self.client_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def get_client_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取客户端统计信息
|
||||
|
||||
Returns:
|
||||
客户端统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.client_state.copy(),
|
||||
"stats": self.client_stats.copy(),
|
||||
"config": self.client_config.copy()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置客户端统计信息"""
|
||||
try:
|
||||
self.client_stats = {
|
||||
"clients_joined": 0,
|
||||
"clients_left": 0,
|
||||
"authentication_success": 0,
|
||||
"authentication_failed": 0,
|
||||
"messages_sent": 0,
|
||||
"messages_received": 0,
|
||||
"banned_clients": 0,
|
||||
"errors": 0
|
||||
}
|
||||
print("✓ 客户端统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端统计信息重置失败: {e}")
|
||||
|
||||
def set_client_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置客户端配置
|
||||
|
||||
Args:
|
||||
config: 客户端配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.client_config.update(config)
|
||||
print(f"✓ 客户端配置已更新: {self.client_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_client_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取客户端配置
|
||||
|
||||
Returns:
|
||||
客户端配置字典
|
||||
"""
|
||||
return self.client_config.copy()
|
||||
|
||||
def _trigger_client_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发客户端回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.client_callbacks:
|
||||
for callback in self.client_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端回调触发失败: {e}")
|
||||
|
||||
def register_client_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册客户端回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.client_callbacks:
|
||||
self.client_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 客户端回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端回调注册失败: {e}")
|
||||
|
||||
def unregister_client_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销客户端回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.client_callbacks:
|
||||
if callback in self.client_callbacks[callback_type]:
|
||||
self.client_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 客户端回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端回调注销失败: {e}")
|
||||
759
plugins/user/realtime_communication/config/comm_config.py
Normal file
759
plugins/user/realtime_communication/config/comm_config.py
Normal file
@ -0,0 +1,759 @@
|
||||
"""
|
||||
通信配置管理器模块
|
||||
管理通信配置和用户偏好
|
||||
"""
|
||||
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class CommConfig:
|
||||
"""
|
||||
通信配置管理器
|
||||
管理通信配置和用户偏好
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化通信配置管理器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 配置文件路径
|
||||
self.config_file_path = "/home/hello/EG/plugins/user/realtime_communication/config/communication_config.json"
|
||||
|
||||
# 默认配置
|
||||
self.default_config = {
|
||||
"server": {
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"enable_ssl": False,
|
||||
"ssl_cert_file": "",
|
||||
"ssl_key_file": "",
|
||||
"max_connections": 1000,
|
||||
"connection_timeout": 30.0,
|
||||
"ping_interval": 30.0
|
||||
},
|
||||
"client": {
|
||||
"enable_authentication": True,
|
||||
"auth_timeout": 30.0,
|
||||
"max_clients": 1000,
|
||||
"enable_heartbeat": True,
|
||||
"heartbeat_interval": 30.0,
|
||||
"enable_rate_limiting": True,
|
||||
"max_messages_per_second": 100,
|
||||
"enable_banning": True,
|
||||
"ban_duration": 3600
|
||||
},
|
||||
"message": {
|
||||
"enable_message_filtering": True,
|
||||
"max_message_size": 65536,
|
||||
"enable_message_queue": True,
|
||||
"message_queue_size": 10000,
|
||||
"enable_message_compression": True,
|
||||
"compression_threshold": 1024
|
||||
},
|
||||
"room": {
|
||||
"max_rooms": 1000,
|
||||
"max_clients_per_room": 100,
|
||||
"enable_room_persistence": False,
|
||||
"room_timeout": 3600,
|
||||
"enable_room_passwords": True
|
||||
},
|
||||
"protocol": {
|
||||
"supported_protocols": ["websocket", "json", "binary"],
|
||||
"default_protocol": "json",
|
||||
"enable_compression": True,
|
||||
"compression_threshold": 1024,
|
||||
"enable_encryption": False,
|
||||
"max_message_size": 65536
|
||||
},
|
||||
"auth": {
|
||||
"enable_authentication": True,
|
||||
"auth_timeout": 30.0,
|
||||
"enable_token_auth": True,
|
||||
"enable_password_auth": True,
|
||||
"token_lifetime": 86400,
|
||||
"enable_session_management": True,
|
||||
"session_timeout": 3600,
|
||||
"max_login_attempts": 5,
|
||||
"login_lockout_duration": 900
|
||||
},
|
||||
"serialization": {
|
||||
"default_format": "json",
|
||||
"supported_formats": ["json", "pickle", "binary"],
|
||||
"enable_compression": True,
|
||||
"compression_threshold": 1024,
|
||||
"enable_caching": True,
|
||||
"cache_size": 1000
|
||||
},
|
||||
"monitoring": {
|
||||
"enable_monitoring": True,
|
||||
"monitoring_interval": 5.0,
|
||||
"log_level": "INFO",
|
||||
"enable_file_logging": True,
|
||||
"log_file_path": "/home/hello/EG/plugins/user/realtime_communication/logs/communication_monitor.log"
|
||||
},
|
||||
"events": {
|
||||
"enable_event_system": True,
|
||||
"max_event_queue_size": 10000,
|
||||
"enable_event_filtering": True
|
||||
}
|
||||
}
|
||||
|
||||
# 当前配置
|
||||
self.current_config = self.default_config.copy()
|
||||
|
||||
# 配置状态
|
||||
self.config_state = {
|
||||
"last_loaded": 0.0,
|
||||
"last_saved": 0.0,
|
||||
"config_version": "1.0.0",
|
||||
"is_dirty": False
|
||||
}
|
||||
|
||||
# 配置统计
|
||||
self.config_stats = {
|
||||
"loads": 0,
|
||||
"saves": 0,
|
||||
"updates": 0,
|
||||
"config_errors": 0
|
||||
}
|
||||
|
||||
# 配置监听器
|
||||
self.config_listeners = {}
|
||||
|
||||
# 回调函数
|
||||
self.config_callbacks = {
|
||||
"config_loaded": [],
|
||||
"config_saved": [],
|
||||
"config_updated": [],
|
||||
"config_error": []
|
||||
}
|
||||
|
||||
print("✓ 通信配置管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化通信配置管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化通信配置管理器...")
|
||||
|
||||
# 创建配置目录
|
||||
config_dir = os.path.dirname(self.config_file_path)
|
||||
if not os.path.exists(config_dir):
|
||||
os.makedirs(config_dir)
|
||||
|
||||
# 创建日志目录
|
||||
if "monitoring" in self.default_config:
|
||||
log_dir = os.path.dirname(self.default_config["monitoring"]["log_file_path"])
|
||||
if not os.path.exists(log_dir):
|
||||
os.makedirs(log_dir)
|
||||
|
||||
# 加载配置
|
||||
self.load_config()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 通信配置管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信配置管理器初始化失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用通信配置管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 通信配置管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 通信配置管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信配置管理器启用失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用通信配置管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 保存配置(如果有更改)
|
||||
if self.config_state["is_dirty"]:
|
||||
self.save_config()
|
||||
|
||||
print("✓ 通信配置管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信配置管理器禁用失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理通信配置管理器资源"""
|
||||
try:
|
||||
# 禁用通信配置管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.config_callbacks.clear()
|
||||
self.config_listeners.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 通信配置管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信配置管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新通信配置管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
# 检查配置文件是否被外部修改
|
||||
self._check_config_file_changes()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信配置管理器更新失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _check_config_file_changes(self):
|
||||
"""检查配置文件是否被外部修改"""
|
||||
try:
|
||||
if not os.path.exists(self.config_file_path):
|
||||
return
|
||||
|
||||
last_modified = os.path.getmtime(self.config_file_path)
|
||||
if last_modified > self.config_state["last_loaded"]:
|
||||
# 配置文件已被修改,重新加载
|
||||
print("检测到配置文件被外部修改,正在重新加载...")
|
||||
self.load_config()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置文件变更检查失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
def load_config(self) -> bool:
|
||||
"""
|
||||
加载配置
|
||||
|
||||
Returns:
|
||||
是否加载成功
|
||||
"""
|
||||
try:
|
||||
# 检查配置文件是否存在
|
||||
if os.path.exists(self.config_file_path):
|
||||
with open(self.config_file_path, 'r', encoding='utf-8') as f:
|
||||
loaded_config = json.load(f)
|
||||
|
||||
# 合并配置(使用默认配置作为基础)
|
||||
self.current_config = self._merge_config(self.default_config, loaded_config)
|
||||
|
||||
print(f"✓ 配置已从文件加载: {self.config_file_path}")
|
||||
else:
|
||||
# 使用默认配置
|
||||
self.current_config = self.default_config.copy()
|
||||
print("✓ 使用默认配置")
|
||||
|
||||
self.config_state["last_loaded"] = time.time()
|
||||
self.config_state["is_dirty"] = False
|
||||
self.config_stats["loads"] += 1
|
||||
|
||||
# 触发配置加载回调
|
||||
self._trigger_config_callback("config_loaded", {
|
||||
"config": self.current_config,
|
||||
"timestamp": self.config_state["last_loaded"]
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置加载失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
# 使用默认配置
|
||||
self.current_config = self.default_config.copy()
|
||||
return False
|
||||
|
||||
def _merge_config(self, base_config: Dict[str, Any], override_config: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
合并配置(递归)
|
||||
|
||||
Args:
|
||||
base_config: 基础配置
|
||||
override_config: 覆盖配置
|
||||
|
||||
Returns:
|
||||
合并后的配置
|
||||
"""
|
||||
try:
|
||||
merged = base_config.copy()
|
||||
|
||||
for key, value in override_config.items():
|
||||
if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
|
||||
# 递归合并嵌套字典
|
||||
merged[key] = self._merge_config(merged[key], value)
|
||||
else:
|
||||
# 直接覆盖
|
||||
merged[key] = value
|
||||
|
||||
return merged
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置合并失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return base_config
|
||||
|
||||
def save_config(self) -> bool:
|
||||
"""
|
||||
保存配置
|
||||
|
||||
Returns:
|
||||
是否保存成功
|
||||
"""
|
||||
try:
|
||||
# 创建配置目录(如果不存在)
|
||||
config_dir = os.path.dirname(self.config_file_path)
|
||||
if not os.path.exists(config_dir):
|
||||
os.makedirs(config_dir)
|
||||
|
||||
# 保存配置到文件
|
||||
with open(self.config_file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.current_config, f, indent=2, ensure_ascii=False)
|
||||
|
||||
self.config_state["last_saved"] = time.time()
|
||||
self.config_state["is_dirty"] = False
|
||||
self.config_stats["saves"] += 1
|
||||
|
||||
# 触发配置保存回调
|
||||
self._trigger_config_callback("config_saved", {
|
||||
"config": self.current_config,
|
||||
"timestamp": self.config_state["last_saved"]
|
||||
})
|
||||
|
||||
print(f"✓ 配置已保存到文件: {self.config_file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置保存失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_config(self, section: str = None, key: str = None, default_value: Any = None) -> Any:
|
||||
"""
|
||||
获取配置值
|
||||
|
||||
Args:
|
||||
section: 配置节(可选)
|
||||
key: 配置键(可选)
|
||||
default_value: 默认值
|
||||
|
||||
Returns:
|
||||
配置值
|
||||
"""
|
||||
try:
|
||||
if section is None:
|
||||
return self.current_config.copy()
|
||||
|
||||
if section not in self.current_config:
|
||||
return default_value
|
||||
|
||||
if key is None:
|
||||
return self.current_config[section].copy()
|
||||
|
||||
if key not in self.current_config[section]:
|
||||
return default_value
|
||||
|
||||
return self.current_config[section][key]
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取配置失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return default_value
|
||||
|
||||
def set_config(self, section: str, key: str, value: Any) -> bool:
|
||||
"""
|
||||
设置配置值
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
value: 配置值
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
if section not in self.current_config:
|
||||
self.current_config[section] = {}
|
||||
|
||||
self.current_config[section][key] = value
|
||||
self.config_state["is_dirty"] = True
|
||||
self.config_stats["updates"] += 1
|
||||
|
||||
# 通知配置监听器
|
||||
self._notify_config_listeners(section, key, value)
|
||||
|
||||
# 触发配置更新回调
|
||||
self._trigger_config_callback("config_updated", {
|
||||
"section": section,
|
||||
"key": key,
|
||||
"value": value,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 设置配置失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def update_config_section(self, section: str, config_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
更新配置节
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
config_data: 配置数据
|
||||
|
||||
Returns:
|
||||
是否更新成功
|
||||
"""
|
||||
try:
|
||||
if section not in self.current_config:
|
||||
self.current_config[section] = {}
|
||||
|
||||
self.current_config[section].update(config_data)
|
||||
self.config_state["is_dirty"] = True
|
||||
self.config_stats["updates"] += 1
|
||||
|
||||
# 通知配置监听器
|
||||
for key, value in config_data.items():
|
||||
self._notify_config_listeners(section, key, value)
|
||||
|
||||
# 触发配置更新回调
|
||||
self._trigger_config_callback("config_updated", {
|
||||
"section": section,
|
||||
"config_data": config_data,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 更新配置节失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def reset_config(self) -> bool:
|
||||
"""
|
||||
重置配置为默认值
|
||||
|
||||
Returns:
|
||||
是否重置成功
|
||||
"""
|
||||
try:
|
||||
self.current_config = self.default_config.copy()
|
||||
self.config_state["is_dirty"] = True
|
||||
|
||||
# 通知所有配置监听器
|
||||
for section_name, section_data in self.current_config.items():
|
||||
if isinstance(section_data, dict):
|
||||
for key, value in section_data.items():
|
||||
self._notify_config_listeners(section_name, key, value)
|
||||
|
||||
print("✓ 配置已重置为默认值")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置重置失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def register_config_listener(self, section: str, key: str, listener: callable):
|
||||
"""
|
||||
注册配置监听器
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
listener: 监听器函数
|
||||
"""
|
||||
try:
|
||||
listener_key = f"{section}.{key}"
|
||||
if listener_key not in self.config_listeners:
|
||||
self.config_listeners[listener_key] = []
|
||||
|
||||
self.config_listeners[listener_key].append(listener)
|
||||
print(f"✓ 配置监听器已注册: {listener_key}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置监听器注册失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
def unregister_config_listener(self, section: str, key: str, listener: callable):
|
||||
"""
|
||||
注销配置监听器
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
listener: 监听器函数
|
||||
"""
|
||||
try:
|
||||
listener_key = f"{section}.{key}"
|
||||
if listener_key in self.config_listeners:
|
||||
if listener in self.config_listeners[listener_key]:
|
||||
self.config_listeners[listener_key].remove(listener)
|
||||
print(f"✓ 配置监听器已注销: {listener_key}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置监听器注销失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
def _notify_config_listeners(self, section: str, key: str, value: Any):
|
||||
"""
|
||||
通知配置监听器
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
value: 配置值
|
||||
"""
|
||||
try:
|
||||
listener_key = f"{section}.{key}"
|
||||
if listener_key in self.config_listeners:
|
||||
for listener in self.config_listeners[listener_key]:
|
||||
try:
|
||||
listener(section, key, value)
|
||||
except Exception as e:
|
||||
print(f"✗ 配置监听器执行失败: {listener_key} - {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置监听器通知失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
|
||||
def get_config_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取配置统计信息
|
||||
|
||||
Returns:
|
||||
配置统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.config_state.copy(),
|
||||
"stats": self.config_stats.copy(),
|
||||
"config_sections": list(self.current_config.keys())
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置配置统计信息"""
|
||||
try:
|
||||
self.config_stats = {
|
||||
"loads": 0,
|
||||
"saves": 0,
|
||||
"updates": 0,
|
||||
"config_errors": 0
|
||||
}
|
||||
print("✓ 配置统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 配置统计信息重置失败: {e}")
|
||||
|
||||
def validate_config(self) -> bool:
|
||||
"""
|
||||
验证配置
|
||||
|
||||
Returns:
|
||||
配置是否有效
|
||||
"""
|
||||
try:
|
||||
# 检查必需的配置项
|
||||
required_sections = ["server", "client", "message", "room", "protocol", "auth", "serialization"]
|
||||
for section in required_sections:
|
||||
if section not in self.current_config:
|
||||
print(f"✗ 缺少必需的配置节: {section}")
|
||||
return False
|
||||
|
||||
# 检查服务器配置
|
||||
server_config = self.current_config["server"]
|
||||
if "port" not in server_config or not isinstance(server_config["port"], int):
|
||||
print("✗ 无效的服务器端口配置")
|
||||
return False
|
||||
|
||||
if "max_connections" not in server_config or not isinstance(server_config["max_connections"], int):
|
||||
print("✗ 无效的最大连接数配置")
|
||||
return False
|
||||
|
||||
# 检查客户端配置
|
||||
client_config = self.current_config["client"]
|
||||
if "max_clients" not in client_config or not isinstance(client_config["max_clients"], int):
|
||||
print("✗ 无效的最大客户端数配置")
|
||||
return False
|
||||
|
||||
print("✓ 配置验证通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置验证失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def export_config(self, file_path: str) -> bool:
|
||||
"""
|
||||
导出配置到文件
|
||||
|
||||
Args:
|
||||
file_path: 导出文件路径
|
||||
|
||||
Returns:
|
||||
是否导出成功
|
||||
"""
|
||||
try:
|
||||
# 创建导出目录
|
||||
export_dir = os.path.dirname(file_path)
|
||||
if not os.path.exists(export_dir):
|
||||
os.makedirs(export_dir)
|
||||
|
||||
# 导出配置
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(self.current_config, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print(f"✓ 配置已导出到: {file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置导出失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def import_config(self, file_path: str) -> bool:
|
||||
"""
|
||||
从文件导入配置
|
||||
|
||||
Args:
|
||||
file_path: 导入文件路径
|
||||
|
||||
Returns:
|
||||
是否导入成功
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists(file_path):
|
||||
print(f"✗ 配置文件不存在: {file_path}")
|
||||
return False
|
||||
|
||||
# 读取配置文件
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
imported_config = json.load(f)
|
||||
|
||||
# 验证配置
|
||||
if not isinstance(imported_config, dict):
|
||||
print("✗ 无效的配置文件格式")
|
||||
return False
|
||||
|
||||
# 合并配置
|
||||
self.current_config = self._merge_config(self.default_config, imported_config)
|
||||
self.config_state["is_dirty"] = True
|
||||
|
||||
# 通知配置监听器
|
||||
for section_name, section_data in self.current_config.items():
|
||||
if isinstance(section_data, dict):
|
||||
for key, value in section_data.items():
|
||||
self._notify_config_listeners(section_name, key, value)
|
||||
|
||||
print(f"✓ 配置已从文件导入: {file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置导入失败: {e}")
|
||||
self.config_stats["config_errors"] += 1
|
||||
return False
|
||||
|
||||
def _trigger_config_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发配置回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.config_callbacks:
|
||||
for callback in self.config_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 配置回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 配置回调触发失败: {e}")
|
||||
|
||||
def register_config_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册配置回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.config_callbacks:
|
||||
self.config_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 配置回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 配置回调注册失败: {e}")
|
||||
|
||||
def unregister_config_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销配置回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.config_callbacks:
|
||||
if callback in self.config_callbacks[callback_type]:
|
||||
self.config_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 配置回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 配置回调注销失败: {e}")
|
||||
698
plugins/user/realtime_communication/core/websocket_server.py
Normal file
698
plugins/user/realtime_communication/core/websocket_server.py
Normal file
@ -0,0 +1,698 @@
|
||||
"""
|
||||
WebSocket服务器模块
|
||||
处理实时双向通信连接
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import json
|
||||
import base64
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class WebSocketServer:
|
||||
"""
|
||||
WebSocket服务器
|
||||
处理实时双向通信连接
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化WebSocket服务器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# WebSocket配置
|
||||
self.websocket_config = {
|
||||
"host": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"enable_ssl": False,
|
||||
"ssl_cert_file": "",
|
||||
"ssl_key_file": "",
|
||||
"max_connections": 1000,
|
||||
"enable_compression": True,
|
||||
"ping_interval": 30.0,
|
||||
"ping_timeout": 10.0,
|
||||
"message_queue_size": 1000,
|
||||
"enable_cors": True
|
||||
}
|
||||
|
||||
# WebSocket服务器状态
|
||||
self.server_state = {
|
||||
"is_running": False,
|
||||
"start_time": 0.0,
|
||||
"uptime": 0.0,
|
||||
"current_connections": 0,
|
||||
"total_connections": 0,
|
||||
"bytes_sent": 0,
|
||||
"bytes_received": 0
|
||||
}
|
||||
|
||||
# WebSocket服务器统计
|
||||
self.server_stats = {
|
||||
"messages_sent": 0,
|
||||
"messages_received": 0,
|
||||
"connections_accepted": 0,
|
||||
"connections_dropped": 0,
|
||||
"errors": 0
|
||||
}
|
||||
|
||||
# 连接存储
|
||||
self.connections = {}
|
||||
self.connection_lock = threading.RLock()
|
||||
|
||||
# 消息队列
|
||||
self.message_queue = []
|
||||
self.message_queue_lock = threading.RLock()
|
||||
|
||||
# 服务器线程
|
||||
self.server_thread = None
|
||||
self.server_thread_running = False
|
||||
|
||||
# 回调函数
|
||||
self.websocket_callbacks = {
|
||||
"server_started": [],
|
||||
"server_stopped": [],
|
||||
"client_connected": [],
|
||||
"client_disconnected": [],
|
||||
"message_received": [],
|
||||
"websocket_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_ping_time = 0.0
|
||||
self.last_message_time = 0.0
|
||||
|
||||
print("✓ WebSocket服务器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化WebSocket服务器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化WebSocket服务器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ WebSocket服务器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket服务器初始化失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用WebSocket服务器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ WebSocket服务器未初始化")
|
||||
return False
|
||||
|
||||
# 启动WebSocket服务器
|
||||
self._start_websocket_server()
|
||||
|
||||
self.enabled = True
|
||||
print("✓ WebSocket服务器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket服务器启用失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用WebSocket服务器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 停止WebSocket服务器
|
||||
self._stop_websocket_server()
|
||||
|
||||
print("✓ WebSocket服务器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket服务器禁用失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理WebSocket服务器资源"""
|
||||
try:
|
||||
# 禁用WebSocket服务器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.websocket_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ WebSocket服务器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket服务器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新WebSocket服务器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 更新运行时间
|
||||
if self.server_state["is_running"]:
|
||||
self.server_state["uptime"] = current_time - self.server_state["start_time"]
|
||||
|
||||
# 处理消息队列
|
||||
self._process_message_queue()
|
||||
|
||||
# 发送心跳
|
||||
if current_time - self.last_ping_time > self.websocket_config["ping_interval"]:
|
||||
self._send_ping_to_all_clients()
|
||||
self.last_ping_time = current_time
|
||||
|
||||
self.last_message_time = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket服务器更新失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _start_websocket_server(self):
|
||||
"""启动WebSocket服务器"""
|
||||
try:
|
||||
if self.server_state["is_running"]:
|
||||
return
|
||||
|
||||
# 在实际实现中,这里会启动一个WebSocket服务器
|
||||
# 由于这是一个示例,我们模拟服务器启动过程
|
||||
self.server_state["is_running"] = True
|
||||
self.server_state["start_time"] = time.time()
|
||||
|
||||
# 触发服务器启动回调
|
||||
self._trigger_websocket_callback("server_started", {
|
||||
"host": self.websocket_config["host"],
|
||||
"port": self.websocket_config["port"],
|
||||
"timestamp": self.server_state["start_time"]
|
||||
})
|
||||
|
||||
print(f"✓ WebSocket服务器已启动: ws://{self.websocket_config['host']}:{self.websocket_config['port']}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket服务器启动失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
|
||||
def _stop_websocket_server(self):
|
||||
"""停止WebSocket服务器"""
|
||||
try:
|
||||
if not self.server_state["is_running"]:
|
||||
return
|
||||
|
||||
# 断开所有客户端连接
|
||||
self._disconnect_all_clients()
|
||||
|
||||
self.server_state["is_running"] = False
|
||||
self.server_state["start_time"] = 0.0
|
||||
self.server_state["uptime"] = 0.0
|
||||
|
||||
# 触发服务器停止回调
|
||||
self._trigger_websocket_callback("server_stopped", {
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print("✓ WebSocket服务器已停止")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket服务器停止失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
|
||||
def _process_message_queue(self):
|
||||
"""处理消息队列"""
|
||||
try:
|
||||
if not self.message_queue:
|
||||
return
|
||||
|
||||
with self.message_queue_lock:
|
||||
messages_to_process = self.message_queue[:]
|
||||
self.message_queue.clear()
|
||||
|
||||
for message_data in messages_to_process:
|
||||
try:
|
||||
client_id = message_data.get("client_id")
|
||||
message = message_data.get("message")
|
||||
|
||||
# 处理消息
|
||||
self._handle_incoming_message(client_id, message)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息处理失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息队列处理失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
|
||||
def _handle_incoming_message(self, client_id: str, message: Dict[str, Any]):
|
||||
"""
|
||||
处理传入消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
"""
|
||||
try:
|
||||
self.server_stats["messages_received"] += 1
|
||||
|
||||
# 触发消息接收回调
|
||||
self._trigger_websocket_callback("message_received", {
|
||||
"client_id": client_id,
|
||||
"message": message,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 将消息传递给消息路由器处理
|
||||
if self.plugin.message_router:
|
||||
self.plugin.message_router.route_message(client_id, message)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 传入消息处理失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
|
||||
def _send_ping_to_all_clients(self):
|
||||
"""向所有客户端发送心跳"""
|
||||
try:
|
||||
ping_message = {
|
||||
"type": "ping",
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
with self.connection_lock:
|
||||
for client_id, connection in self.connections.items():
|
||||
try:
|
||||
self._send_message_to_client(client_id, ping_message)
|
||||
except Exception as e:
|
||||
print(f"✗ 心跳发送失败: {client_id} - {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 心跳发送失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
|
||||
def _disconnect_all_clients(self):
|
||||
"""断开所有客户端连接"""
|
||||
try:
|
||||
with self.connection_lock:
|
||||
client_ids = list(self.connections.keys())
|
||||
|
||||
for client_id in client_ids:
|
||||
self.disconnect_client(client_id, "server_shutdown")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 断开所有客户端连接失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
|
||||
def send_message_to_client(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
向客户端发送消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否发送成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
return self._send_message_to_client(client_id, message)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 向客户端发送消息失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def _send_message_to_client(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
向客户端发送消息(内部实现)
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否发送成功
|
||||
"""
|
||||
try:
|
||||
# 检查客户端连接是否存在
|
||||
with self.connection_lock:
|
||||
if client_id not in self.connections:
|
||||
return False
|
||||
|
||||
# 序列化消息
|
||||
if self.plugin.data_serializer:
|
||||
serialized_message = self.plugin.data_serializer.serialize(message)
|
||||
else:
|
||||
serialized_message = json.dumps(message, ensure_ascii=False)
|
||||
|
||||
# 发送消息(模拟)
|
||||
message_size = len(serialized_message.encode('utf-8'))
|
||||
self.server_state["bytes_sent"] += message_size
|
||||
self.server_stats["messages_sent"] += 1
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 向客户端发送消息失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def broadcast_message(self, message: Dict[str, Any], exclude_client_id: str = None) -> bool:
|
||||
"""
|
||||
广播消息到所有客户端
|
||||
|
||||
Args:
|
||||
message: 消息数据
|
||||
exclude_client_id: 要排除的客户端ID
|
||||
|
||||
Returns:
|
||||
是否广播成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
success_count = 0
|
||||
with self.connection_lock:
|
||||
for client_id in self.connections.keys():
|
||||
# 跳过排除的客户端
|
||||
if client_id == exclude_client_id:
|
||||
continue
|
||||
|
||||
if self._send_message_to_client(client_id, message):
|
||||
success_count += 1
|
||||
|
||||
return success_count > 0
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息广播失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def add_client_connection(self, client_id: str, connection_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
添加客户端连接
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
connection_data: 连接数据
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
with self.connection_lock:
|
||||
# 检查连接数限制
|
||||
if len(self.connections) >= self.websocket_config["max_connections"]:
|
||||
print("✗ 连接数已达上限")
|
||||
return False
|
||||
|
||||
# 添加连接
|
||||
self.connections[client_id] = {
|
||||
"connection_data": connection_data,
|
||||
"connect_time": time.time(),
|
||||
"last_activity": time.time(),
|
||||
"bytes_sent": 0,
|
||||
"bytes_received": 0,
|
||||
"messages_sent": 0,
|
||||
"messages_received": 0
|
||||
}
|
||||
|
||||
self.server_state["current_connections"] = len(self.connections)
|
||||
self.server_state["total_connections"] += 1
|
||||
self.server_stats["connections_accepted"] += 1
|
||||
|
||||
# 触发客户端连接回调
|
||||
self._trigger_websocket_callback("client_connected", {
|
||||
"client_id": client_id,
|
||||
"connection_data": connection_data,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 客户端已连接: {client_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 添加客户端连接失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_client_connection(self, client_id: str, reason: str = "unknown") -> bool:
|
||||
"""
|
||||
移除客户端连接
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
reason: 断开原因
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
with self.connection_lock:
|
||||
if client_id in self.connections:
|
||||
del self.connections[client_id]
|
||||
|
||||
self.server_state["current_connections"] = len(self.connections)
|
||||
self.server_stats["connections_dropped"] += 1
|
||||
|
||||
# 触发客户端断开回调
|
||||
self._trigger_websocket_callback("client_disconnected", {
|
||||
"client_id": client_id,
|
||||
"reason": reason,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 客户端已断开: {client_id} (原因: {reason})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 移除客户端连接失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def disconnect_client(self, client_id: str, reason: str = "kicked") -> bool:
|
||||
"""
|
||||
断开客户端连接
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
reason: 断开原因
|
||||
|
||||
Returns:
|
||||
是否断开成功
|
||||
"""
|
||||
try:
|
||||
# 通知客户端断开连接
|
||||
disconnect_message = {
|
||||
"type": "disconnect",
|
||||
"reason": reason,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
self._send_message_to_client(client_id, disconnect_message)
|
||||
|
||||
# 移除连接
|
||||
return self.remove_client_connection(client_id, reason)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 断开客户端连接失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def get_connection_info(self, client_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取连接信息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
|
||||
Returns:
|
||||
连接信息或None
|
||||
"""
|
||||
try:
|
||||
with self.connection_lock:
|
||||
if client_id in self.connections:
|
||||
return self.connections[client_id].copy()
|
||||
else:
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取连接信息失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
return None
|
||||
|
||||
def get_all_connections(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取所有连接信息
|
||||
|
||||
Returns:
|
||||
所有连接信息字典
|
||||
"""
|
||||
try:
|
||||
with self.connection_lock:
|
||||
return {k: v.copy() for k, v in self.connections.items()}
|
||||
except Exception as e:
|
||||
print(f"✗ 获取所有连接信息失败: {e}")
|
||||
self.server_stats["errors"] += 1
|
||||
return {}
|
||||
|
||||
def get_server_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取服务器统计信息
|
||||
|
||||
Returns:
|
||||
服务器统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.server_state.copy(),
|
||||
"stats": self.server_stats.copy(),
|
||||
"config": self.websocket_config.copy()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置服务器统计信息"""
|
||||
try:
|
||||
self.server_stats = {
|
||||
"messages_sent": 0,
|
||||
"messages_received": 0,
|
||||
"connections_accepted": 0,
|
||||
"connections_dropped": 0,
|
||||
"errors": 0
|
||||
}
|
||||
|
||||
self.server_state["bytes_sent"] = 0
|
||||
self.server_state["bytes_received"] = 0
|
||||
|
||||
print("✓ 服务器统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 服务器统计信息重置失败: {e}")
|
||||
|
||||
def set_websocket_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置WebSocket配置
|
||||
|
||||
Args:
|
||||
config: WebSocket配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
old_port = self.websocket_config.get("port")
|
||||
new_port = config.get("port", old_port)
|
||||
|
||||
# 如果服务器正在运行且端口发生变化,重启服务器
|
||||
if (self.server_state["is_running"] and
|
||||
old_port != new_port):
|
||||
self._stop_websocket_server()
|
||||
self.websocket_config.update(config)
|
||||
self._start_websocket_server()
|
||||
else:
|
||||
self.websocket_config.update(config)
|
||||
|
||||
print(f"✓ WebSocket配置已更新: {self.websocket_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_websocket_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取WebSocket配置
|
||||
|
||||
Returns:
|
||||
WebSocket配置字典
|
||||
"""
|
||||
return self.websocket_config.copy()
|
||||
|
||||
def _trigger_websocket_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发WebSocket回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.websocket_callbacks:
|
||||
for callback in self.websocket_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket回调触发失败: {e}")
|
||||
|
||||
def register_websocket_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册WebSocket回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.websocket_callbacks:
|
||||
self.websocket_callbacks[callback_type].append(callback)
|
||||
print(f"✓ WebSocket回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket回调注册失败: {e}")
|
||||
|
||||
def unregister_websocket_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销WebSocket回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.websocket_callbacks:
|
||||
if callback in self.websocket_callbacks[callback_type]:
|
||||
self.websocket_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ WebSocket回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ WebSocket回调注销失败: {e}")
|
||||
596
plugins/user/realtime_communication/editor/comm_editor.py
Normal file
596
plugins/user/realtime_communication/editor/comm_editor.py
Normal file
@ -0,0 +1,596 @@
|
||||
"""
|
||||
通信编辑器模块
|
||||
提供图形界面配置通信参数
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class CommEditor:
|
||||
"""
|
||||
通信编辑器
|
||||
提供图形界面配置通信参数
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化通信编辑器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 编辑器配置
|
||||
self.editor_config = {
|
||||
"enable_editor": True,
|
||||
"enable_realtime_monitoring": True,
|
||||
"enable_performance_display": True,
|
||||
"enable_config_editor": True,
|
||||
"enable_statistics_display": True,
|
||||
"refresh_interval": 1.0,
|
||||
"max_data_points": 100
|
||||
}
|
||||
|
||||
# 编辑器状态
|
||||
self.editor_state = {
|
||||
"is_visible": False,
|
||||
"last_update": 0.0,
|
||||
"active_tab": "overview",
|
||||
"selected_client": None,
|
||||
"selected_room": None
|
||||
}
|
||||
|
||||
# UI组件
|
||||
self.ui_components = {
|
||||
"main_window": None,
|
||||
"tabs": {},
|
||||
"panels": {},
|
||||
"charts": {},
|
||||
"controls": {}
|
||||
}
|
||||
|
||||
# 编辑器统计
|
||||
self.editor_stats = {
|
||||
"updates": 0,
|
||||
"ui_refreshes": 0,
|
||||
"data_points": 0,
|
||||
"editor_errors": 0
|
||||
}
|
||||
|
||||
# 实时数据缓存
|
||||
self.realtime_data = {
|
||||
"performance_metrics": {},
|
||||
"client_data": {},
|
||||
"room_data": {},
|
||||
"message_stats": {},
|
||||
"network_stats": {}
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.editor_callbacks = {
|
||||
"ui_updated": [],
|
||||
"data_refreshed": [],
|
||||
"config_changed": [],
|
||||
"editor_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_ui_update = 0.0
|
||||
self.last_data_refresh = 0.0
|
||||
|
||||
print("✓ 通信编辑器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化通信编辑器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化通信编辑器...")
|
||||
|
||||
# 初始化UI组件(模拟)
|
||||
self._initialize_ui_components()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 通信编辑器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信编辑器初始化失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _initialize_ui_components(self):
|
||||
"""初始化UI组件"""
|
||||
try:
|
||||
# 创建主窗口
|
||||
self.ui_components["main_window"] = {
|
||||
"title": "实时通信插件编辑器",
|
||||
"size": (1200, 800),
|
||||
"position": (100, 100)
|
||||
}
|
||||
|
||||
# 创建标签页
|
||||
self.ui_components["tabs"] = {
|
||||
"overview": {"name": "概览", "icon": "dashboard"},
|
||||
"clients": {"name": "客户端", "icon": "people"},
|
||||
"rooms": {"name": "房间", "icon": "meeting_room"},
|
||||
"messages": {"name": "消息", "icon": "message"},
|
||||
"network": {"name": "网络", "icon": "network"},
|
||||
"config": {"name": "配置", "icon": "settings"},
|
||||
"statistics": {"name": "统计", "icon": "bar_chart"}
|
||||
}
|
||||
|
||||
# 创建面板
|
||||
self.ui_components["panels"] = {
|
||||
"server_status": {"title": "服务器状态", "visible": True},
|
||||
"performance": {"title": "性能指标", "visible": True},
|
||||
"clients_list": {"title": "客户端列表", "visible": True},
|
||||
"rooms_list": {"title": "房间列表", "visible": True},
|
||||
"message_stats": {"title": "消息统计", "visible": True}
|
||||
}
|
||||
|
||||
print("✓ UI组件已初始化")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ UI组件初始化失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用通信编辑器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 通信编辑器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 通信编辑器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信编辑器启用失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用通信编辑器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 隐藏UI
|
||||
self.hide_editor()
|
||||
|
||||
print("✓ 通信编辑器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信编辑器禁用失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理通信编辑器资源"""
|
||||
try:
|
||||
# 禁用通信编辑器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.editor_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 通信编辑器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信编辑器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新通信编辑器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期刷新UI
|
||||
if current_time - self.last_ui_update >= self.editor_config["refresh_interval"]:
|
||||
self._refresh_ui()
|
||||
self.last_ui_update = current_time
|
||||
|
||||
# 定期更新数据
|
||||
if current_time - self.last_data_refresh >= 0.5: # 每0.5秒更新一次数据
|
||||
self._update_realtime_data()
|
||||
self.last_data_refresh = current_time
|
||||
|
||||
self.editor_state["last_update"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信编辑器更新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _refresh_ui(self):
|
||||
"""刷新UI"""
|
||||
try:
|
||||
# 更新UI组件状态
|
||||
self._update_ui_components()
|
||||
|
||||
# 更新统计信息
|
||||
self.editor_stats["ui_refreshes"] += 1
|
||||
|
||||
# 触发UI更新回调
|
||||
self._trigger_editor_callback("ui_updated", {
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ UI刷新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def _update_ui_components(self):
|
||||
"""更新UI组件"""
|
||||
try:
|
||||
# 更新服务器状态面板
|
||||
if self.plugin.websocket_server:
|
||||
server_stats = self.plugin.websocket_server.get_server_stats()
|
||||
self.ui_components["panels"]["server_status"]["data"] = server_stats
|
||||
|
||||
# 更新客户端列表面板
|
||||
if self.plugin.client_manager:
|
||||
clients = self.plugin.client_manager.get_all_clients()
|
||||
self.ui_components["panels"]["clients_list"]["data"] = clients
|
||||
|
||||
# 更新房间列表面板
|
||||
if self.plugin.room_manager:
|
||||
rooms = self.plugin.room_manager.get_all_rooms()
|
||||
self.ui_components["panels"]["rooms_list"]["data"] = rooms
|
||||
|
||||
# 更新消息统计面板
|
||||
if self.plugin.message_router:
|
||||
message_stats = self.plugin.message_router.get_message_stats()
|
||||
self.ui_components["panels"]["message_stats"]["data"] = message_stats
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ UI组件更新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def _update_realtime_data(self):
|
||||
"""更新实时数据"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
|
||||
# 更新性能指标
|
||||
if self.plugin.monitor:
|
||||
metrics = self.plugin.monitor.get_performance_metrics()
|
||||
self.realtime_data["performance_metrics"] = metrics
|
||||
|
||||
# 更新客户端数据
|
||||
if self.plugin.client_manager:
|
||||
clients = self.plugin.client_manager.get_all_clients()
|
||||
self.realtime_data["client_data"] = clients
|
||||
|
||||
# 更新房间数据
|
||||
if self.plugin.room_manager:
|
||||
rooms = self.plugin.room_manager.get_all_rooms()
|
||||
self.realtime_data["room_data"] = rooms
|
||||
|
||||
# 更新消息统计
|
||||
if self.plugin.message_router:
|
||||
message_stats = self.plugin.message_router.get_message_stats()
|
||||
self.realtime_data["message_stats"] = message_stats
|
||||
|
||||
# 更新网络统计
|
||||
if self.plugin.websocket_server:
|
||||
network_stats = self.plugin.websocket_server.get_server_stats()
|
||||
self.realtime_data["network_stats"] = network_stats
|
||||
|
||||
# 触发数据刷新回调
|
||||
self._trigger_editor_callback("data_refreshed", {
|
||||
"data": self.realtime_data,
|
||||
"timestamp": current_time
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 实时数据更新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def show_editor(self):
|
||||
"""显示编辑器"""
|
||||
try:
|
||||
self.editor_state["is_visible"] = True
|
||||
print("✓ 通信编辑器已显示")
|
||||
|
||||
# 刷新数据
|
||||
self._update_realtime_data()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器显示失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def hide_editor(self):
|
||||
"""隐藏编辑器"""
|
||||
try:
|
||||
self.editor_state["is_visible"] = False
|
||||
print("✓ 通信编辑器已隐藏")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器隐藏失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def switch_tab(self, tab_name: str):
|
||||
"""
|
||||
切换标签页
|
||||
|
||||
Args:
|
||||
tab_name: 标签页名称
|
||||
"""
|
||||
try:
|
||||
if tab_name in self.ui_components["tabs"]:
|
||||
self.editor_state["active_tab"] = tab_name
|
||||
print(f"✓ 切换到标签页: {tab_name}")
|
||||
else:
|
||||
print(f"✗ 无效的标签页: {tab_name}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 标签页切换失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def select_client(self, client_id: str):
|
||||
"""
|
||||
选择客户端
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
"""
|
||||
try:
|
||||
self.editor_state["selected_client"] = client_id
|
||||
print(f"✓ 选择客户端: {client_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端选择失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def select_room(self, room_id: str):
|
||||
"""
|
||||
选择房间
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
"""
|
||||
try:
|
||||
self.editor_state["selected_room"] = room_id
|
||||
print(f"✓ 选择房间: {room_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间选择失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
|
||||
def update_config(self, section: str, key: str, value: Any) -> bool:
|
||||
"""
|
||||
更新配置
|
||||
|
||||
Args:
|
||||
section: 配置节
|
||||
key: 配置键
|
||||
value: 配置值
|
||||
|
||||
Returns:
|
||||
是否更新成功
|
||||
"""
|
||||
try:
|
||||
# 通过配置管理器更新配置
|
||||
if self.plugin.config_manager:
|
||||
result = self.plugin.config_manager.set_config(section, key, value)
|
||||
|
||||
if result:
|
||||
self.editor_stats["updates"] += 1
|
||||
|
||||
# 触发配置更改回调
|
||||
self._trigger_editor_callback("config_changed", {
|
||||
"section": section,
|
||||
"key": key,
|
||||
"value": value,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 配置已更新: {section}.{key} = {value}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 配置更新失败: {section}.{key}")
|
||||
return False
|
||||
else:
|
||||
print("✗ 配置管理器不可用")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 配置更新失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_editor_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取编辑器统计信息
|
||||
|
||||
Returns:
|
||||
编辑器统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.editor_state.copy(),
|
||||
"stats": self.editor_stats.copy(),
|
||||
"config": self.editor_config.copy(),
|
||||
"ui_components": len(self.ui_components["tabs"])
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置编辑器统计信息"""
|
||||
try:
|
||||
self.editor_stats = {
|
||||
"updates": 0,
|
||||
"ui_refreshes": 0,
|
||||
"data_points": 0,
|
||||
"editor_errors": 0
|
||||
}
|
||||
print("✓ 编辑器统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器统计信息重置失败: {e}")
|
||||
|
||||
def set_editor_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置编辑器配置
|
||||
|
||||
Args:
|
||||
config: 编辑器配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.editor_config.update(config)
|
||||
print(f"✓ 编辑器配置已更新: {self.editor_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_editor_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取编辑器配置
|
||||
|
||||
Returns:
|
||||
编辑器配置字典
|
||||
"""
|
||||
return self.editor_config.copy()
|
||||
|
||||
def get_realtime_data(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取实时数据
|
||||
|
||||
Returns:
|
||||
实时数据字典
|
||||
"""
|
||||
return self.realtime_data.copy()
|
||||
|
||||
def export_data(self, data_type: str, file_path: str) -> bool:
|
||||
"""
|
||||
导出数据
|
||||
|
||||
Args:
|
||||
data_type: 数据类型
|
||||
file_path: 导出文件路径
|
||||
|
||||
Returns:
|
||||
是否导出成功
|
||||
"""
|
||||
try:
|
||||
import json
|
||||
import os
|
||||
|
||||
# 创建导出目录
|
||||
export_dir = os.path.dirname(file_path)
|
||||
if not os.path.exists(export_dir):
|
||||
os.makedirs(export_dir)
|
||||
|
||||
# 获取要导出的数据
|
||||
export_data = None
|
||||
if data_type == "performance":
|
||||
export_data = self.realtime_data["performance_metrics"]
|
||||
elif data_type == "clients":
|
||||
export_data = self.realtime_data["client_data"]
|
||||
elif data_type == "rooms":
|
||||
export_data = self.realtime_data["room_data"]
|
||||
elif data_type == "messages":
|
||||
export_data = self.realtime_data["message_stats"]
|
||||
elif data_type == "network":
|
||||
export_data = self.realtime_data["network_stats"]
|
||||
elif data_type == "all":
|
||||
export_data = self.realtime_data
|
||||
else:
|
||||
print(f"✗ 不支持的数据类型: {data_type}")
|
||||
return False
|
||||
|
||||
# 导出数据
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(export_data, f, indent=2, ensure_ascii=False, default=str)
|
||||
|
||||
print(f"✓ 数据已导出到: {file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 数据导出失败: {e}")
|
||||
self.editor_stats["editor_errors"] += 1
|
||||
return False
|
||||
|
||||
def _trigger_editor_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发编辑器回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.editor_callbacks:
|
||||
for callback in self.editor_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器回调触发失败: {e}")
|
||||
|
||||
def register_editor_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册编辑器回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.editor_callbacks:
|
||||
self.editor_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 编辑器回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器回调注册失败: {e}")
|
||||
|
||||
def unregister_editor_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销编辑器回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.editor_callbacks:
|
||||
if callback in self.editor_callbacks[callback_type]:
|
||||
self.editor_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 编辑器回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 编辑器回调注销失败: {e}")
|
||||
716
plugins/user/realtime_communication/events/event_handler.py
Normal file
716
plugins/user/realtime_communication/events/event_handler.py
Normal file
@ -0,0 +1,716 @@
|
||||
"""
|
||||
事件处理器模块
|
||||
处理通信事件和系统响应
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import queue
|
||||
from typing import Dict, Any, List, Optional, Callable
|
||||
|
||||
class EventHandler:
|
||||
"""
|
||||
事件处理器
|
||||
处理通信事件和系统响应
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化事件处理器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 事件配置
|
||||
self.event_config = {
|
||||
"enable_event_system": True,
|
||||
"max_event_queue_size": 10000,
|
||||
"enable_event_filtering": True,
|
||||
"event_processing_interval": 0.01, # 10ms
|
||||
"enable_async_processing": True,
|
||||
"max_concurrent_events": 100,
|
||||
"enable_event_prioritization": True,
|
||||
"enable_event_logging": True
|
||||
}
|
||||
|
||||
# 事件状态
|
||||
self.event_state = {
|
||||
"is_processing": False,
|
||||
"pending_events": 0,
|
||||
"processed_events": 0,
|
||||
"dropped_events": 0,
|
||||
"last_event_time": 0.0
|
||||
}
|
||||
|
||||
# 事件队列
|
||||
self.event_queue = queue.Queue(maxsize=self.event_config["max_event_queue_size"])
|
||||
self.event_queue_lock = threading.RLock()
|
||||
|
||||
# 事件处理器存储
|
||||
self.event_handlers = {}
|
||||
|
||||
# 事件统计
|
||||
self.event_stats = {
|
||||
"events_received": 0,
|
||||
"events_processed": 0,
|
||||
"events_dropped": 0,
|
||||
"handler_errors": 0,
|
||||
"async_events": 0
|
||||
}
|
||||
|
||||
# 事件过滤器
|
||||
self.event_filters = {}
|
||||
|
||||
# 回调函数
|
||||
self.event_callbacks = {
|
||||
"event_received": [],
|
||||
"event_processed": [],
|
||||
"event_dropped": [],
|
||||
"event_error": []
|
||||
}
|
||||
|
||||
# 事件处理线程
|
||||
self.event_thread = None
|
||||
self.event_thread_running = False
|
||||
|
||||
# 时间戳记录
|
||||
self.last_event_process = 0.0
|
||||
self.last_stats_reset = 0.0
|
||||
|
||||
print("✓ 事件处理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化事件处理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化事件处理器...")
|
||||
|
||||
# 注册默认事件处理器
|
||||
self._register_default_handlers()
|
||||
|
||||
# 启动事件处理线程
|
||||
self._start_event_thread()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 事件处理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器初始化失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _register_default_handlers(self):
|
||||
"""注册默认事件处理器"""
|
||||
try:
|
||||
# 注册系统事件处理器
|
||||
self.register_event_handler("client_connected", self._handle_client_connected)
|
||||
self.register_event_handler("client_disconnected", self._handle_client_disconnected)
|
||||
self.register_event_handler("message_received", self._handle_message_received)
|
||||
self.register_event_handler("room_created", self._handle_room_created)
|
||||
self.register_event_handler("room_destroyed", self._handle_room_destroyed)
|
||||
self.register_event_handler("client_joined_room", self._handle_client_joined_room)
|
||||
self.register_event_handler("client_left_room", self._handle_client_left_room)
|
||||
|
||||
print("✓ 默认事件处理器已注册")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 默认事件处理器注册失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _start_event_thread(self):
|
||||
"""启动事件处理线程"""
|
||||
try:
|
||||
self.event_thread_running = True
|
||||
self.event_thread = threading.Thread(target=self._event_loop, daemon=True)
|
||||
self.event_thread.start()
|
||||
print("✓ 事件处理线程已启动")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理线程启动失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _event_loop(self):
|
||||
"""事件处理循环"""
|
||||
try:
|
||||
while self.event_thread_running:
|
||||
try:
|
||||
if self.enabled and self.event_config["enable_event_system"]:
|
||||
# 处理事件队列
|
||||
self._process_event_queue()
|
||||
|
||||
# 短暂休眠
|
||||
time.sleep(self.event_config["event_processing_interval"])
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理循环错误: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
time.sleep(1.0) # 出错时延长休眠
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理线程失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用事件处理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 事件处理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 事件处理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器启用失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用事件处理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 停止事件处理线程
|
||||
if self.event_thread_running:
|
||||
self.event_thread_running = False
|
||||
if self.event_thread and self.event_thread.is_alive():
|
||||
self.event_thread.join(timeout=5.0)
|
||||
|
||||
print("✓ 事件处理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器禁用失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理事件处理器资源"""
|
||||
try:
|
||||
# 禁用事件处理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调和处理器
|
||||
self.event_callbacks.clear()
|
||||
self.event_handlers.clear()
|
||||
self.event_filters.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 事件处理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新事件处理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
self.event_state["last_event_time"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器更新失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _process_event_queue(self):
|
||||
"""处理事件队列"""
|
||||
try:
|
||||
processed_count = 0
|
||||
max_process_per_loop = 100 # 每次循环最多处理100个事件
|
||||
|
||||
while not self.event_queue.empty() and processed_count < max_process_per_loop:
|
||||
try:
|
||||
# 从队列获取事件
|
||||
event_data = self.event_queue.get_nowait()
|
||||
|
||||
# 处理事件
|
||||
self._handle_event_internal(event_data)
|
||||
|
||||
processed_count += 1
|
||||
self.event_stats["events_processed"] += 1
|
||||
|
||||
except queue.Empty:
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"✗ 事件队列处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
self.event_state["pending_events"] = self.event_queue.qsize()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件队列处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_event_internal(self, event_data: Dict[str, Any]):
|
||||
"""
|
||||
内部事件处理
|
||||
|
||||
Args:
|
||||
event_data: 事件数据
|
||||
"""
|
||||
try:
|
||||
event_type = event_data.get("type")
|
||||
event_payload = event_data.get("payload", {})
|
||||
event_priority = event_data.get("priority", 0)
|
||||
event_timestamp = event_data.get("timestamp", time.time())
|
||||
|
||||
# 应用事件过滤器
|
||||
if self.event_config["enable_event_filtering"]:
|
||||
if not self._apply_event_filters(event_type, event_payload):
|
||||
# 事件被过滤掉
|
||||
return
|
||||
|
||||
# 查找事件处理器
|
||||
if event_type in self.event_handlers:
|
||||
handlers = self.event_handlers[event_type]
|
||||
|
||||
# 按优先级排序处理器
|
||||
if self.event_config["enable_event_prioritization"]:
|
||||
handlers = sorted(handlers, key=lambda x: x.get("priority", 0), reverse=True)
|
||||
|
||||
# 调用所有处理器
|
||||
for handler_info in handlers:
|
||||
try:
|
||||
handler_func = handler_info["function"]
|
||||
handler_result = handler_func(event_payload)
|
||||
|
||||
# 检查是否需要停止传播
|
||||
if handler_result is False:
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器执行失败: {event_type} - {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
# 触发事件处理回调
|
||||
self._trigger_event_callback("event_processed", {
|
||||
"event_type": event_type,
|
||||
"event_payload": event_payload,
|
||||
"processing_time": time.time() - event_timestamp,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 内部事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _apply_event_filters(self, event_type: str, event_payload: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
应用事件过滤器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
event_payload: 事件载荷
|
||||
|
||||
Returns:
|
||||
是否通过过滤器
|
||||
"""
|
||||
try:
|
||||
if event_type in self.event_filters:
|
||||
filters = self.event_filters[event_type]
|
||||
for filter_func in filters:
|
||||
if not filter_func(event_payload):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件过滤器应用失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
return True
|
||||
|
||||
def emit_event(self, event_type: str, event_payload: Dict[str, Any] = None,
|
||||
priority: int = 0, async_process: bool = None) -> bool:
|
||||
"""
|
||||
发出事件
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
event_payload: 事件载荷
|
||||
priority: 事件优先级
|
||||
async_process: 是否异步处理
|
||||
|
||||
Returns:
|
||||
是否发出成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled or not self.event_config["enable_event_system"]:
|
||||
return False
|
||||
|
||||
# 使用默认异步处理设置或指定设置
|
||||
if async_process is None:
|
||||
async_process = self.event_config["enable_async_processing"]
|
||||
|
||||
event_data = {
|
||||
"type": event_type,
|
||||
"payload": event_payload or {},
|
||||
"priority": priority,
|
||||
"timestamp": time.time(),
|
||||
"async": async_process
|
||||
}
|
||||
|
||||
# 触发事件接收回调
|
||||
self._trigger_event_callback("event_received", {
|
||||
"event_type": event_type,
|
||||
"event_payload": event_payload,
|
||||
"priority": priority,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 更新统计
|
||||
self.event_stats["events_received"] += 1
|
||||
|
||||
if async_process:
|
||||
# 异步处理:添加到队列
|
||||
try:
|
||||
self.event_queue.put_nowait(event_data)
|
||||
self.event_stats["async_events"] += 1
|
||||
return True
|
||||
except queue.Full:
|
||||
# 队列已满,丢弃事件
|
||||
self.event_stats["events_dropped"] += 1
|
||||
self.event_state["dropped_events"] += 1
|
||||
|
||||
# 触发事件丢弃回调
|
||||
self._trigger_event_callback("event_dropped", {
|
||||
"event_type": event_type,
|
||||
"event_payload": event_payload,
|
||||
"reason": "queue_full",
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return False
|
||||
else:
|
||||
# 同步处理:立即处理
|
||||
self._handle_event_internal(event_data)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件发出失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
return False
|
||||
|
||||
def register_event_handler(self, event_type: str, handler: Callable, priority: int = 0):
|
||||
"""
|
||||
注册事件处理器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
handler: 处理器函数
|
||||
priority: 处理器优先级
|
||||
"""
|
||||
try:
|
||||
if event_type not in self.event_handlers:
|
||||
self.event_handlers[event_type] = []
|
||||
|
||||
handler_info = {
|
||||
"function": handler,
|
||||
"priority": priority
|
||||
}
|
||||
|
||||
self.event_handlers[event_type].append(handler_info)
|
||||
print(f"✓ 事件处理器已注册: {event_type} (优先级: {priority})")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器注册失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def unregister_event_handler(self, event_type: str, handler: Callable):
|
||||
"""
|
||||
注销事件处理器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
handler: 处理器函数
|
||||
"""
|
||||
try:
|
||||
if event_type in self.event_handlers:
|
||||
handlers = self.event_handlers[event_type]
|
||||
for i, handler_info in enumerate(handlers):
|
||||
if handler_info["function"] == handler:
|
||||
del handlers[i]
|
||||
print(f"✓ 事件处理器已注销: {event_type}")
|
||||
return
|
||||
|
||||
print(f"✗ 事件处理器不存在: {event_type}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件处理器注销失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def register_event_filter(self, event_type: str, filter_func: Callable):
|
||||
"""
|
||||
注册事件过滤器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
filter_func: 过滤器函数
|
||||
"""
|
||||
try:
|
||||
if event_type not in self.event_filters:
|
||||
self.event_filters[event_type] = []
|
||||
|
||||
self.event_filters[event_type].append(filter_func)
|
||||
print(f"✓ 事件过滤器已注册: {event_type}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件过滤器注册失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def unregister_event_filter(self, event_type: str, filter_func: Callable):
|
||||
"""
|
||||
注销事件过滤器
|
||||
|
||||
Args:
|
||||
event_type: 事件类型
|
||||
filter_func: 过滤器函数
|
||||
"""
|
||||
try:
|
||||
if event_type in self.event_filters:
|
||||
filters = self.event_filters[event_type]
|
||||
if filter_func in filters:
|
||||
filters.remove(filter_func)
|
||||
print(f"✓ 事件过滤器已注销: {event_type}")
|
||||
return
|
||||
|
||||
print(f"✗ 事件过滤器不存在: {event_type}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 事件过滤器注销失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
# 默认事件处理器
|
||||
def _handle_client_connected(self, payload: Dict[str, Any]):
|
||||
"""处理客户端连接事件"""
|
||||
try:
|
||||
client_id = payload.get("client_id")
|
||||
connection_data = payload.get("connection_data")
|
||||
|
||||
# 添加客户端到客户端管理器
|
||||
if self.plugin.client_manager:
|
||||
self.plugin.client_manager.add_client(client_id, {
|
||||
"connection_data": connection_data,
|
||||
"ip_address": connection_data.get("remote_address", "") if connection_data else ""
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端连接事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_client_disconnected(self, payload: Dict[str, Any]):
|
||||
"""处理客户端断开连接事件"""
|
||||
try:
|
||||
client_id = payload.get("client_id")
|
||||
reason = payload.get("reason", "unknown")
|
||||
|
||||
# 从客户端管理器移除客户端
|
||||
if self.plugin.client_manager:
|
||||
self.plugin.client_manager.remove_client(client_id, reason)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端断开连接事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_message_received(self, payload: Dict[str, Any]):
|
||||
"""处理消息接收事件"""
|
||||
try:
|
||||
client_id = payload.get("client_id")
|
||||
message = payload.get("message")
|
||||
|
||||
# 将消息传递给消息路由器
|
||||
if self.plugin.message_router:
|
||||
self.plugin.message_router.route_message(client_id, message)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息接收事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_room_created(self, payload: Dict[str, Any]):
|
||||
"""处理房间创建事件"""
|
||||
try:
|
||||
room_id = payload.get("room_id")
|
||||
room_name = payload.get("room_name")
|
||||
|
||||
# 可以在这里添加额外的房间创建逻辑
|
||||
print(f"房间已创建: {room_name} ({room_id})")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间创建事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_room_destroyed(self, payload: Dict[str, Any]):
|
||||
"""处理房间销毁事件"""
|
||||
try:
|
||||
room_id = payload.get("room_id")
|
||||
room_name = payload.get("room_name")
|
||||
|
||||
# 可以在这里添加额外的房间销毁逻辑
|
||||
print(f"房间已销毁: {room_name} ({room_id})")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间销毁事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_client_joined_room(self, payload: Dict[str, Any]):
|
||||
"""处理客户端加入房间事件"""
|
||||
try:
|
||||
room_id = payload.get("room_id")
|
||||
client_id = payload.get("client_id")
|
||||
|
||||
# 可以在这里添加额外的客户端加入房间逻辑
|
||||
print(f"客户端 {client_id} 已加入房间 {room_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端加入房间事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def _handle_client_left_room(self, payload: Dict[str, Any]):
|
||||
"""处理客户端离开房间事件"""
|
||||
try:
|
||||
room_id = payload.get("room_id")
|
||||
client_id = payload.get("client_id")
|
||||
|
||||
# 可以在这里添加额外的客户端离开房间逻辑
|
||||
print(f"客户端 {client_id} 已离开房间 {room_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 客户端离开房间事件处理失败: {e}")
|
||||
self.event_stats["handler_errors"] += 1
|
||||
|
||||
def get_event_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取事件统计信息
|
||||
|
||||
Returns:
|
||||
事件统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.event_state.copy(),
|
||||
"stats": self.event_stats.copy(),
|
||||
"config": self.event_config.copy(),
|
||||
"pending_events": self.event_queue.qsize()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置事件统计信息"""
|
||||
try:
|
||||
self.event_stats = {
|
||||
"events_received": 0,
|
||||
"events_processed": 0,
|
||||
"events_dropped": 0,
|
||||
"handler_errors": 0,
|
||||
"async_events": 0
|
||||
}
|
||||
print("✓ 事件统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件统计信息重置失败: {e}")
|
||||
|
||||
def set_event_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置事件配置
|
||||
|
||||
Args:
|
||||
config: 事件配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.event_config.update(config)
|
||||
print(f"✓ 事件配置已更新: {self.event_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 事件配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_event_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取事件配置
|
||||
|
||||
Returns:
|
||||
事件配置字典
|
||||
"""
|
||||
return self.event_config.copy()
|
||||
|
||||
def _trigger_event_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发事件回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.event_callbacks:
|
||||
for callback in self.event_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 事件回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件回调触发失败: {e}")
|
||||
|
||||
def register_event_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册事件回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.event_callbacks:
|
||||
self.event_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 事件回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件回调注册失败: {e}")
|
||||
|
||||
def unregister_event_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销事件回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.event_callbacks:
|
||||
if callback in self.event_callbacks[callback_type]:
|
||||
self.event_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 事件回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 事件回调注销失败: {e}")
|
||||
771
plugins/user/realtime_communication/messaging/message_router.py
Normal file
771
plugins/user/realtime_communication/messaging/message_router.py
Normal file
@ -0,0 +1,771 @@
|
||||
"""
|
||||
消息路由器模块
|
||||
处理客户端间的消息传递
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class MessageRouter:
|
||||
"""
|
||||
消息路由器
|
||||
处理客户端间的消息传递
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化消息路由器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 消息路由配置
|
||||
self.message_config = {
|
||||
"enable_message_filtering": True,
|
||||
"max_message_size": 65536, # 64KB
|
||||
"enable_message_queue": True,
|
||||
"message_queue_size": 10000,
|
||||
"enable_broadcast_optimization": True,
|
||||
"enable_message_compression": True,
|
||||
"enable_rate_limiting": True,
|
||||
"max_messages_per_second_per_client": 100,
|
||||
"enable_message_logging": False
|
||||
}
|
||||
|
||||
# 消息路由状态
|
||||
self.router_state = {
|
||||
"is_processing": False,
|
||||
"pending_messages": 0,
|
||||
"active_routes": 0,
|
||||
"last_message_time": 0.0
|
||||
}
|
||||
|
||||
# 消息路由统计
|
||||
self.message_stats = {
|
||||
"messages_routed": 0,
|
||||
"messages_broadcast": 0,
|
||||
"messages_filtered": 0,
|
||||
"messages_dropped": 0,
|
||||
"bytes_routed": 0,
|
||||
"routing_errors": 0
|
||||
}
|
||||
|
||||
# 消息处理器存储
|
||||
self.message_handlers = {}
|
||||
|
||||
# 消息队列
|
||||
self.message_queue = []
|
||||
self.message_queue_lock = threading.RLock()
|
||||
|
||||
# 路由表
|
||||
self.routing_table = {}
|
||||
|
||||
# 回调函数
|
||||
self.message_callbacks = {
|
||||
"message_routed": [],
|
||||
"message_broadcast": [],
|
||||
"message_filtered": [],
|
||||
"message_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_queue_process = 0.0
|
||||
self.last_stats_reset = 0.0
|
||||
|
||||
print("✓ 消息路由器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化消息路由器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化消息路由器...")
|
||||
|
||||
# 注册默认消息处理器
|
||||
self._register_default_handlers()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 消息路由器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息路由器初始化失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _register_default_handlers(self):
|
||||
"""注册默认消息处理器"""
|
||||
try:
|
||||
# 注册系统消息处理器
|
||||
self.register_message_handler("ping", self._handle_ping_message)
|
||||
self.register_message_handler("pong", self._handle_pong_message)
|
||||
self.register_message_handler("chat", self._handle_chat_message)
|
||||
self.register_message_handler("join_room", self._handle_join_room_message)
|
||||
self.register_message_handler("leave_room", self._handle_leave_room_message)
|
||||
self.register_message_handler("broadcast", self._handle_broadcast_message)
|
||||
|
||||
print("✓ 默认消息处理器已注册")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 默认消息处理器注册失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用消息路由器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 消息路由器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 消息路由器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息路由器启用失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用消息路由器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 清空消息队列
|
||||
with self.message_queue_lock:
|
||||
self.message_queue.clear()
|
||||
|
||||
print("✓ 消息路由器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息路由器禁用失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理消息路由器资源"""
|
||||
try:
|
||||
# 禁用消息路由器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调和处理器
|
||||
self.message_callbacks.clear()
|
||||
self.message_handlers.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 消息路由器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息路由器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新消息路由器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 处理消息队列
|
||||
if self.message_config["enable_message_queue"]:
|
||||
self._process_message_queue()
|
||||
|
||||
self.router_state["last_message_time"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息路由器更新失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _process_message_queue(self):
|
||||
"""处理消息队列"""
|
||||
try:
|
||||
if not self.message_queue:
|
||||
return
|
||||
|
||||
with self.message_queue_lock:
|
||||
messages_to_process = self.message_queue[:]
|
||||
self.message_queue.clear()
|
||||
|
||||
for message_data in messages_to_process:
|
||||
try:
|
||||
client_id = message_data.get("client_id")
|
||||
message = message_data.get("message")
|
||||
|
||||
# 处理消息
|
||||
self._route_message_internal(client_id, message)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 队列消息处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
|
||||
self.router_state["pending_messages"] = len(self.message_queue)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息队列处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
|
||||
def register_message_handler(self, message_type: str, handler: callable):
|
||||
"""
|
||||
注册消息处理器
|
||||
|
||||
Args:
|
||||
message_type: 消息类型
|
||||
handler: 处理器函数
|
||||
"""
|
||||
try:
|
||||
self.message_handlers[message_type] = handler
|
||||
print(f"✓ 消息处理器已注册: {message_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 消息处理器注册失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
|
||||
def unregister_message_handler(self, message_type: str):
|
||||
"""
|
||||
注销消息处理器
|
||||
|
||||
Args:
|
||||
message_type: 消息类型
|
||||
"""
|
||||
try:
|
||||
if message_type in self.message_handlers:
|
||||
del self.message_handlers[message_type]
|
||||
print(f"✓ 消息处理器已注销: {message_type}")
|
||||
else:
|
||||
print(f"✗ 消息处理器不存在: {message_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 消息处理器注销失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
|
||||
def route_message(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
路由消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否路由成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 检查消息大小
|
||||
if self.message_config["enable_message_filtering"]:
|
||||
message_size = len(json.dumps(message, ensure_ascii=False).encode('utf-8'))
|
||||
if message_size > self.message_config["max_message_size"]:
|
||||
print(f"✗ 消息过大: {message_size} bytes")
|
||||
self.message_stats["messages_dropped"] += 1
|
||||
return False
|
||||
|
||||
# 如果启用消息队列,将消息加入队列
|
||||
if self.message_config["enable_message_queue"]:
|
||||
with self.message_queue_lock:
|
||||
if len(self.message_queue) >= self.message_config["message_queue_size"]:
|
||||
print("✗ 消息队列已满,丢弃消息")
|
||||
self.message_stats["messages_dropped"] += 1
|
||||
return False
|
||||
|
||||
self.message_queue.append({
|
||||
"client_id": client_id,
|
||||
"message": message,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
self.router_state["pending_messages"] = len(self.message_queue)
|
||||
return True
|
||||
else:
|
||||
# 直接处理消息
|
||||
return self._route_message_internal(client_id, message)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息路由失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def _route_message_internal(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
内部消息路由处理
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否路由成功
|
||||
"""
|
||||
try:
|
||||
# 更新统计信息
|
||||
self.message_stats["messages_routed"] += 1
|
||||
message_size = len(json.dumps(message, ensure_ascii=False).encode('utf-8'))
|
||||
self.message_stats["bytes_routed"] += message_size
|
||||
|
||||
# 触发消息路由回调
|
||||
self._trigger_message_callback("message_routed", {
|
||||
"client_id": client_id,
|
||||
"message": message,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 获取消息类型
|
||||
message_type = message.get("type", "unknown")
|
||||
|
||||
# 查找对应的消息处理器
|
||||
if message_type in self.message_handlers:
|
||||
try:
|
||||
# 调用消息处理器
|
||||
handler_result = self.message_handlers[message_type](client_id, message)
|
||||
return handler_result if handler_result is not None else True
|
||||
except Exception as e:
|
||||
print(f"✗ 消息处理器执行失败: {message_type} - {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
else:
|
||||
# 默认处理:广播给所有客户端(除了发送者)
|
||||
return self._handle_default_message(client_id, message)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 内部消息路由处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def _handle_default_message(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
处理默认消息(广播给其他客户端)
|
||||
|
||||
Args:
|
||||
client_id: 发送客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否处理成功
|
||||
"""
|
||||
try:
|
||||
# 广播消息给所有其他客户端
|
||||
if self.plugin.websocket_server:
|
||||
broadcast_success = self.plugin.websocket_server.broadcast_message(
|
||||
message, exclude_client_id=client_id)
|
||||
if broadcast_success:
|
||||
self.message_stats["messages_broadcast"] += 1
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 默认消息处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
# 默认消息处理器
|
||||
def _handle_ping_message(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
处理ping消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否处理成功
|
||||
"""
|
||||
try:
|
||||
# 更新客户端心跳
|
||||
if self.plugin.client_manager:
|
||||
self.plugin.client_manager.update_client_heartbeat(client_id)
|
||||
|
||||
# 回复pong消息
|
||||
pong_message = {
|
||||
"type": "pong",
|
||||
"timestamp": time.time(),
|
||||
"ping_timestamp": message.get("timestamp", 0)
|
||||
}
|
||||
|
||||
if self.plugin.websocket_server:
|
||||
return self.plugin.websocket_server.send_message_to_client(client_id, pong_message)
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ ping消息处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def _handle_pong_message(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
处理pong消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否处理成功
|
||||
"""
|
||||
try:
|
||||
# 更新客户端心跳
|
||||
if self.plugin.client_manager:
|
||||
self.plugin.client_manager.update_client_heartbeat(client_id)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ pong消息处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def _handle_chat_message(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
处理聊天消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否处理成功
|
||||
"""
|
||||
try:
|
||||
# 获取客户端信息
|
||||
client_data = self.plugin.client_manager.get_client(client_id) if self.plugin.client_manager else None
|
||||
if not client_data:
|
||||
return False
|
||||
|
||||
# 添加发送者信息
|
||||
message["sender_id"] = client_id
|
||||
message["sender_name"] = client_data.get("username", "Unknown")
|
||||
message["sender_time"] = time.time()
|
||||
|
||||
# 广播聊天消息
|
||||
if self.plugin.websocket_server:
|
||||
broadcast_success = self.plugin.websocket_server.broadcast_message(message)
|
||||
if broadcast_success:
|
||||
self.message_stats["messages_broadcast"] += 1
|
||||
return broadcast_success
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 聊天消息处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def _handle_join_room_message(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
处理加入房间消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否处理成功
|
||||
"""
|
||||
try:
|
||||
room_id = message.get("room_id")
|
||||
if not room_id:
|
||||
return False
|
||||
|
||||
# 使用房间管理器处理加入房间请求
|
||||
if self.plugin.room_manager:
|
||||
join_success = self.plugin.room_manager.add_client_to_room(room_id, client_id)
|
||||
if join_success:
|
||||
# 通知客户端加入成功
|
||||
response_message = {
|
||||
"type": "room_joined",
|
||||
"room_id": room_id,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
if self.plugin.websocket_server:
|
||||
self.plugin.websocket_server.send_message_to_client(client_id, response_message)
|
||||
|
||||
return join_success
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 加入房间消息处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def _handle_leave_room_message(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
处理离开房间消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否处理成功
|
||||
"""
|
||||
try:
|
||||
room_id = message.get("room_id")
|
||||
if not room_id:
|
||||
return False
|
||||
|
||||
# 使用房间管理器处理离开房间请求
|
||||
if self.plugin.room_manager:
|
||||
leave_success = self.plugin.room_manager.remove_client_from_room(room_id, client_id)
|
||||
if leave_success:
|
||||
# 通知客户端离开成功
|
||||
response_message = {
|
||||
"type": "room_left",
|
||||
"room_id": room_id,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
if self.plugin.websocket_server:
|
||||
self.plugin.websocket_server.send_message_to_client(client_id, response_message)
|
||||
|
||||
return leave_success
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 离开房间消息处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def _handle_broadcast_message(self, client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
处理广播消息
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否处理成功
|
||||
"""
|
||||
try:
|
||||
# 广播消息给所有客户端
|
||||
if self.plugin.websocket_server:
|
||||
broadcast_success = self.plugin.websocket_server.broadcast_message(message)
|
||||
if broadcast_success:
|
||||
self.message_stats["messages_broadcast"] += 1
|
||||
return broadcast_success
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 广播消息处理失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def send_direct_message(self, from_client_id: str, to_client_id: str, message: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
发送直接消息
|
||||
|
||||
Args:
|
||||
from_client_id: 发送客户端ID
|
||||
to_client_id: 接收客户端ID
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
是否发送成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 添加发送者信息
|
||||
message["sender_id"] = from_client_id
|
||||
message["timestamp"] = time.time()
|
||||
|
||||
# 发送消息到目标客户端
|
||||
if self.plugin.websocket_server:
|
||||
send_success = self.plugin.websocket_server.send_message_to_client(to_client_id, message)
|
||||
if send_success:
|
||||
self.message_stats["messages_routed"] += 1
|
||||
return send_success
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 直接消息发送失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def broadcast_to_room(self, room_id: str, message: Dict[str, Any], exclude_client_id: str = None) -> bool:
|
||||
"""
|
||||
广播消息到房间
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
message: 消息数据
|
||||
exclude_client_id: 要排除的客户端ID
|
||||
|
||||
Returns:
|
||||
是否广播成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 使用房间管理器获取房间内的客户端
|
||||
if self.plugin.room_manager:
|
||||
room_clients = self.plugin.room_manager.get_room_clients(room_id)
|
||||
if not room_clients:
|
||||
return False
|
||||
|
||||
success_count = 0
|
||||
for client_id in room_clients:
|
||||
# 跳过排除的客户端
|
||||
if client_id == exclude_client_id:
|
||||
continue
|
||||
|
||||
# 发送消息
|
||||
if self.plugin.websocket_server:
|
||||
send_success = self.plugin.websocket_server.send_message_to_client(client_id, message)
|
||||
if send_success:
|
||||
success_count += 1
|
||||
|
||||
return success_count > 0
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间广播失败: {e}")
|
||||
self.message_stats["routing_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_message_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取消息统计信息
|
||||
|
||||
Returns:
|
||||
消息统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.router_state.copy(),
|
||||
"stats": self.message_stats.copy(),
|
||||
"config": self.message_config.copy()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置消息统计信息"""
|
||||
try:
|
||||
self.message_stats = {
|
||||
"messages_routed": 0,
|
||||
"messages_broadcast": 0,
|
||||
"messages_filtered": 0,
|
||||
"messages_dropped": 0,
|
||||
"bytes_routed": 0,
|
||||
"routing_errors": 0
|
||||
}
|
||||
print("✓ 消息统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 消息统计信息重置失败: {e}")
|
||||
|
||||
def set_message_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置消息配置
|
||||
|
||||
Args:
|
||||
config: 消息配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.message_config.update(config)
|
||||
print(f"✓ 消息配置已更新: {self.message_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 消息配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_message_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取消息配置
|
||||
|
||||
Returns:
|
||||
消息配置字典
|
||||
"""
|
||||
return self.message_config.copy()
|
||||
|
||||
def _trigger_message_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发消息回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.message_callbacks:
|
||||
for callback in self.message_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 消息回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 消息回调触发失败: {e}")
|
||||
|
||||
def register_message_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册消息回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.message_callbacks:
|
||||
self.message_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 消息回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 消息回调注册失败: {e}")
|
||||
|
||||
def unregister_message_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销消息回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.message_callbacks:
|
||||
if callback in self.message_callbacks[callback_type]:
|
||||
self.message_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 消息回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 消息回调注销失败: {e}")
|
||||
@ -0,0 +1,825 @@
|
||||
"""
|
||||
通信监控模块
|
||||
实时监控通信性能和记录日志
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, Any, List, Optional
|
||||
from collections import deque
|
||||
|
||||
class CommunicationMonitor:
|
||||
"""
|
||||
通信监控器
|
||||
实时监控通信性能和记录日志
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化通信监控器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 监控配置
|
||||
self.monitor_config = {
|
||||
"enable_monitoring": True,
|
||||
"monitoring_interval": 5.0,
|
||||
"log_level": "INFO",
|
||||
"enable_file_logging": True,
|
||||
"log_file_path": "/home/hello/EG/plugins/user/realtime_communication/logs/communication_monitor.log",
|
||||
"max_log_file_size": 10485760, # 10MB
|
||||
"enable_performance_monitoring": True,
|
||||
"enable_alerts": True,
|
||||
"alert_thresholds": {
|
||||
"cpu_usage": 80.0,
|
||||
"memory_usage": 85.0,
|
||||
"network_latency": 100.0,
|
||||
"error_rate": 5.0,
|
||||
"message_queue_size": 1000
|
||||
},
|
||||
"enable_metrics_collection": True,
|
||||
"metrics_retention_period": 3600, # 1小时
|
||||
"enable_realtime_dashboard": True
|
||||
}
|
||||
|
||||
# 性能指标存储
|
||||
self.performance_metrics = {
|
||||
"cpu_usage": deque(maxlen=1000),
|
||||
"memory_usage": deque(maxlen=1000),
|
||||
"network_in": deque(maxlen=1000),
|
||||
"network_out": deque(maxlen=1000),
|
||||
"active_connections": deque(maxlen=1000),
|
||||
"messages_per_second": deque(maxlen=1000),
|
||||
"message_queue_size": deque(maxlen=1000),
|
||||
"error_rate": deque(maxlen=1000)
|
||||
}
|
||||
|
||||
# 监控状态
|
||||
self.monitor_state = {
|
||||
"last_monitoring_update": 0.0,
|
||||
"last_performance_check": 0.0,
|
||||
"total_logs": 0,
|
||||
"total_alerts": 0,
|
||||
"active_alerts": 0
|
||||
}
|
||||
|
||||
# 警报系统
|
||||
self.active_alerts = {}
|
||||
self.alert_history = deque(maxlen=1000)
|
||||
|
||||
# 日志文件
|
||||
self.log_file = None
|
||||
self.log_file_size = 0
|
||||
|
||||
# 监控统计
|
||||
self.monitor_stats = {
|
||||
"metrics_collected": 0,
|
||||
"logs_written": 0,
|
||||
"alerts_generated": 0,
|
||||
"alerts_resolved": 0,
|
||||
"performance_checks": 0,
|
||||
"monitor_errors": 0
|
||||
}
|
||||
|
||||
# 线程锁
|
||||
self.monitor_lock = threading.RLock()
|
||||
|
||||
# 回调函数
|
||||
self.monitor_callbacks = {
|
||||
"metric_collected": [],
|
||||
"alert_triggered": [],
|
||||
"alert_resolved": [],
|
||||
"log_entry": [],
|
||||
"performance_degraded": []
|
||||
}
|
||||
|
||||
# 监控线程
|
||||
self.monitor_thread = None
|
||||
self.monitor_thread_running = False
|
||||
|
||||
# 时间戳记录
|
||||
self.last_log_write = 0.0
|
||||
self.last_metric_collection = 0.0
|
||||
|
||||
print("✓ 通信监控器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化通信监控器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化通信监控器...")
|
||||
|
||||
# 创建日志目录
|
||||
log_dir = os.path.dirname(self.monitor_config["log_file_path"])
|
||||
if not os.path.exists(log_dir):
|
||||
os.makedirs(log_dir)
|
||||
|
||||
# 初始化日志文件
|
||||
if self.monitor_config["enable_file_logging"]:
|
||||
self._initialize_log_file()
|
||||
|
||||
# 启动监控线程
|
||||
self._start_monitor_thread()
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 通信监控器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信监控器初始化失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _initialize_log_file(self):
|
||||
"""初始化日志文件"""
|
||||
try:
|
||||
# 检查文件是否存在
|
||||
if os.path.exists(self.monitor_config["log_file_path"]):
|
||||
self.log_file_size = os.path.getsize(self.monitor_config["log_file_path"])
|
||||
|
||||
# 打开日志文件
|
||||
self.log_file = open(self.monitor_config["log_file_path"], "a", encoding="utf-8")
|
||||
print(f"✓ 日志文件已初始化: {self.monitor_config['log_file_path']}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 日志文件初始化失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _start_monitor_thread(self):
|
||||
"""启动监控线程"""
|
||||
try:
|
||||
self.monitor_thread_running = True
|
||||
self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
|
||||
self.monitor_thread.start()
|
||||
print("✓ 监控线程已启动")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控线程启动失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _monitor_loop(self):
|
||||
"""监控线程循环"""
|
||||
try:
|
||||
while self.monitor_thread_running:
|
||||
try:
|
||||
if self.enabled and self.monitor_config["enable_monitoring"]:
|
||||
current_time = time.time()
|
||||
|
||||
# 收集性能指标
|
||||
if current_time - self.last_metric_collection >= self.monitor_config["monitoring_interval"]:
|
||||
self._collect_performance_metrics()
|
||||
self.last_metric_collection = current_time
|
||||
|
||||
# 检查警报
|
||||
self._check_alerts()
|
||||
|
||||
# 检查日志文件大小
|
||||
self._check_log_file_size()
|
||||
|
||||
# 短暂休眠
|
||||
time.sleep(1.0)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 监控循环错误: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
time.sleep(5.0) # 出错时延长休眠
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 监控线程失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用通信监控器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 通信监控器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 通信监控器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信监控器启用失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用通信监控器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 停止监控线程
|
||||
if self.monitor_thread_running:
|
||||
self.monitor_thread_running = False
|
||||
if self.monitor_thread and self.monitor_thread.is_alive():
|
||||
self.monitor_thread.join(timeout=5.0)
|
||||
|
||||
# 关闭日志文件
|
||||
if self.log_file:
|
||||
self.log_file.close()
|
||||
self.log_file = None
|
||||
|
||||
print("✓ 通信监控器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信监控器禁用失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理通信监控器资源"""
|
||||
try:
|
||||
# 禁用通信监控器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.monitor_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 通信监控器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信监控器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新通信监控器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
self.monitor_state["last_monitoring_update"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通信监控器更新失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _collect_performance_metrics(self):
|
||||
"""收集性能指标"""
|
||||
try:
|
||||
current_time = time.time()
|
||||
metrics = {}
|
||||
|
||||
# 收集系统资源使用情况
|
||||
try:
|
||||
import psutil
|
||||
|
||||
# CPU使用率
|
||||
cpu_percent = psutil.cpu_percent(interval=0.1)
|
||||
metrics["cpu_usage"] = cpu_percent
|
||||
self.performance_metrics["cpu_usage"].append((current_time, cpu_percent))
|
||||
|
||||
# 内存使用率
|
||||
memory_info = psutil.virtual_memory()
|
||||
memory_percent = memory_info.percent
|
||||
metrics["memory_usage"] = memory_percent
|
||||
self.performance_metrics["memory_usage"].append((current_time, memory_percent))
|
||||
|
||||
# 网络使用情况
|
||||
net_io = psutil.net_io_counters()
|
||||
metrics["network_in"] = net_io.bytes_recv
|
||||
metrics["network_out"] = net_io.bytes_sent
|
||||
self.performance_metrics["network_in"].append((current_time, net_io.bytes_recv))
|
||||
self.performance_metrics["network_out"].append((current_time, net_io.bytes_sent))
|
||||
|
||||
except ImportError:
|
||||
# 如果没有psutil,使用简化的指标
|
||||
metrics["cpu_usage"] = 0.0
|
||||
metrics["memory_usage"] = 0.0
|
||||
metrics["network_in"] = 0
|
||||
metrics["network_out"] = 0
|
||||
|
||||
# 收集服务器指标
|
||||
if self.plugin.websocket_server:
|
||||
server_stats = self.plugin.websocket_server.get_server_stats()
|
||||
server_state = server_stats.get("state", {})
|
||||
|
||||
# 活跃连接数
|
||||
active_connections = server_state.get("current_connections", 0)
|
||||
metrics["active_connections"] = active_connections
|
||||
self.performance_metrics["active_connections"].append((current_time, active_connections))
|
||||
|
||||
# 数据传输量
|
||||
bytes_sent = server_state.get("bytes_sent", 0)
|
||||
bytes_received = server_state.get("bytes_received", 0)
|
||||
metrics["bytes_sent"] = bytes_sent
|
||||
metrics["bytes_received"] = bytes_received
|
||||
|
||||
# 收集客户端指标
|
||||
if self.plugin.client_manager:
|
||||
client_stats = self.plugin.client_manager.get_client_stats()
|
||||
client_state = client_stats.get("state", {})
|
||||
client_count = client_state.get("current_clients", 0)
|
||||
metrics["client_count"] = client_count
|
||||
|
||||
# 收集消息指标
|
||||
if self.plugin.message_router:
|
||||
message_stats = self.plugin.message_router.get_message_stats()
|
||||
message_state = message_stats.get("state", {})
|
||||
message_stats_data = message_stats.get("stats", {})
|
||||
|
||||
# 消息队列大小
|
||||
pending_messages = message_state.get("pending_messages", 0)
|
||||
metrics["message_queue_size"] = pending_messages
|
||||
self.performance_metrics["message_queue_size"].append((current_time, pending_messages))
|
||||
|
||||
# 消息处理速率
|
||||
messages_routed = message_stats_data.get("messages_routed", 0)
|
||||
if hasattr(self, '_last_messages_routed'):
|
||||
mps = (messages_routed - self._last_messages_routed) / self.monitor_config["monitoring_interval"]
|
||||
metrics["messages_per_second"] = max(0, mps)
|
||||
self.performance_metrics["messages_per_second"].append((current_time, metrics["messages_per_second"]))
|
||||
else:
|
||||
metrics["messages_per_second"] = 0
|
||||
self.performance_metrics["messages_per_second"].append((current_time, 0))
|
||||
|
||||
self._last_messages_routed = messages_routed
|
||||
|
||||
# 收集房间指标
|
||||
if self.plugin.room_manager:
|
||||
room_stats = self.plugin.room_manager.get_room_stats()
|
||||
room_state = room_stats.get("state", {})
|
||||
active_rooms = room_state.get("active_rooms", 0)
|
||||
metrics["active_rooms"] = active_rooms
|
||||
|
||||
# 更新统计
|
||||
self.monitor_stats["metrics_collected"] += 1
|
||||
self.last_metric_collection = current_time
|
||||
|
||||
# 触发指标收集回调
|
||||
self._trigger_monitor_callback("metric_collected", {
|
||||
"metrics": metrics,
|
||||
"timestamp": current_time
|
||||
})
|
||||
|
||||
# 记录日志
|
||||
if self._should_log("DEBUG"):
|
||||
self._write_log("DEBUG", f"性能指标收集: {metrics}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 性能指标收集失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _check_alerts(self):
|
||||
"""检查警报条件"""
|
||||
try:
|
||||
if not self.monitor_config["enable_alerts"]:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
thresholds = self.monitor_config["alert_thresholds"]
|
||||
|
||||
# 检查CPU使用率
|
||||
if self.performance_metrics["cpu_usage"]:
|
||||
latest_cpu = self.performance_metrics["cpu_usage"][-1][1]
|
||||
if latest_cpu > thresholds["cpu_usage"]:
|
||||
self._trigger_alert("high_cpu_usage", f"CPU使用率过高: {latest_cpu:.2f}%", current_time)
|
||||
|
||||
# 检查内存使用率
|
||||
if self.performance_metrics["memory_usage"]:
|
||||
latest_memory = self.performance_metrics["memory_usage"][-1][1]
|
||||
if latest_memory > thresholds["memory_usage"]:
|
||||
self._trigger_alert("high_memory_usage", f"内存使用率过高: {latest_memory:.2f}%", current_time)
|
||||
|
||||
# 检查消息队列大小
|
||||
if self.performance_metrics["message_queue_size"]:
|
||||
latest_queue_size = self.performance_metrics["message_queue_size"][-1][1]
|
||||
if latest_queue_size > thresholds["message_queue_size"]:
|
||||
self._trigger_alert("high_message_queue", f"消息队列过大: {latest_queue_size}", current_time)
|
||||
|
||||
# 检查错误率
|
||||
if self.performance_metrics["error_rate"]:
|
||||
latest_error_rate = self.performance_metrics["error_rate"][-1][1]
|
||||
if latest_error_rate > thresholds["error_rate"]:
|
||||
self._trigger_alert("high_error_rate", f"错误率过高: {latest_error_rate:.2f}%", current_time)
|
||||
|
||||
# 检查活跃连接数
|
||||
if self.performance_metrics["active_connections"]:
|
||||
latest_connections = self.performance_metrics["active_connections"][-1][1]
|
||||
if self.plugin.websocket_server:
|
||||
max_connections = self.plugin.websocket_server.websocket_config.get("max_connections", 1000)
|
||||
if latest_connections > max_connections * 0.9: # 90%阈值
|
||||
self._trigger_alert("high_connections", f"连接数接近上限: {latest_connections}/{max_connections}", current_time)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 警报检查失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _trigger_alert(self, alert_type: str, message: str, timestamp: float = None):
|
||||
"""
|
||||
触发警报
|
||||
|
||||
Args:
|
||||
alert_type: 警报类型
|
||||
message: 警报消息
|
||||
timestamp: 时间戳
|
||||
"""
|
||||
try:
|
||||
if timestamp is None:
|
||||
timestamp = time.time()
|
||||
|
||||
alert_id = f"{alert_type}_{int(timestamp)}"
|
||||
|
||||
# 检查是否已存在相同类型的活动警报
|
||||
with self.monitor_lock:
|
||||
if alert_type in self.active_alerts:
|
||||
# 更新现有警报
|
||||
self.active_alerts[alert_type]["count"] += 1
|
||||
self.active_alerts[alert_type]["last_triggered"] = timestamp
|
||||
else:
|
||||
# 创建新警报
|
||||
self.active_alerts[alert_type] = {
|
||||
"id": alert_id,
|
||||
"type": alert_type,
|
||||
"message": message,
|
||||
"first_triggered": timestamp,
|
||||
"last_triggered": timestamp,
|
||||
"count": 1,
|
||||
"resolved": False
|
||||
}
|
||||
|
||||
self.monitor_state["active_alerts"] += 1
|
||||
self.monitor_stats["alerts_generated"] += 1
|
||||
|
||||
# 添加到警报历史
|
||||
self.alert_history.append({
|
||||
"id": alert_id,
|
||||
"type": alert_type,
|
||||
"message": message,
|
||||
"timestamp": timestamp,
|
||||
"resolved": False
|
||||
})
|
||||
|
||||
# 触发警报回调
|
||||
self._trigger_monitor_callback("alert_triggered", {
|
||||
"alert_id": alert_id,
|
||||
"alert_type": alert_type,
|
||||
"message": message,
|
||||
"timestamp": timestamp
|
||||
})
|
||||
|
||||
# 记录日志
|
||||
self._write_log("WARNING", f"警报触发 [{alert_type}]: {message}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 警报触发失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def resolve_alert(self, alert_type: str):
|
||||
"""
|
||||
解决警报
|
||||
|
||||
Args:
|
||||
alert_type: 警报类型
|
||||
"""
|
||||
try:
|
||||
with self.monitor_lock:
|
||||
if alert_type in self.active_alerts:
|
||||
alert_data = self.active_alerts[alert_type]
|
||||
alert_data["resolved"] = True
|
||||
alert_data["resolved_time"] = time.time()
|
||||
|
||||
self.monitor_state["active_alerts"] -= 1
|
||||
self.monitor_stats["alerts_resolved"] += 1
|
||||
|
||||
# 触发警报解决回调
|
||||
self._trigger_monitor_callback("alert_resolved", {
|
||||
"alert_type": alert_type,
|
||||
"alert_data": alert_data
|
||||
})
|
||||
|
||||
# 从活动警报中移除
|
||||
del self.active_alerts[alert_type]
|
||||
|
||||
# 记录日志
|
||||
self._write_log("INFO", f"警报已解决: {alert_type}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 警报解决失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _check_log_file_size(self):
|
||||
"""检查日志文件大小"""
|
||||
try:
|
||||
if not self.monitor_config["enable_file_logging"] or not self.log_file:
|
||||
return
|
||||
|
||||
# 检查文件大小
|
||||
if os.path.exists(self.monitor_config["log_file_path"]):
|
||||
current_size = os.path.getsize(self.monitor_config["log_file_path"])
|
||||
if current_size > self.monitor_config["max_log_file_size"]:
|
||||
# 轮转日志文件
|
||||
self._rotate_log_file()
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 日志文件大小检查失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _rotate_log_file(self):
|
||||
"""轮转日志文件"""
|
||||
try:
|
||||
if self.log_file:
|
||||
self.log_file.close()
|
||||
|
||||
# 重命名当前日志文件
|
||||
timestamp = int(time.time())
|
||||
rotated_filename = f"{self.monitor_config['log_file_path']}.{timestamp}"
|
||||
os.rename(self.monitor_config["log_file_path"], rotated_filename)
|
||||
|
||||
# 重新初始化日志文件
|
||||
self._initialize_log_file()
|
||||
|
||||
print(f"✓ 日志文件已轮转: {rotated_filename}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 日志文件轮转失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _write_log(self, level: str, message: str, extra_data: Dict[str, Any] = None):
|
||||
"""
|
||||
写入日志
|
||||
|
||||
Args:
|
||||
level: 日志级别
|
||||
message: 日志消息
|
||||
extra_data: 额外数据
|
||||
"""
|
||||
try:
|
||||
if not self._should_log(level):
|
||||
return
|
||||
|
||||
timestamp = time.time()
|
||||
log_entry = {
|
||||
"timestamp": timestamp,
|
||||
"level": level,
|
||||
"message": message,
|
||||
"extra_data": extra_data
|
||||
}
|
||||
|
||||
# 控制台输出
|
||||
print(f"[{level}] {message}")
|
||||
|
||||
# 文件日志
|
||||
if self.monitor_config["enable_file_logging"] and self.log_file:
|
||||
try:
|
||||
log_line = json.dumps(log_entry, ensure_ascii=False)
|
||||
self.log_file.write(log_line + "\n")
|
||||
self.log_file.flush()
|
||||
|
||||
self.log_file_size += len(log_line) + 1
|
||||
self.monitor_stats["logs_written"] += 1
|
||||
self.monitor_state["total_logs"] += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 文件日志写入失败: {e}")
|
||||
|
||||
# 触发日志条目回调
|
||||
self._trigger_monitor_callback("log_entry", log_entry)
|
||||
|
||||
self.last_log_write = timestamp
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 日志写入失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
|
||||
def _should_log(self, level: str) -> bool:
|
||||
"""
|
||||
检查是否应该记录指定级别的日志
|
||||
|
||||
Args:
|
||||
level: 日志级别
|
||||
|
||||
Returns:
|
||||
是否应该记录日志
|
||||
"""
|
||||
try:
|
||||
log_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
||||
current_level = self.monitor_config["log_level"]
|
||||
|
||||
if current_level not in log_levels:
|
||||
return True # 默认记录所有日志
|
||||
|
||||
if level not in log_levels:
|
||||
return True # 默认记录未知级别的日志
|
||||
|
||||
current_index = log_levels.index(current_level)
|
||||
level_index = log_levels.index(level)
|
||||
|
||||
# 只记录等于或高于当前级别的日志
|
||||
return level_index >= current_index
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 日志级别检查失败: {e}")
|
||||
return True
|
||||
|
||||
def get_performance_metrics(self, metric_name: str = None, limit: int = 100) -> Any:
|
||||
"""
|
||||
获取性能指标
|
||||
|
||||
Args:
|
||||
metric_name: 指标名称(可选)
|
||||
limit: 限制返回的数量
|
||||
|
||||
Returns:
|
||||
性能指标数据
|
||||
"""
|
||||
try:
|
||||
with self.monitor_lock:
|
||||
if metric_name:
|
||||
if metric_name in self.performance_metrics:
|
||||
metrics = list(self.performance_metrics[metric_name])
|
||||
return metrics[-limit:] if len(metrics) > limit else metrics
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
# 返回所有指标
|
||||
result = {}
|
||||
for name, metrics in self.performance_metrics.items():
|
||||
metric_list = list(metrics)
|
||||
result[name] = metric_list[-limit:] if len(metric_list) > limit else metric_list
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取性能指标失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
return {}
|
||||
|
||||
def get_active_alerts(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取活动警报
|
||||
|
||||
Returns:
|
||||
活动警报字典
|
||||
"""
|
||||
try:
|
||||
with self.monitor_lock:
|
||||
return self.active_alerts.copy()
|
||||
except Exception as e:
|
||||
print(f"✗ 获取活动警报失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
return {}
|
||||
|
||||
def get_alert_history(self, limit: int = 100) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取警报历史
|
||||
|
||||
Args:
|
||||
limit: 限制返回的数量
|
||||
|
||||
Returns:
|
||||
警报历史列表
|
||||
"""
|
||||
try:
|
||||
with self.monitor_lock:
|
||||
history = list(self.alert_history)
|
||||
return history[-limit:] if len(history) > limit else history
|
||||
except Exception as e:
|
||||
print(f"✗ 获取警报历史失败: {e}")
|
||||
self.monitor_stats["monitor_errors"] += 1
|
||||
return []
|
||||
|
||||
def get_monitor_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取监控统计信息
|
||||
|
||||
Returns:
|
||||
监控统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.monitor_state.copy(),
|
||||
"stats": self.monitor_stats.copy(),
|
||||
"config": self.monitor_config.copy(),
|
||||
"active_alerts_count": len(self.active_alerts),
|
||||
"alert_history_count": len(self.alert_history)
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置监控统计信息"""
|
||||
try:
|
||||
self.monitor_stats = {
|
||||
"metrics_collected": 0,
|
||||
"logs_written": 0,
|
||||
"alerts_generated": 0,
|
||||
"alerts_resolved": 0,
|
||||
"performance_checks": 0,
|
||||
"monitor_errors": 0
|
||||
}
|
||||
|
||||
self.monitor_state["total_logs"] = 0
|
||||
self.monitor_state["total_alerts"] = 0
|
||||
self.monitor_state["active_alerts"] = 0
|
||||
|
||||
print("✓ 监控统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控统计信息重置失败: {e}")
|
||||
|
||||
def set_monitor_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置监控配置
|
||||
|
||||
Args:
|
||||
config: 监控配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.monitor_config.update(config)
|
||||
print(f"✓ 监控配置已更新: {self.monitor_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 监控配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_monitor_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取监控配置
|
||||
|
||||
Returns:
|
||||
监控配置字典
|
||||
"""
|
||||
return self.monitor_config.copy()
|
||||
|
||||
def _trigger_monitor_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发监控回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.monitor_callbacks:
|
||||
for callback in self.monitor_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 监控回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控回调触发失败: {e}")
|
||||
|
||||
def register_monitor_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册监控回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.monitor_callbacks:
|
||||
self.monitor_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 监控回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控回调注册失败: {e}")
|
||||
|
||||
def unregister_monitor_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销监控回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.monitor_callbacks:
|
||||
if callback in self.monitor_callbacks[callback_type]:
|
||||
self.monitor_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 监控回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 监控回调注销失败: {e}")
|
||||
391
plugins/user/realtime_communication/plugin.py
Normal file
391
plugins/user/realtime_communication/plugin.py
Normal file
@ -0,0 +1,391 @@
|
||||
"""
|
||||
实时通信插件主文件
|
||||
为EG引擎提供实时通信功能
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict, Any
|
||||
|
||||
# 导入各个模块
|
||||
from .core.websocket_server import WebSocketServer
|
||||
from .clients.client_manager import ClientManager
|
||||
from .messaging.message_router import MessageRouter
|
||||
from .rooms.room_manager import RoomManager
|
||||
from .protocol.protocol_handler import ProtocolHandler
|
||||
from .auth.auth_manager import AuthManager
|
||||
from .serialization.data_serializer import DataSerializer
|
||||
from .monitoring.communication_monitor import CommunicationMonitor
|
||||
from .config.comm_config import CommConfig
|
||||
from .events.event_handler import EventHandler
|
||||
from .editor.comm_editor import CommEditor
|
||||
|
||||
class RealtimeCommunicationPlugin:
|
||||
"""
|
||||
实时通信插件主类
|
||||
整合所有通信功能模块
|
||||
"""
|
||||
|
||||
def __init__(self, engine):
|
||||
"""
|
||||
初始化实时通信插件
|
||||
|
||||
Args:
|
||||
engine: EG引擎实例
|
||||
"""
|
||||
self.engine = engine
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 插件信息
|
||||
self.plugin_info = {
|
||||
"name": "Realtime Communication Plugin",
|
||||
"version": "1.0.0",
|
||||
"author": "EG Plugin System",
|
||||
"description": "为EG引擎提供实时通信功能"
|
||||
}
|
||||
|
||||
# 插件状态
|
||||
self.plugin_state = {
|
||||
"initialized_modules": [],
|
||||
"last_update": 0.0,
|
||||
"total_messages": 0,
|
||||
"active_connections": 0
|
||||
}
|
||||
|
||||
# 插件统计
|
||||
self.plugin_stats = {
|
||||
"messages_sent": 0,
|
||||
"messages_received": 0,
|
||||
"connections_accepted": 0,
|
||||
"connections_dropped": 0,
|
||||
"errors": 0
|
||||
}
|
||||
|
||||
# 功能模块
|
||||
self.websocket_server = None
|
||||
self.client_manager = None
|
||||
self.message_router = None
|
||||
self.room_manager = None
|
||||
self.protocol_handler = None
|
||||
self.auth_manager = None
|
||||
self.data_serializer = None
|
||||
self.monitor = None
|
||||
self.config_manager = None
|
||||
self.event_handler = None
|
||||
self.editor = None
|
||||
|
||||
print("✓ 实时通信插件已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化插件
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化实时通信插件...")
|
||||
|
||||
# 初始化配置管理器
|
||||
self.config_manager = CommConfig(self)
|
||||
if self.config_manager.initialize():
|
||||
self.plugin_state["initialized_modules"].append("config_manager")
|
||||
else:
|
||||
print("✗ 配置管理器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化认证管理器
|
||||
self.auth_manager = AuthManager(self)
|
||||
if self.auth_manager.initialize():
|
||||
self.plugin_state["initialized_modules"].append("auth_manager")
|
||||
else:
|
||||
print("✗ 认证管理器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化数据序列化器
|
||||
self.data_serializer = DataSerializer(self)
|
||||
if self.data_serializer.initialize():
|
||||
self.plugin_state["initialized_modules"].append("data_serializer")
|
||||
else:
|
||||
print("✗ 数据序列化器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化协议处理器
|
||||
self.protocol_handler = ProtocolHandler(self)
|
||||
if self.protocol_handler.initialize():
|
||||
self.plugin_state["initialized_modules"].append("protocol_handler")
|
||||
else:
|
||||
print("✗ 协议处理器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化客户端管理器
|
||||
self.client_manager = ClientManager(self)
|
||||
if self.client_manager.initialize():
|
||||
self.plugin_state["initialized_modules"].append("client_manager")
|
||||
else:
|
||||
print("✗ 客户端管理器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化消息路由器
|
||||
self.message_router = MessageRouter(self)
|
||||
if self.message_router.initialize():
|
||||
self.plugin_state["initialized_modules"].append("message_router")
|
||||
else:
|
||||
print("✗ 消息路由器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化房间管理器
|
||||
self.room_manager = RoomManager(self)
|
||||
if self.room_manager.initialize():
|
||||
self.plugin_state["initialized_modules"].append("room_manager")
|
||||
else:
|
||||
print("✗ 房间管理器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化WebSocket服务器
|
||||
self.websocket_server = WebSocketServer(self)
|
||||
if self.websocket_server.initialize():
|
||||
self.plugin_state["initialized_modules"].append("websocket_server")
|
||||
else:
|
||||
print("✗ WebSocket服务器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化事件处理器
|
||||
self.event_handler = EventHandler(self)
|
||||
if self.event_handler.initialize():
|
||||
self.plugin_state["initialized_modules"].append("event_handler")
|
||||
else:
|
||||
print("✗ 事件处理器初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化监控系统
|
||||
self.monitor = CommunicationMonitor(self)
|
||||
if self.monitor.initialize():
|
||||
self.plugin_state["initialized_modules"].append("monitor")
|
||||
else:
|
||||
print("✗ 监控系统初始化失败")
|
||||
return False
|
||||
|
||||
# 初始化编辑器接口
|
||||
self.editor = CommEditor(self)
|
||||
if self.editor.initialize():
|
||||
self.plugin_state["initialized_modules"].append("editor")
|
||||
else:
|
||||
print("✗ 编辑器接口初始化失败")
|
||||
return False
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 实时通信插件初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 实时通信插件初始化失败: {e}")
|
||||
self.plugin_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用插件
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 实时通信插件未初始化")
|
||||
return False
|
||||
|
||||
print("正在启用实时通信插件...")
|
||||
|
||||
# 启用各模块(按依赖顺序)
|
||||
modules_to_enable = [
|
||||
("config_manager", self.config_manager),
|
||||
("auth_manager", self.auth_manager),
|
||||
("data_serializer", self.data_serializer),
|
||||
("protocol_handler", self.protocol_handler),
|
||||
("client_manager", self.client_manager),
|
||||
("message_router", self.message_router),
|
||||
("room_manager", self.room_manager),
|
||||
("event_handler", self.event_handler),
|
||||
("monitor", self.monitor),
|
||||
("editor", self.editor),
|
||||
("websocket_server", self.websocket_server)
|
||||
]
|
||||
|
||||
for module_name, module in modules_to_enable:
|
||||
if module and not module.enable():
|
||||
print(f"✗ {module_name} 启用失败")
|
||||
return False
|
||||
elif module:
|
||||
print(f"✓ {module_name} 已启用")
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 实时通信插件已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 实时通信插件启用失败: {e}")
|
||||
self.plugin_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用插件"""
|
||||
try:
|
||||
print("正在禁用实时通信插件...")
|
||||
|
||||
# 禁用各模块(按依赖顺序倒序)
|
||||
modules_to_disable = [
|
||||
("websocket_server", self.websocket_server),
|
||||
("editor", self.editor),
|
||||
("monitor", self.monitor),
|
||||
("event_handler", self.event_handler),
|
||||
("room_manager", self.room_manager),
|
||||
("message_router", self.message_router),
|
||||
("client_manager", self.client_manager),
|
||||
("protocol_handler", self.protocol_handler),
|
||||
("data_serializer", self.data_serializer),
|
||||
("auth_manager", self.auth_manager),
|
||||
("config_manager", self.config_manager)
|
||||
]
|
||||
|
||||
for module_name, module in modules_to_disable:
|
||||
if module:
|
||||
module.disable()
|
||||
print(f"✓ {module_name} 已禁用")
|
||||
|
||||
self.enabled = False
|
||||
print("✓ 实时通信插件已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 实时通信插件禁用失败: {e}")
|
||||
self.plugin_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理插件资源"""
|
||||
try:
|
||||
print("正在清理实时通信插件资源...")
|
||||
|
||||
# 禁用插件
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理各模块
|
||||
modules_to_finalize = [
|
||||
self.websocket_server,
|
||||
self.client_manager,
|
||||
self.message_router,
|
||||
self.room_manager,
|
||||
self.protocol_handler,
|
||||
self.auth_manager,
|
||||
self.data_serializer,
|
||||
self.monitor,
|
||||
self.config_manager,
|
||||
self.event_handler,
|
||||
self.editor
|
||||
]
|
||||
|
||||
for module in modules_to_finalize:
|
||||
if module:
|
||||
module.finalize()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 实时通信插件资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 实时通信插件资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新插件状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 更新各模块
|
||||
if self.websocket_server:
|
||||
self.websocket_server.update(dt)
|
||||
|
||||
if self.client_manager:
|
||||
self.client_manager.update(dt)
|
||||
|
||||
if self.message_router:
|
||||
self.message_router.update(dt)
|
||||
|
||||
if self.room_manager:
|
||||
self.room_manager.update(dt)
|
||||
|
||||
if self.monitor:
|
||||
self.monitor.update(dt)
|
||||
|
||||
if self.editor:
|
||||
self.editor.update(dt)
|
||||
|
||||
self.plugin_state["last_update"] = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 实时通信插件更新失败: {e}")
|
||||
self.plugin_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def get_plugin_info(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取插件信息
|
||||
|
||||
Returns:
|
||||
插件信息字典
|
||||
"""
|
||||
return self.plugin_info.copy()
|
||||
|
||||
def get_plugin_state(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取插件状态
|
||||
|
||||
Returns:
|
||||
插件状态字典
|
||||
"""
|
||||
return self.plugin_state.copy()
|
||||
|
||||
def get_plugin_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取插件统计信息
|
||||
|
||||
Returns:
|
||||
插件统计字典
|
||||
"""
|
||||
return {
|
||||
"info": self.plugin_info.copy(),
|
||||
"state": self.plugin_state.copy(),
|
||||
"stats": self.plugin_stats.copy()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置插件统计信息"""
|
||||
try:
|
||||
self.plugin_stats = {
|
||||
"messages_sent": 0,
|
||||
"messages_received": 0,
|
||||
"connections_accepted": 0,
|
||||
"connections_dropped": 0,
|
||||
"errors": 0
|
||||
}
|
||||
print("✓ 插件统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 插件统计信息重置失败: {e}")
|
||||
|
||||
# 插件导出
|
||||
plugin = RealtimeCommunicationPlugin
|
||||
658
plugins/user/realtime_communication/protocol/protocol_handler.py
Normal file
658
plugins/user/realtime_communication/protocol/protocol_handler.py
Normal file
@ -0,0 +1,658 @@
|
||||
"""
|
||||
协议处理器模块
|
||||
处理各种通信协议和消息格式
|
||||
"""
|
||||
|
||||
import time
|
||||
import json
|
||||
import zlib
|
||||
import base64
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class ProtocolHandler:
|
||||
"""
|
||||
协议处理器
|
||||
处理各种通信协议和消息格式
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化协议处理器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 协议配置
|
||||
self.protocol_config = {
|
||||
"supported_protocols": ["websocket", "json", "binary"],
|
||||
"default_protocol": "json",
|
||||
"enable_compression": True,
|
||||
"compression_threshold": 1024, # 1KB
|
||||
"enable_encryption": False,
|
||||
"enable_message_validation": True,
|
||||
"max_message_size": 65536, # 64KB
|
||||
"enable_fragmentation": True,
|
||||
"fragment_size": 8192, # 8KB
|
||||
"enable_checksum": True
|
||||
}
|
||||
|
||||
# 协议状态
|
||||
self.protocol_state = {
|
||||
"active_protocols": [],
|
||||
"compressed_messages": 0,
|
||||
"encrypted_messages": 0,
|
||||
"fragmented_messages": 0
|
||||
}
|
||||
|
||||
# 协议统计
|
||||
self.protocol_stats = {
|
||||
"messages_encoded": 0,
|
||||
"messages_decoded": 0,
|
||||
"bytes_encoded": 0,
|
||||
"bytes_decoded": 0,
|
||||
"compression_savings": 0,
|
||||
"protocol_errors": 0
|
||||
}
|
||||
|
||||
# 协议处理器映射
|
||||
self.protocol_handlers = {
|
||||
"json": {
|
||||
"encode": self._encode_json_message,
|
||||
"decode": self._decode_json_message
|
||||
},
|
||||
"binary": {
|
||||
"encode": self._encode_binary_message,
|
||||
"decode": self._decode_binary_message
|
||||
}
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.protocol_callbacks = {
|
||||
"message_encoded": [],
|
||||
"message_decoded": [],
|
||||
"compression_applied": [],
|
||||
"encryption_applied": [],
|
||||
"protocol_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_compression = 0.0
|
||||
self.last_encryption = 0.0
|
||||
|
||||
print("✓ 协议处理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化协议处理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化协议处理器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 协议处理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 协议处理器初始化失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用协议处理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 协议处理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 协议处理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 协议处理器启用失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用协议处理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
print("✓ 协议处理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 协议处理器禁用失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理协议处理器资源"""
|
||||
try:
|
||||
# 禁用协议处理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.protocol_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 协议处理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 协议处理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新协议处理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
# 协议处理器不需要频繁更新
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 协议处理器更新失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def encode_message(self, message: Dict[str, Any], protocol: str = None) -> Optional[bytes]:
|
||||
"""
|
||||
编码消息
|
||||
|
||||
Args:
|
||||
message: 消息数据
|
||||
protocol: 协议类型
|
||||
|
||||
Returns:
|
||||
编码后的消息或None
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
# 使用默认协议或指定协议
|
||||
if protocol is None:
|
||||
protocol = self.protocol_config["default_protocol"]
|
||||
|
||||
# 验证协议支持
|
||||
if protocol not in self.protocol_handlers:
|
||||
print(f"✗ 不支持的协议: {protocol}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
# 验证消息大小
|
||||
if self.protocol_config["enable_message_validation"]:
|
||||
message_size = len(json.dumps(message, ensure_ascii=False).encode('utf-8'))
|
||||
if message_size > self.protocol_config["max_message_size"]:
|
||||
print(f"✗ 消息过大: {message_size} bytes")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
# 获取协议处理器
|
||||
encoder = self.protocol_handlers[protocol]["encode"]
|
||||
|
||||
# 编码消息
|
||||
encoded_message = encoder(message)
|
||||
if encoded_message is None:
|
||||
return None
|
||||
|
||||
# 更新统计
|
||||
self.protocol_stats["messages_encoded"] += 1
|
||||
self.protocol_stats["bytes_encoded"] += len(encoded_message)
|
||||
|
||||
# 触发消息编码回调
|
||||
self._trigger_protocol_callback("message_encoded", {
|
||||
"protocol": protocol,
|
||||
"message_size": len(encoded_message),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return encoded_message
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息编码失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
def decode_message(self, encoded_message: bytes, protocol: str = None) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
解码消息
|
||||
|
||||
Args:
|
||||
encoded_message: 编码后的消息
|
||||
protocol: 协议类型
|
||||
|
||||
Returns:
|
||||
解码后的消息或None
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
# 使用默认协议或指定协议
|
||||
if protocol is None:
|
||||
protocol = self.protocol_config["default_protocol"]
|
||||
|
||||
# 验证协议支持
|
||||
if protocol not in self.protocol_handlers:
|
||||
print(f"✗ 不支持的协议: {protocol}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
# 获取协议处理器
|
||||
decoder = self.protocol_handlers[protocol]["decode"]
|
||||
|
||||
# 解码消息
|
||||
decoded_message = decoder(encoded_message)
|
||||
if decoded_message is None:
|
||||
return None
|
||||
|
||||
# 更新统计
|
||||
self.protocol_stats["messages_decoded"] += 1
|
||||
self.protocol_stats["bytes_decoded"] += len(encoded_message)
|
||||
|
||||
# 触发消息解码回调
|
||||
self._trigger_protocol_callback("message_decoded", {
|
||||
"protocol": protocol,
|
||||
"message_size": len(encoded_message),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return decoded_message
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息解码失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
def _encode_json_message(self, message: Dict[str, Any]) -> Optional[bytes]:
|
||||
"""
|
||||
JSON消息编码
|
||||
|
||||
Args:
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
编码后的消息或None
|
||||
"""
|
||||
try:
|
||||
# 序列化为JSON
|
||||
json_string = json.dumps(message, ensure_ascii=False)
|
||||
encoded_message = json_string.encode('utf-8')
|
||||
|
||||
# 检查是否需要压缩
|
||||
if (self.protocol_config["enable_compression"] and
|
||||
len(encoded_message) > self.protocol_config["compression_threshold"]):
|
||||
compressed_message = zlib.compress(encoded_message)
|
||||
if len(compressed_message) < len(encoded_message):
|
||||
# 使用压缩版本
|
||||
encoded_message = compressed_message
|
||||
self.protocol_state["compressed_messages"] += 1
|
||||
self.protocol_stats["compression_savings"] += len(encoded_message) - len(compressed_message)
|
||||
|
||||
# 触发压缩应用回调
|
||||
self._trigger_protocol_callback("compression_applied", {
|
||||
"original_size": len(json_string.encode('utf-8')),
|
||||
"compressed_size": len(compressed_message),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return encoded_message
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ JSON消息编码失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
def _decode_json_message(self, encoded_message: bytes) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
JSON消息解码
|
||||
|
||||
Args:
|
||||
encoded_message: 编码后的消息
|
||||
|
||||
Returns:
|
||||
解码后的消息或None
|
||||
"""
|
||||
try:
|
||||
# 尝试解压缩
|
||||
try:
|
||||
decompressed_message = zlib.decompress(encoded_message)
|
||||
encoded_message = decompressed_message
|
||||
except zlib.error:
|
||||
# 不是压缩数据,使用原始数据
|
||||
pass
|
||||
|
||||
# 解码为JSON
|
||||
json_string = encoded_message.decode('utf-8')
|
||||
decoded_message = json.loads(json_string)
|
||||
|
||||
return decoded_message
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ JSON消息解码失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
def _encode_binary_message(self, message: Dict[str, Any]) -> Optional[bytes]:
|
||||
"""
|
||||
二进制消息编码
|
||||
|
||||
Args:
|
||||
message: 消息数据
|
||||
|
||||
Returns:
|
||||
编码后的消息或None
|
||||
"""
|
||||
try:
|
||||
# 将消息转换为二进制格式(简化实现)
|
||||
json_string = json.dumps(message, ensure_ascii=False)
|
||||
binary_message = json_string.encode('utf-8')
|
||||
|
||||
# 添加简单的头部信息
|
||||
header = len(binary_message).to_bytes(4, byteorder='big')
|
||||
encoded_message = header + binary_message
|
||||
|
||||
# 检查是否需要压缩
|
||||
if (self.protocol_config["enable_compression"] and
|
||||
len(encoded_message) > self.protocol_config["compression_threshold"]):
|
||||
compressed_message = zlib.compress(encoded_message)
|
||||
if len(compressed_message) < len(encoded_message):
|
||||
# 使用压缩版本
|
||||
encoded_message = compressed_message
|
||||
self.protocol_state["compressed_messages"] += 1
|
||||
self.protocol_stats["compression_savings"] += len(encoded_message) - len(compressed_message)
|
||||
|
||||
# 触发压缩应用回调
|
||||
self._trigger_protocol_callback("compression_applied", {
|
||||
"original_size": len(header + binary_message),
|
||||
"compressed_size": len(compressed_message),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return encoded_message
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 二进制消息编码失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
def _decode_binary_message(self, encoded_message: bytes) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
二进制消息解码
|
||||
|
||||
Args:
|
||||
encoded_message: 编码后的消息
|
||||
|
||||
Returns:
|
||||
解码后的消息或None
|
||||
"""
|
||||
try:
|
||||
# 尝试解压缩
|
||||
try:
|
||||
decompressed_message = zlib.decompress(encoded_message)
|
||||
encoded_message = decompressed_message
|
||||
except zlib.error:
|
||||
# 不是压缩数据,使用原始数据
|
||||
pass
|
||||
|
||||
# 解析头部信息
|
||||
if len(encoded_message) < 4:
|
||||
raise ValueError("消息太短")
|
||||
|
||||
message_length = int.from_bytes(encoded_message[:4], byteorder='big')
|
||||
binary_message = encoded_message[4:4 + message_length]
|
||||
|
||||
# 解码为JSON
|
||||
json_string = binary_message.decode('utf-8')
|
||||
decoded_message = json.loads(json_string)
|
||||
|
||||
return decoded_message
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 二进制消息解码失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
def fragment_message(self, message: bytes, fragment_size: int = None) -> List[bytes]:
|
||||
"""
|
||||
分片消息
|
||||
|
||||
Args:
|
||||
message: 消息数据
|
||||
fragment_size: 分片大小
|
||||
|
||||
Returns:
|
||||
分片列表
|
||||
"""
|
||||
try:
|
||||
if not self.protocol_config["enable_fragmentation"]:
|
||||
return [message]
|
||||
|
||||
if fragment_size is None:
|
||||
fragment_size = self.protocol_config["fragment_size"]
|
||||
|
||||
fragments = []
|
||||
for i in range(0, len(message), fragment_size):
|
||||
fragment = message[i:i + fragment_size]
|
||||
fragments.append(fragment)
|
||||
|
||||
self.protocol_state["fragmented_messages"] += 1
|
||||
|
||||
return fragments
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息分片失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return [message]
|
||||
|
||||
def reassemble_message(self, fragments: List[bytes]) -> Optional[bytes]:
|
||||
"""
|
||||
重组消息
|
||||
|
||||
Args:
|
||||
fragments: 分片列表
|
||||
|
||||
Returns:
|
||||
重组后的消息或None
|
||||
"""
|
||||
try:
|
||||
if not fragments:
|
||||
return None
|
||||
|
||||
reassembled_message = b''.join(fragments)
|
||||
return reassembled_message
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 消息重组失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return None
|
||||
|
||||
def add_protocol_handler(self, protocol: str, encode_func: callable, decode_func: callable) -> bool:
|
||||
"""
|
||||
添加协议处理器
|
||||
|
||||
Args:
|
||||
protocol: 协议名称
|
||||
encode_func: 编码函数
|
||||
decode_func: 解码函数
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
self.protocol_handlers[protocol] = {
|
||||
"encode": encode_func,
|
||||
"decode": decode_func
|
||||
}
|
||||
|
||||
if protocol not in self.protocol_config["supported_protocols"]:
|
||||
self.protocol_config["supported_protocols"].append(protocol)
|
||||
|
||||
print(f"✓ 协议处理器已添加: {protocol}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 协议处理器添加失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_protocol_handler(self, protocol: str) -> bool:
|
||||
"""
|
||||
移除协议处理器
|
||||
|
||||
Args:
|
||||
protocol: 协议名称
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
if protocol in self.protocol_handlers:
|
||||
del self.protocol_handlers[protocol]
|
||||
|
||||
if protocol in self.protocol_config["supported_protocols"]:
|
||||
self.protocol_config["supported_protocols"].remove(protocol)
|
||||
|
||||
print(f"✓ 协议处理器已移除: {protocol}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 协议处理器不存在: {protocol}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 协议处理器移除失败: {e}")
|
||||
self.protocol_stats["protocol_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_protocol_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取协议统计信息
|
||||
|
||||
Returns:
|
||||
协议统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.protocol_state.copy(),
|
||||
"stats": self.protocol_stats.copy(),
|
||||
"config": self.protocol_config.copy()
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置协议统计信息"""
|
||||
try:
|
||||
self.protocol_stats = {
|
||||
"messages_encoded": 0,
|
||||
"messages_decoded": 0,
|
||||
"bytes_encoded": 0,
|
||||
"bytes_decoded": 0,
|
||||
"compression_savings": 0,
|
||||
"protocol_errors": 0
|
||||
}
|
||||
print("✓ 协议统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 协议统计信息重置失败: {e}")
|
||||
|
||||
def set_protocol_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置协议配置
|
||||
|
||||
Args:
|
||||
config: 协议配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.protocol_config.update(config)
|
||||
print(f"✓ 协议配置已更新: {self.protocol_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 协议配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_protocol_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取协议配置
|
||||
|
||||
Returns:
|
||||
协议配置字典
|
||||
"""
|
||||
return self.protocol_config.copy()
|
||||
|
||||
def _trigger_protocol_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发协议回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.protocol_callbacks:
|
||||
for callback in self.protocol_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 协议回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 协议回调触发失败: {e}")
|
||||
|
||||
def register_protocol_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册协议回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.protocol_callbacks:
|
||||
self.protocol_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 协议回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 协议回调注册失败: {e}")
|
||||
|
||||
def unregister_protocol_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销协议回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.protocol_callbacks:
|
||||
if callback in self.protocol_callbacks[callback_type]:
|
||||
self.protocol_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 协议回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 协议回调注销失败: {e}")
|
||||
894
plugins/user/realtime_communication/rooms/room_manager.py
Normal file
894
plugins/user/realtime_communication/rooms/room_manager.py
Normal file
@ -0,0 +1,894 @@
|
||||
"""
|
||||
房间管理器模块
|
||||
管理通信组和广播消息
|
||||
"""
|
||||
|
||||
import time
|
||||
import threading
|
||||
import uuid
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class RoomManager:
|
||||
"""
|
||||
房间管理器
|
||||
管理通信组和广播消息
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化房间管理器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 房间配置
|
||||
self.room_config = {
|
||||
"max_rooms": 1000,
|
||||
"max_clients_per_room": 100,
|
||||
"enable_room_persistence": False,
|
||||
"room_timeout": 3600, # 1小时无活动房间自动关闭
|
||||
"enable_room_passwords": True,
|
||||
"enable_room_visibility": True,
|
||||
"default_room_settings": {
|
||||
"max_clients": 50,
|
||||
"is_public": True,
|
||||
"allow_spectators": True,
|
||||
"enable_voice_chat": True
|
||||
}
|
||||
}
|
||||
|
||||
# 房间状态
|
||||
self.room_state = {
|
||||
"total_rooms": 0,
|
||||
"active_rooms": 0,
|
||||
"clients_in_rooms": 0
|
||||
}
|
||||
|
||||
# 房间存储
|
||||
self.rooms = {}
|
||||
self.client_rooms = {} # 客户端所在房间映射
|
||||
self.room_lock = threading.RLock()
|
||||
|
||||
# 房间统计
|
||||
self.room_stats = {
|
||||
"rooms_created": 0,
|
||||
"rooms_destroyed": 0,
|
||||
"clients_joined": 0,
|
||||
"clients_left": 0,
|
||||
"messages_broadcast": 0,
|
||||
"errors": 0
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.room_callbacks = {
|
||||
"room_created": [],
|
||||
"room_destroyed": [],
|
||||
"client_joined": [],
|
||||
"client_left": [],
|
||||
"room_updated": [],
|
||||
"room_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_cleanup = 0.0
|
||||
self.last_room_check = 0.0
|
||||
|
||||
print("✓ 房间管理器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化房间管理器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化房间管理器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 房间管理器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间管理器初始化失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用房间管理器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 房间管理器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 房间管理器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间管理器启用失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用房间管理器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 销毁所有房间
|
||||
self._destroy_all_rooms()
|
||||
|
||||
print("✓ 房间管理器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间管理器禁用失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理房间管理器资源"""
|
||||
try:
|
||||
# 禁用房间管理器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.room_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 房间管理器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间管理器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新房间管理器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期清理过期房间
|
||||
if current_time - self.last_cleanup > 60.0: # 每分钟清理一次
|
||||
self._cleanup_expired_rooms(current_time)
|
||||
self.last_cleanup = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间管理器更新失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _cleanup_expired_rooms(self, current_time: float):
|
||||
"""清理过期房间"""
|
||||
try:
|
||||
expired_rooms = []
|
||||
with self.room_lock:
|
||||
for room_id, room_data in self.rooms.items():
|
||||
# 检查房间是否超时
|
||||
if current_time - room_data["last_activity"] > self.room_config["room_timeout"]:
|
||||
# 检查房间是否为空
|
||||
if len(room_data["clients"]) == 0:
|
||||
expired_rooms.append(room_id)
|
||||
|
||||
# 销毁过期房间
|
||||
for room_id in expired_rooms:
|
||||
self.destroy_room(room_id)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 过期房间清理失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
|
||||
def _destroy_all_rooms(self):
|
||||
"""销毁所有房间"""
|
||||
try:
|
||||
with self.room_lock:
|
||||
room_ids = list(self.rooms.keys())
|
||||
|
||||
for room_id in room_ids:
|
||||
self.destroy_room(room_id)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 销毁所有房间失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
|
||||
def create_room(self, room_name: str = None, room_settings: Dict[str, Any] = None,
|
||||
room_password: str = None) -> Optional[str]:
|
||||
"""
|
||||
创建房间
|
||||
|
||||
Args:
|
||||
room_name: 房间名称
|
||||
room_settings: 房间设置
|
||||
room_password: 房间密码
|
||||
|
||||
Returns:
|
||||
房间ID或None
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
# 检查房间数量限制
|
||||
with self.room_lock:
|
||||
if len(self.rooms) >= self.room_config["max_rooms"]:
|
||||
print("✗ 房间数量已达上限")
|
||||
return None
|
||||
|
||||
# 生成房间ID
|
||||
room_id = str(uuid.uuid4())
|
||||
|
||||
# 使用默认设置或传入设置
|
||||
settings = self.room_config["default_room_settings"].copy()
|
||||
if room_settings:
|
||||
settings.update(room_settings)
|
||||
|
||||
# 创建房间数据
|
||||
room_data = {
|
||||
"room_id": room_id,
|
||||
"room_name": room_name or f"房间-{room_id[:8]}",
|
||||
"settings": settings,
|
||||
"password": room_password,
|
||||
"clients": {}, # 客户端ID到客户端数据的映射
|
||||
"host_client_id": None,
|
||||
"created_time": time.time(),
|
||||
"last_activity": time.time(),
|
||||
"room_state": {}, # 房间状态数据
|
||||
"custom_data": {} # 自定义房间数据
|
||||
}
|
||||
|
||||
# 添加到房间列表
|
||||
with self.room_lock:
|
||||
self.rooms[room_id] = room_data
|
||||
|
||||
self.room_state["total_rooms"] += 1
|
||||
self.room_state["active_rooms"] += 1
|
||||
self.room_stats["rooms_created"] += 1
|
||||
|
||||
# 触发房间创建回调
|
||||
self._trigger_room_callback("room_created", {
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"settings": settings,
|
||||
"timestamp": room_data["created_time"]
|
||||
})
|
||||
|
||||
print(f"✓ 房间已创建: {room_id} ({room_data['room_name']})")
|
||||
return room_id
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间创建失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return None
|
||||
|
||||
def destroy_room(self, room_id: str) -> bool:
|
||||
"""
|
||||
销毁房间
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
|
||||
Returns:
|
||||
是否销毁成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 检查房间是否存在
|
||||
with self.room_lock:
|
||||
if room_id not in self.rooms:
|
||||
print(f"✗ 房间不存在: {room_id}")
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
|
||||
# 通知房间内所有客户端
|
||||
for client_id in list(room_data["clients"].keys()):
|
||||
self._notify_client_room_destroyed(client_id, room_id)
|
||||
|
||||
# 移除房间
|
||||
del self.rooms[room_id]
|
||||
|
||||
self.room_state["active_rooms"] -= 1
|
||||
self.room_stats["rooms_destroyed"] += 1
|
||||
|
||||
# 触发房间销毁回调
|
||||
self._trigger_room_callback("room_destroyed", {
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
print(f"✓ 房间已销毁: {room_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间销毁失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def _notify_client_room_destroyed(self, client_id: str, room_id: str):
|
||||
"""
|
||||
通知客户端房间被销毁
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
room_id: 房间ID
|
||||
"""
|
||||
try:
|
||||
# 从客户端房间映射中移除
|
||||
if client_id in self.client_rooms:
|
||||
del self.client_rooms[client_id]
|
||||
|
||||
# 发送房间销毁通知
|
||||
if self.plugin.websocket_server:
|
||||
destroy_message = {
|
||||
"type": "room_destroyed",
|
||||
"room_id": room_id,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
self.plugin.websocket_server.send_message_to_client(client_id, destroy_message)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 通知客户端房间销毁失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
|
||||
def add_client_to_room(self, room_id: str, client_id: str, client_data: Dict[str, Any] = None) -> bool:
|
||||
"""
|
||||
添加客户端到房间
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
client_id: 客户端ID
|
||||
client_data: 客户端数据
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 检查客户端是否已认证
|
||||
if self.plugin.client_manager and not self.plugin.client_manager.is_client_authenticated(client_id):
|
||||
print(f"✗ 客户端未认证: {client_id}")
|
||||
return False
|
||||
|
||||
# 检查房间是否存在
|
||||
with self.room_lock:
|
||||
if room_id not in self.rooms:
|
||||
print(f"✗ 房间不存在: {room_id}")
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
|
||||
# 检查房间是否已满
|
||||
if len(room_data["clients"]) >= room_data["settings"]["max_clients"]:
|
||||
print(f"✗ 房间已满: {room_id}")
|
||||
return False
|
||||
|
||||
# 检查房间密码
|
||||
if room_data["password"] and not self._verify_room_password(room_id, client_data):
|
||||
print(f"✗ 房间密码错误: {room_id}")
|
||||
return False
|
||||
|
||||
# 添加客户端到房间
|
||||
client_info = client_data or {}
|
||||
client_info["join_time"] = time.time()
|
||||
client_info["last_activity"] = time.time()
|
||||
|
||||
room_data["clients"][client_id] = client_info
|
||||
room_data["last_activity"] = time.time()
|
||||
|
||||
# 设置房间主机(如果是第一个客户端)
|
||||
if room_data["host_client_id"] is None:
|
||||
room_data["host_client_id"] = client_id
|
||||
|
||||
# 更新客户端房间映射
|
||||
self.client_rooms[client_id] = room_id
|
||||
|
||||
self.room_state["clients_in_rooms"] += 1
|
||||
self.room_stats["clients_joined"] += 1
|
||||
|
||||
# 触发客户端加入回调
|
||||
self._trigger_room_callback("client_joined", {
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"client_id": client_id,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 通知客户端加入成功
|
||||
join_success_message = {
|
||||
"type": "room_join_success",
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
if self.plugin.websocket_server:
|
||||
self.plugin.websocket_server.send_message_to_client(client_id, join_success_message)
|
||||
|
||||
print(f"✓ 客户端已加入房间: {client_id} -> {room_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 添加客户端到房间失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_client_from_room(self, room_id: str, client_id: str) -> bool:
|
||||
"""
|
||||
从房间移除客户端
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
client_id: 客户端ID
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
# 检查房间是否存在
|
||||
with self.room_lock:
|
||||
if room_id not in self.rooms:
|
||||
print(f"✗ 房间不存在: {room_id}")
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
|
||||
# 检查客户端是否在房间中
|
||||
if client_id not in room_data["clients"]:
|
||||
print(f"✗ 客户端不在房间中: {client_id}")
|
||||
return False
|
||||
|
||||
# 移除客户端
|
||||
del room_data["clients"][client_id]
|
||||
room_data["last_activity"] = time.time()
|
||||
|
||||
# 更新主机(如果移除的是主机)
|
||||
if room_data["host_client_id"] == client_id:
|
||||
if room_data["clients"]:
|
||||
# 选择第一个客户端作为新主机
|
||||
room_data["host_client_id"] = next(iter(room_data["clients"]))
|
||||
else:
|
||||
room_data["host_client_id"] = None
|
||||
|
||||
# 移除客户端房间映射
|
||||
if client_id in self.client_rooms:
|
||||
del self.client_rooms[client_id]
|
||||
|
||||
self.room_state["clients_in_rooms"] -= 1
|
||||
self.room_stats["clients_left"] += 1
|
||||
|
||||
# 触发客户端离开回调
|
||||
self._trigger_room_callback("client_left", {
|
||||
"room_id": room_id,
|
||||
"room_name": room_data["room_name"],
|
||||
"client_id": client_id,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
# 通知客户端离开成功
|
||||
leave_success_message = {
|
||||
"type": "room_leave_success",
|
||||
"room_id": room_id,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
if self.plugin.websocket_server:
|
||||
self.plugin.websocket_server.send_message_to_client(client_id, leave_success_message)
|
||||
|
||||
# 如果房间为空,销毁房间
|
||||
if len(room_data["clients"]) == 0:
|
||||
self.destroy_room(room_id)
|
||||
|
||||
print(f"✓ 客户端已离开房间: {client_id} <- {room_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 从房间移除客户端失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def _verify_room_password(self, room_id: str, client_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
验证房间密码
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
client_data: 客户端数据
|
||||
|
||||
Returns:
|
||||
密码是否正确
|
||||
"""
|
||||
try:
|
||||
if not self.room_config["enable_room_passwords"]:
|
||||
return True
|
||||
|
||||
with self.room_lock:
|
||||
if room_id not in self.rooms:
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
if not room_data["password"]:
|
||||
return True
|
||||
|
||||
client_password = client_data.get("password") if client_data else None
|
||||
return client_password == room_data["password"]
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间密码验证失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def get_room_info(self, room_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取房间信息
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
|
||||
Returns:
|
||||
房间信息或None
|
||||
"""
|
||||
try:
|
||||
with self.room_lock:
|
||||
if room_id in self.rooms:
|
||||
room_data = self.rooms[room_id]
|
||||
# 返回不包含敏感信息的房间信息
|
||||
safe_room_data = {
|
||||
"room_id": room_data["room_id"],
|
||||
"room_name": room_data["room_name"],
|
||||
"settings": room_data["settings"],
|
||||
"client_count": len(room_data["clients"]),
|
||||
"has_password": bool(room_data["password"]),
|
||||
"host_client_id": room_data["host_client_id"],
|
||||
"created_time": room_data["created_time"],
|
||||
"last_activity": room_data["last_activity"]
|
||||
}
|
||||
return safe_room_data
|
||||
else:
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取房间信息失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return None
|
||||
|
||||
def get_all_rooms(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取所有房间信息
|
||||
|
||||
Returns:
|
||||
房间信息列表
|
||||
"""
|
||||
try:
|
||||
rooms_info = []
|
||||
with self.room_lock:
|
||||
for room_id, room_data in self.rooms.items():
|
||||
# 只返回公开房间或用户所在的房间
|
||||
if room_data["settings"].get("is_public", True):
|
||||
safe_room_data = {
|
||||
"room_id": room_data["room_id"],
|
||||
"room_name": room_data["room_name"],
|
||||
"settings": room_data["settings"],
|
||||
"client_count": len(room_data["clients"]),
|
||||
"has_password": bool(room_data["password"]),
|
||||
"host_client_id": room_data["host_client_id"],
|
||||
"created_time": room_data["created_time"],
|
||||
"last_activity": room_data["last_activity"]
|
||||
}
|
||||
rooms_info.append(safe_room_data)
|
||||
|
||||
return rooms_info
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取所有房间信息失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return []
|
||||
|
||||
def get_client_room(self, client_id: str) -> Optional[str]:
|
||||
"""
|
||||
获取客户端所在房间
|
||||
|
||||
Args:
|
||||
client_id: 客户端ID
|
||||
|
||||
Returns:
|
||||
房间ID或None
|
||||
"""
|
||||
try:
|
||||
return self.client_rooms.get(client_id)
|
||||
except Exception as e:
|
||||
print(f"✗ 获取客户端房间失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return None
|
||||
|
||||
def get_room_clients(self, room_id: str) -> List[str]:
|
||||
"""
|
||||
获取房间内所有客户端
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
|
||||
Returns:
|
||||
客户端ID列表
|
||||
"""
|
||||
try:
|
||||
with self.room_lock:
|
||||
if room_id in self.rooms:
|
||||
return list(self.rooms[room_id]["clients"].keys())
|
||||
else:
|
||||
return []
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取房间客户端失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return []
|
||||
|
||||
def update_room_state(self, room_id: str, state_data: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
更新房间状态
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
state_data: 状态数据
|
||||
|
||||
Returns:
|
||||
是否更新成功
|
||||
"""
|
||||
try:
|
||||
with self.room_lock:
|
||||
if room_id not in self.rooms:
|
||||
return False
|
||||
|
||||
self.rooms[room_id]["room_state"].update(state_data)
|
||||
self.rooms[room_id]["last_activity"] = time.time()
|
||||
|
||||
# 触发房间更新回调
|
||||
self._trigger_room_callback("room_updated", {
|
||||
"room_id": room_id,
|
||||
"state_data": state_data,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 更新房间状态失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def broadcast_to_room(self, room_id: str, message_data: Dict[str, Any],
|
||||
exclude_client_id: str = None) -> bool:
|
||||
"""
|
||||
向房间内所有客户端广播消息
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
message_data: 消息数据
|
||||
exclude_client_id: 要排除的客户端ID
|
||||
|
||||
Returns:
|
||||
是否广播成功
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return False
|
||||
|
||||
with self.room_lock:
|
||||
if room_id not in self.rooms:
|
||||
return False
|
||||
|
||||
room_data = self.rooms[room_id]
|
||||
success_count = 0
|
||||
|
||||
# 向房间内每个客户端发送消息
|
||||
for client_id in room_data["clients"]:
|
||||
# 跳过排除的客户端
|
||||
if client_id == exclude_client_id:
|
||||
continue
|
||||
|
||||
# 发送消息
|
||||
if self.plugin.websocket_server:
|
||||
send_success = self.plugin.websocket_server.send_message_to_client(
|
||||
client_id, message_data)
|
||||
if send_success:
|
||||
success_count += 1
|
||||
|
||||
if success_count > 0:
|
||||
self.room_stats["messages_broadcast"] += 1
|
||||
|
||||
return success_count > 0
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 房间广播失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def set_room_custom_data(self, room_id: str, key: str, value: Any) -> bool:
|
||||
"""
|
||||
设置房间自定义数据
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
key: 数据键
|
||||
value: 数据值
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
with self.room_lock:
|
||||
if room_id not in self.rooms:
|
||||
return False
|
||||
|
||||
self.rooms[room_id]["custom_data"][key] = value
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 设置房间自定义数据失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return False
|
||||
|
||||
def get_room_custom_data(self, room_id: str, key: str, default: Any = None) -> Any:
|
||||
"""
|
||||
获取房间自定义数据
|
||||
|
||||
Args:
|
||||
room_id: 房间ID
|
||||
key: 数据键
|
||||
default: 默认值
|
||||
|
||||
Returns:
|
||||
数据值或默认值
|
||||
"""
|
||||
try:
|
||||
with self.room_lock:
|
||||
if room_id not in self.rooms:
|
||||
return default
|
||||
|
||||
return self.rooms[room_id]["custom_data"].get(key, default)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 获取房间自定义数据失败: {e}")
|
||||
self.room_stats["errors"] += 1
|
||||
return default
|
||||
|
||||
def get_room_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取房间统计信息
|
||||
|
||||
Returns:
|
||||
房间统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.room_state.copy(),
|
||||
"stats": self.room_stats.copy(),
|
||||
"config": self.room_config.copy(),
|
||||
"current_rooms": len(self.rooms),
|
||||
"current_clients_in_rooms": len(self.client_rooms)
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置房间统计信息"""
|
||||
try:
|
||||
self.room_stats = {
|
||||
"rooms_created": 0,
|
||||
"rooms_destroyed": 0,
|
||||
"clients_joined": 0,
|
||||
"clients_left": 0,
|
||||
"messages_broadcast": 0,
|
||||
"errors": 0
|
||||
}
|
||||
print("✓ 房间统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 房间统计信息重置失败: {e}")
|
||||
|
||||
def set_room_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置房间配置
|
||||
|
||||
Args:
|
||||
config: 房间配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.room_config.update(config)
|
||||
print(f"✓ 房间配置已更新: {self.room_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 房间配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_room_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取房间配置
|
||||
|
||||
Returns:
|
||||
房间配置字典
|
||||
"""
|
||||
return self.room_config.copy()
|
||||
|
||||
def _trigger_room_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发房间回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.room_callbacks:
|
||||
for callback in self.room_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 房间回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 房间回调触发失败: {e}")
|
||||
|
||||
def register_room_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册房间回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.room_callbacks:
|
||||
self.room_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 房间回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 房间回调注册失败: {e}")
|
||||
|
||||
def unregister_room_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销房间回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.room_callbacks:
|
||||
if callback in self.room_callbacks[callback_type]:
|
||||
self.room_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 房间回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 房间回调注销失败: {e}")
|
||||
@ -0,0 +1,773 @@
|
||||
"""
|
||||
数据序列化器模块
|
||||
将消息序列化为网络数据
|
||||
"""
|
||||
|
||||
import time
|
||||
import json
|
||||
import pickle
|
||||
import zlib
|
||||
from typing import Dict, Any, List, Optional, Union
|
||||
|
||||
class DataSerializer:
|
||||
"""
|
||||
数据序列化器
|
||||
将消息序列化为网络数据
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
初始化数据序列化器
|
||||
|
||||
Args:
|
||||
plugin: 实时通信插件实例
|
||||
"""
|
||||
self.plugin = plugin
|
||||
self.enabled = False
|
||||
self.initialized = False
|
||||
|
||||
# 序列化配置
|
||||
self.serializer_config = {
|
||||
"default_format": "json",
|
||||
"supported_formats": ["json", "pickle", "binary"],
|
||||
"enable_compression": True,
|
||||
"compression_threshold": 1024, # 1KB
|
||||
"enable_caching": True,
|
||||
"cache_size": 1000,
|
||||
"enable_incremental_encoding": True,
|
||||
"enable_type_preservation": True
|
||||
}
|
||||
|
||||
# 序列化状态
|
||||
self.serializer_state = {
|
||||
"cached_objects": 0,
|
||||
"compressed_objects": 0,
|
||||
"serialized_objects": 0
|
||||
}
|
||||
|
||||
# 序列化统计
|
||||
self.serializer_stats = {
|
||||
"objects_serialized": 0,
|
||||
"objects_deserialized": 0,
|
||||
"bytes_serialized": 0,
|
||||
"bytes_deserialized": 0,
|
||||
"compression_savings": 0,
|
||||
"cache_hits": 0,
|
||||
"cache_misses": 0,
|
||||
"serializer_errors": 0
|
||||
}
|
||||
|
||||
# 缓存管理
|
||||
self.serialization_cache = {}
|
||||
self.cache_timestamps = {}
|
||||
|
||||
# 序列化器映射
|
||||
self.serializers = {
|
||||
"json": {
|
||||
"serialize": self._serialize_json,
|
||||
"deserialize": self._deserialize_json
|
||||
},
|
||||
"pickle": {
|
||||
"serialize": self._serialize_pickle,
|
||||
"deserialize": self._deserialize_pickle
|
||||
},
|
||||
"binary": {
|
||||
"serialize": self._serialize_binary,
|
||||
"deserialize": self._deserialize_binary
|
||||
}
|
||||
}
|
||||
|
||||
# 回调函数
|
||||
self.serializer_callbacks = {
|
||||
"object_serialized": [],
|
||||
"object_deserialized": [],
|
||||
"compression_applied": [],
|
||||
"cache_hit": [],
|
||||
"serializer_error": []
|
||||
}
|
||||
|
||||
# 时间戳记录
|
||||
self.last_serialization = 0.0
|
||||
self.last_cache_cleanup = 0.0
|
||||
|
||||
print("✓ 数据序列化器已创建")
|
||||
|
||||
def initialize(self) -> bool:
|
||||
"""
|
||||
初始化数据序列化器
|
||||
|
||||
Returns:
|
||||
是否初始化成功
|
||||
"""
|
||||
try:
|
||||
print("正在初始化数据序列化器...")
|
||||
|
||||
self.initialized = True
|
||||
print("✓ 数据序列化器初始化完成")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 数据序列化器初始化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def enable(self) -> bool:
|
||||
"""
|
||||
启用数据序列化器
|
||||
|
||||
Returns:
|
||||
是否启用成功
|
||||
"""
|
||||
try:
|
||||
if not self.initialized:
|
||||
print("✗ 数据序列化器未初始化")
|
||||
return False
|
||||
|
||||
self.enabled = True
|
||||
print("✓ 数据序列化器已启用")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 数据序列化器启用失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def disable(self):
|
||||
"""禁用数据序列化器"""
|
||||
try:
|
||||
self.enabled = False
|
||||
|
||||
# 清理缓存
|
||||
self.serialization_cache.clear()
|
||||
self.cache_timestamps.clear()
|
||||
|
||||
print("✓ 数据序列化器已禁用")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 数据序列化器禁用失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def finalize(self):
|
||||
"""清理数据序列化器资源"""
|
||||
try:
|
||||
# 禁用数据序列化器
|
||||
if self.enabled:
|
||||
self.disable()
|
||||
|
||||
# 清理回调
|
||||
self.serializer_callbacks.clear()
|
||||
|
||||
self.initialized = False
|
||||
print("✓ 数据序列化器资源已清理")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 数据序列化器资源清理失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def update(self, dt: float):
|
||||
"""
|
||||
更新数据序列化器状态
|
||||
|
||||
Args:
|
||||
dt: 时间增量(秒)
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
|
||||
# 定期清理缓存
|
||||
if current_time - self.last_cache_cleanup > 300: # 每5分钟清理一次
|
||||
self._cleanup_cache(current_time)
|
||||
self.last_cache_cleanup = current_time
|
||||
|
||||
self.last_serialization = current_time
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 数据序列化器更新失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def _cleanup_cache(self, current_time: float):
|
||||
"""清理缓存"""
|
||||
try:
|
||||
if not self.serializer_config["enable_caching"]:
|
||||
return
|
||||
|
||||
expired_keys = []
|
||||
for key, timestamp in self.cache_timestamps.items():
|
||||
# 缓存对象超过10分钟未使用则清除
|
||||
if current_time - timestamp > 600:
|
||||
expired_keys.append(key)
|
||||
|
||||
for key in expired_keys:
|
||||
if key in self.serialization_cache:
|
||||
del self.serialization_cache[key]
|
||||
if key in self.cache_timestamps:
|
||||
del self.cache_timestamps[key]
|
||||
|
||||
self.serializer_state["cached_objects"] = len(self.serialization_cache)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 缓存清理失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
|
||||
def serialize(self, obj: Any, format: str = None) -> Optional[bytes]:
|
||||
"""
|
||||
序列化对象
|
||||
|
||||
Args:
|
||||
obj: 要序列化的对象
|
||||
format: 序列化格式
|
||||
|
||||
Returns:
|
||||
序列化后的字节数据或None
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
# 使用默认格式或指定格式
|
||||
if format is None:
|
||||
format = self.serializer_config["default_format"]
|
||||
|
||||
# 验证格式支持
|
||||
if format not in self.serializers:
|
||||
print(f"✗ 不支持的序列化格式: {format}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
# 检查缓存
|
||||
cache_key = None
|
||||
if self.serializer_config["enable_caching"]:
|
||||
cache_key = self._generate_cache_key(obj, format)
|
||||
if cache_key in self.serialization_cache:
|
||||
self.serializer_stats["cache_hits"] += 1
|
||||
self.cache_timestamps[cache_key] = time.time()
|
||||
|
||||
# 触发缓存命中回调
|
||||
self._trigger_serializer_callback("cache_hit", {
|
||||
"cache_key": cache_key,
|
||||
"format": format,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return self.serialization_cache[cache_key]
|
||||
else:
|
||||
self.serializer_stats["cache_misses"] += 1
|
||||
|
||||
# 获取序列化器
|
||||
serializer = self.serializers[format]["serialize"]
|
||||
|
||||
# 序列化对象
|
||||
serialized_data = serializer(obj)
|
||||
if serialized_data is None:
|
||||
return None
|
||||
|
||||
# 更新统计
|
||||
self.serializer_stats["objects_serialized"] += 1
|
||||
self.serializer_stats["bytes_serialized"] += len(serialized_data)
|
||||
self.serializer_state["serialized_objects"] += 1
|
||||
|
||||
# 缓存结果
|
||||
if (self.serializer_config["enable_caching"] and
|
||||
cache_key and
|
||||
len(self.serialization_cache) < self.serializer_config["cache_size"]):
|
||||
self.serialization_cache[cache_key] = serialized_data
|
||||
self.cache_timestamps[cache_key] = time.time()
|
||||
self.serializer_state["cached_objects"] = len(self.serialization_cache)
|
||||
|
||||
# 触发对象序列化回调
|
||||
self._trigger_serializer_callback("object_serialized", {
|
||||
"format": format,
|
||||
"data_size": len(serialized_data),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return serialized_data
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 对象序列化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
def deserialize(self, data: bytes, format: str = None) -> Optional[Any]:
|
||||
"""
|
||||
反序列化对象
|
||||
|
||||
Args:
|
||||
data: 要反序列化的字节数据
|
||||
format: 序列化格式
|
||||
|
||||
Returns:
|
||||
反序列化后的对象或None
|
||||
"""
|
||||
try:
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
# 使用默认格式或指定格式
|
||||
if format is None:
|
||||
format = self.serializer_config["default_format"]
|
||||
|
||||
# 验证格式支持
|
||||
if format not in self.serializers:
|
||||
print(f"✗ 不支持的反序列化格式: {format}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
# 获取反序列化器
|
||||
deserializer = self.serializers[format]["deserialize"]
|
||||
|
||||
# 反序列化对象
|
||||
deserialized_obj = deserializer(data)
|
||||
if deserialized_obj is None:
|
||||
return None
|
||||
|
||||
# 更新统计
|
||||
self.serializer_stats["objects_deserialized"] += 1
|
||||
self.serializer_stats["bytes_deserialized"] += len(data)
|
||||
|
||||
# 触发对象反序列化回调
|
||||
self._trigger_serializer_callback("object_deserialized", {
|
||||
"format": format,
|
||||
"data_size": len(data),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return deserialized_obj
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 对象反序列化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
def _serialize_json(self, obj: Any) -> Optional[bytes]:
|
||||
"""
|
||||
JSON序列化
|
||||
|
||||
Args:
|
||||
obj: 要序列化的对象
|
||||
|
||||
Returns:
|
||||
序列化后的字节数据或None
|
||||
"""
|
||||
try:
|
||||
# 序列化为JSON字符串
|
||||
json_string = json.dumps(obj, ensure_ascii=False, default=self._json_default)
|
||||
serialized_data = json_string.encode('utf-8')
|
||||
|
||||
# 检查是否需要压缩
|
||||
if (self.serializer_config["enable_compression"] and
|
||||
len(serialized_data) > self.serializer_config["compression_threshold"]):
|
||||
compressed_data = zlib.compress(serialized_data)
|
||||
if len(compressed_data) < len(serialized_data):
|
||||
# 使用压缩版本
|
||||
serialized_data = compressed_data
|
||||
self.serializer_state["compressed_objects"] += 1
|
||||
self.serializer_stats["compression_savings"] += len(serialized_data) - len(compressed_data)
|
||||
|
||||
# 触发压缩应用回调
|
||||
self._trigger_serializer_callback("compression_applied", {
|
||||
"original_size": len(json_string.encode('utf-8')),
|
||||
"compressed_size": len(compressed_data),
|
||||
"compression_ratio": len(compressed_data) / len(json_string.encode('utf-8')),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return serialized_data
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ JSON序列化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
def _deserialize_json(self, data: bytes) -> Optional[Any]:
|
||||
"""
|
||||
JSON反序列化
|
||||
|
||||
Args:
|
||||
data: 要反序列化的字节数据
|
||||
|
||||
Returns:
|
||||
反序列化后的对象或None
|
||||
"""
|
||||
try:
|
||||
# 尝试解压缩
|
||||
try:
|
||||
decompressed_data = zlib.decompress(data)
|
||||
data = decompressed_data
|
||||
except zlib.error:
|
||||
# 不是压缩数据,使用原始数据
|
||||
pass
|
||||
|
||||
# 解码为JSON
|
||||
json_string = data.decode('utf-8')
|
||||
deserialized_obj = json.loads(json_string)
|
||||
|
||||
return deserialized_obj
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ JSON反序列化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
def _json_default(self, obj):
|
||||
"""
|
||||
JSON默认序列化方法
|
||||
|
||||
Args:
|
||||
obj: 要序列化的对象
|
||||
|
||||
Returns:
|
||||
可序列化的对象
|
||||
"""
|
||||
# 处理不能直接序列化的对象
|
||||
return str(obj)
|
||||
|
||||
def _serialize_pickle(self, obj: Any) -> Optional[bytes]:
|
||||
"""
|
||||
Pickle序列化
|
||||
|
||||
Args:
|
||||
obj: 要序列化的对象
|
||||
|
||||
Returns:
|
||||
序列化后的字节数据或None
|
||||
"""
|
||||
try:
|
||||
# 序列化为pickle数据
|
||||
pickle_data = pickle.dumps(obj)
|
||||
|
||||
# 检查是否需要压缩
|
||||
if (self.serializer_config["enable_compression"] and
|
||||
len(pickle_data) > self.serializer_config["compression_threshold"]):
|
||||
compressed_data = zlib.compress(pickle_data)
|
||||
if len(compressed_data) < len(pickle_data):
|
||||
# 使用压缩版本
|
||||
pickle_data = compressed_data
|
||||
self.serializer_state["compressed_objects"] += 1
|
||||
self.serializer_stats["compression_savings"] += len(pickle_data) - len(compressed_data)
|
||||
|
||||
# 触发压缩应用回调
|
||||
self._trigger_serializer_callback("compression_applied", {
|
||||
"original_size": len(pickle.dumps(obj)),
|
||||
"compressed_size": len(compressed_data),
|
||||
"compression_ratio": len(compressed_data) / len(pickle.dumps(obj)),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return pickle_data
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Pickle序列化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
def _deserialize_pickle(self, data: bytes) -> Optional[Any]:
|
||||
"""
|
||||
Pickle反序列化
|
||||
|
||||
Args:
|
||||
data: 要反序列化的字节数据
|
||||
|
||||
Returns:
|
||||
反序列化后的对象或None
|
||||
"""
|
||||
try:
|
||||
# 尝试解压缩
|
||||
try:
|
||||
decompressed_data = zlib.decompress(data)
|
||||
data = decompressed_data
|
||||
except zlib.error:
|
||||
# 不是压缩数据,使用原始数据
|
||||
pass
|
||||
|
||||
# 反序列化pickle数据
|
||||
deserialized_obj = pickle.loads(data)
|
||||
|
||||
return deserialized_obj
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Pickle反序列化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
def _serialize_binary(self, obj: Any) -> Optional[bytes]:
|
||||
"""
|
||||
二进制序列化
|
||||
|
||||
Args:
|
||||
obj: 要序列化的对象
|
||||
|
||||
Returns:
|
||||
序列化后的字节数据或None
|
||||
"""
|
||||
try:
|
||||
# 简化实现:将对象转换为JSON再编码为二进制
|
||||
json_string = json.dumps(obj, ensure_ascii=False, default=self._json_default)
|
||||
binary_data = json_string.encode('utf-8')
|
||||
|
||||
# 添加简单的头部信息
|
||||
header = len(binary_data).to_bytes(4, byteorder='big')
|
||||
serialized_data = header + binary_data
|
||||
|
||||
# 检查是否需要压缩
|
||||
if (self.serializer_config["enable_compression"] and
|
||||
len(serialized_data) > self.serializer_config["compression_threshold"]):
|
||||
compressed_data = zlib.compress(serialized_data)
|
||||
if len(compressed_data) < len(serialized_data):
|
||||
# 使用压缩版本
|
||||
serialized_data = compressed_data
|
||||
self.serializer_state["compressed_objects"] += 1
|
||||
self.serializer_stats["compression_savings"] += len(serialized_data) - len(compressed_data)
|
||||
|
||||
# 触发压缩应用回调
|
||||
self._trigger_serializer_callback("compression_applied", {
|
||||
"original_size": len(header + binary_data),
|
||||
"compressed_size": len(compressed_data),
|
||||
"compression_ratio": len(compressed_data) / len(header + binary_data),
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
return serialized_data
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 二进制序列化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
def _deserialize_binary(self, data: bytes) -> Optional[Any]:
|
||||
"""
|
||||
二进制反序列化
|
||||
|
||||
Args:
|
||||
data: 要反序列化的字节数据
|
||||
|
||||
Returns:
|
||||
反序列化后的对象或None
|
||||
"""
|
||||
try:
|
||||
# 尝试解压缩
|
||||
try:
|
||||
decompressed_data = zlib.decompress(data)
|
||||
data = decompressed_data
|
||||
except zlib.error:
|
||||
# 不是压缩数据,使用原始数据
|
||||
pass
|
||||
|
||||
# 解析头部信息
|
||||
if len(data) < 4:
|
||||
raise ValueError("数据太短")
|
||||
|
||||
message_length = int.from_bytes(data[:4], byteorder='big')
|
||||
binary_data = data[4:4 + message_length]
|
||||
|
||||
# 解码为JSON
|
||||
json_string = binary_data.decode('utf-8')
|
||||
deserialized_obj = json.loads(json_string)
|
||||
|
||||
return deserialized_obj
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 二进制反序列化失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return None
|
||||
|
||||
def _generate_cache_key(self, obj: Any, format: str) -> str:
|
||||
"""
|
||||
生成缓存键
|
||||
|
||||
Args:
|
||||
obj: 对象
|
||||
format: 格式
|
||||
|
||||
Returns:
|
||||
缓存键
|
||||
"""
|
||||
try:
|
||||
# 简化实现:使用对象的字符串表示和格式生成键
|
||||
obj_str = str(obj)
|
||||
cache_key = f"{format}:{hash(obj_str)}:{len(obj_str)}"
|
||||
return cache_key
|
||||
except Exception as e:
|
||||
print(f"✗ 缓存键生成失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return f"error_key_{int(time.time() * 1000000)}"
|
||||
|
||||
def add_serializer(self, format: str, serialize_func: callable, deserialize_func: callable) -> bool:
|
||||
"""
|
||||
添加序列化器
|
||||
|
||||
Args:
|
||||
format: 格式名称
|
||||
serialize_func: 序列化函数
|
||||
deserialize_func: 反序列化函数
|
||||
|
||||
Returns:
|
||||
是否添加成功
|
||||
"""
|
||||
try:
|
||||
self.serializers[format] = {
|
||||
"serialize": serialize_func,
|
||||
"deserialize": deserialize_func
|
||||
}
|
||||
|
||||
if format not in self.serializer_config["supported_formats"]:
|
||||
self.serializer_config["supported_formats"].append(format)
|
||||
|
||||
print(f"✓ 序列化器已添加: {format}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 序列化器添加失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return False
|
||||
|
||||
def remove_serializer(self, format: str) -> bool:
|
||||
"""
|
||||
移除序列化器
|
||||
|
||||
Args:
|
||||
format: 格式名称
|
||||
|
||||
Returns:
|
||||
是否移除成功
|
||||
"""
|
||||
try:
|
||||
if format in self.serializers:
|
||||
del self.serializers[format]
|
||||
|
||||
if format in self.serializer_config["supported_formats"]:
|
||||
self.serializer_config["supported_formats"].remove(format)
|
||||
|
||||
print(f"✓ 序列化器已移除: {format}")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ 序列化器不存在: {format}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 序列化器移除失败: {e}")
|
||||
self.serializer_stats["serializer_errors"] += 1
|
||||
return False
|
||||
|
||||
def get_serializer_stats(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取序列化统计信息
|
||||
|
||||
Returns:
|
||||
序列化统计字典
|
||||
"""
|
||||
return {
|
||||
"state": self.serializer_state.copy(),
|
||||
"stats": self.serializer_stats.copy(),
|
||||
"config": self.serializer_config.copy(),
|
||||
"cache_size": len(self.serialization_cache)
|
||||
}
|
||||
|
||||
def reset_stats(self):
|
||||
"""重置序列化统计信息"""
|
||||
try:
|
||||
self.serializer_stats = {
|
||||
"objects_serialized": 0,
|
||||
"objects_deserialized": 0,
|
||||
"bytes_serialized": 0,
|
||||
"bytes_deserialized": 0,
|
||||
"compression_savings": 0,
|
||||
"cache_hits": 0,
|
||||
"cache_misses": 0,
|
||||
"serializer_errors": 0
|
||||
}
|
||||
print("✓ 序列化统计信息已重置")
|
||||
except Exception as e:
|
||||
print(f"✗ 序列化统计信息重置失败: {e}")
|
||||
|
||||
def set_serializer_config(self, config: Dict[str, Any]) -> bool:
|
||||
"""
|
||||
设置序列化配置
|
||||
|
||||
Args:
|
||||
config: 序列化配置字典
|
||||
|
||||
Returns:
|
||||
是否设置成功
|
||||
"""
|
||||
try:
|
||||
self.serializer_config.update(config)
|
||||
print(f"✓ 序列化配置已更新: {self.serializer_config}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ 序列化配置设置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_serializer_config(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取序列化配置
|
||||
|
||||
Returns:
|
||||
序列化配置字典
|
||||
"""
|
||||
return self.serializer_config.copy()
|
||||
|
||||
def _trigger_serializer_callback(self, callback_type: str, data: Dict[str, Any]):
|
||||
"""
|
||||
触发序列化回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
data: 回调数据
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.serializer_callbacks:
|
||||
for callback in self.serializer_callbacks[callback_type]:
|
||||
try:
|
||||
callback(data)
|
||||
except Exception as e:
|
||||
print(f"✗ 序列化回调执行失败: {callback_type} - {e}")
|
||||
except Exception as e:
|
||||
print(f"✗ 序列化回调触发失败: {e}")
|
||||
|
||||
def register_serializer_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注册序列化回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.serializer_callbacks:
|
||||
self.serializer_callbacks[callback_type].append(callback)
|
||||
print(f"✓ 序列化回调已注册: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 序列化回调注册失败: {e}")
|
||||
|
||||
def unregister_serializer_callback(self, callback_type: str, callback: callable):
|
||||
"""
|
||||
注销序列化回调
|
||||
|
||||
Args:
|
||||
callback_type: 回调类型
|
||||
callback: 回调函数
|
||||
"""
|
||||
try:
|
||||
if callback_type in self.serializer_callbacks:
|
||||
if callback in self.serializer_callbacks[callback_type]:
|
||||
self.serializer_callbacks[callback_type].remove(callback)
|
||||
print(f"✓ 序列化回调已注销: {callback_type}")
|
||||
else:
|
||||
print(f"✗ 无效的回调类型: {callback_type}")
|
||||
except Exception as e:
|
||||
print(f"✗ 序列化回调注销失败: {e}")
|
||||
248
plugins/user/realtime_communication/utils/comm_utils.py
Normal file
248
plugins/user/realtime_communication/utils/comm_utils.py
Normal file
@ -0,0 +1,248 @@
|
||||
"""
|
||||
通信工具类模块
|
||||
提供实用工具函数
|
||||
"""
|
||||
|
||||
import time
|
||||
import hashlib
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
class CommUtils:
|
||||
"""
|
||||
通信工具类
|
||||
提供实用工具函数
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def generate_unique_id(prefix: str = "") -> str:
|
||||
"""
|
||||
生成唯一ID
|
||||
|
||||
Args:
|
||||
prefix: ID前缀
|
||||
|
||||
Returns:
|
||||
生成的唯一ID
|
||||
"""
|
||||
try:
|
||||
timestamp = int(time.time() * 1000000) # 微秒时间戳
|
||||
unique_id = f"{prefix}{timestamp}" if prefix else str(timestamp)
|
||||
return unique_id
|
||||
except Exception as e:
|
||||
print(f"✗ 唯一ID生成失败: {e}")
|
||||
return f"error_id_{int(time.time() * 1000000)}"
|
||||
|
||||
@staticmethod
|
||||
def calculate_checksum(data: bytes) -> str:
|
||||
"""
|
||||
计算数据校验和
|
||||
|
||||
Args:
|
||||
data: 要计算校验和的数据
|
||||
|
||||
Returns:
|
||||
校验和字符串
|
||||
"""
|
||||
try:
|
||||
checksum = hashlib.md5(data).hexdigest()
|
||||
return checksum
|
||||
except Exception as e:
|
||||
print(f"✗ 校验和计算失败: {e}")
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def format_bytes(bytes_count: int) -> str:
|
||||
"""
|
||||
格式化字节数
|
||||
|
||||
Args:
|
||||
bytes_count: 字节数
|
||||
|
||||
Returns:
|
||||
格式化后的字符串
|
||||
"""
|
||||
try:
|
||||
if bytes_count < 1024:
|
||||
return f"{bytes_count} B"
|
||||
elif bytes_count < 1024 * 1024:
|
||||
return f"{bytes_count / 1024:.2f} KB"
|
||||
elif bytes_count < 1024 * 1024 * 1024:
|
||||
return f"{bytes_count / (1024 * 1024):.2f} MB"
|
||||
else:
|
||||
return f"{bytes_count / (1024 * 1024 * 1024):.2f} GB"
|
||||
except Exception as e:
|
||||
print(f"✗ 字节格式化失败: {e}")
|
||||
return f"{bytes_count} B"
|
||||
|
||||
@staticmethod
|
||||
def validate_json(data: str) -> bool:
|
||||
"""
|
||||
验证JSON数据
|
||||
|
||||
Args:
|
||||
data: JSON字符串
|
||||
|
||||
Returns:
|
||||
是否为有效JSON
|
||||
"""
|
||||
try:
|
||||
json.loads(data)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def sanitize_input(input_str: str) -> str:
|
||||
"""
|
||||
清理输入字符串
|
||||
|
||||
Args:
|
||||
input_str: 输入字符串
|
||||
|
||||
Returns:
|
||||
清理后的字符串
|
||||
"""
|
||||
try:
|
||||
# 移除潜在的危险字符
|
||||
sanitized = input_str.replace("<", "<").replace(">", ">")
|
||||
sanitized = sanitized.replace("\"", """).replace("'", "'")
|
||||
return sanitized
|
||||
except Exception as e:
|
||||
print(f"✗ 输入清理失败: {e}")
|
||||
return input_str
|
||||
|
||||
@staticmethod
|
||||
def create_response(success: bool, message: str = "", data: Any = None) -> Dict[str, Any]:
|
||||
"""
|
||||
创建响应数据
|
||||
|
||||
Args:
|
||||
success: 是否成功
|
||||
message: 消息
|
||||
data: 数据
|
||||
|
||||
Returns:
|
||||
响应数据字典
|
||||
"""
|
||||
try:
|
||||
response = {
|
||||
"success": success,
|
||||
"message": message,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
if data is not None:
|
||||
response["data"] = data
|
||||
|
||||
return response
|
||||
except Exception as e:
|
||||
print(f"✗ 响应创建失败: {e}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "响应创建失败",
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def merge_dicts(dict1: Dict[str, Any], dict2: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
合并字典(递归)
|
||||
|
||||
Args:
|
||||
dict1: 第一个字典
|
||||
dict2: 第二个字典
|
||||
|
||||
Returns:
|
||||
合并后的字典
|
||||
"""
|
||||
try:
|
||||
result = dict1.copy()
|
||||
|
||||
for key, value in dict2.items():
|
||||
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
||||
# 递归合并嵌套字典
|
||||
result[key] = CommUtils.merge_dicts(result[key], value)
|
||||
else:
|
||||
# 直接覆盖
|
||||
result[key] = value
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
print(f"✗ 字典合并失败: {e}")
|
||||
return dict1
|
||||
|
||||
@staticmethod
|
||||
def get_system_info() -> Dict[str, Any]:
|
||||
"""
|
||||
获取系统信息
|
||||
|
||||
Returns:
|
||||
系统信息字典
|
||||
"""
|
||||
try:
|
||||
import platform
|
||||
import psutil
|
||||
|
||||
# 系统信息
|
||||
system_info = {
|
||||
"platform": platform.system(),
|
||||
"platform_version": platform.version(),
|
||||
"architecture": platform.architecture()[0],
|
||||
"processor": platform.processor(),
|
||||
"python_version": platform.python_version()
|
||||
}
|
||||
|
||||
# CPU信息
|
||||
cpu_info = {
|
||||
"physical_cores": psutil.cpu_count(logical=False),
|
||||
"total_cores": psutil.cpu_count(logical=True),
|
||||
"max_frequency": psutil.cpu_freq().max if psutil.cpu_freq() else 0,
|
||||
"current_frequency": psutil.cpu_freq().current if psutil.cpu_freq() else 0
|
||||
}
|
||||
|
||||
# 内存信息
|
||||
memory_info = psutil.virtual_memory()
|
||||
memory_stats = {
|
||||
"total": memory_info.total,
|
||||
"available": memory_info.available,
|
||||
"used": memory_info.used,
|
||||
"percentage": memory_info.percent
|
||||
}
|
||||
|
||||
# 网络信息
|
||||
net_info = psutil.net_io_counters()
|
||||
network_stats = {
|
||||
"bytes_sent": net_info.bytes_sent,
|
||||
"bytes_recv": net_info.bytes_recv,
|
||||
"packets_sent": net_info.packets_sent,
|
||||
"packets_recv": net_info.packets_recv
|
||||
}
|
||||
|
||||
return {
|
||||
"system": system_info,
|
||||
"cpu": cpu_info,
|
||||
"memory": memory_stats,
|
||||
"network": network_stats,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 系统信息获取失败: {e}")
|
||||
return {
|
||||
"system": {},
|
||||
"cpu": {},
|
||||
"memory": {},
|
||||
"network": {},
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
# 工具函数别名
|
||||
generate_id = CommUtils.generate_unique_id
|
||||
calculate_checksum = CommUtils.calculate_checksum
|
||||
format_bytes = CommUtils.format_bytes
|
||||
validate_json = CommUtils.validate_json
|
||||
sanitize_input = CommUtils.sanitize_input
|
||||
create_response = CommUtils.create_response
|
||||
merge_dicts = CommUtils.merge_dicts
|
||||
get_system_info = CommUtils.get_system_info
|
||||
Loading…
Reference in New Issue
Block a user