diff --git a/message_storage/message_to_db.py b/message_storage/message_to_db.py index 17b61d8..fc65613 100644 --- a/message_storage/message_to_db.py +++ b/message_storage/message_to_db.py @@ -1,6 +1,7 @@ from datetime import datetime, timedelta import xml.etree.ElementTree as ET import logging +import concurrent.futures # 添加线程池支持 from wcferry import WxMsg @@ -24,6 +25,10 @@ class MessageStorage: # 初始化本地缓存字典,使用 group_id 作为键 self.local_membercounts = {} self.local_members = {} + # 创建线程池,用于异步存储消息 + self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=5) + # 用于跟踪异步任务的列表 + self.pending_tasks = [] def process_message(self, message: WxMsg): # 示例message字符串 @@ -39,15 +44,58 @@ class MessageStorage: # 或者使用字符串:r.incr(key) # 如果只存储一个整数值,字符串类型可能更简单 def archive_message(self, msg: WxMsg): + """异步存档消息,防止堵塞主线程""" + # 提交任务到线程池 + future = self.executor.submit(self._archive_message_task, msg) + # 可选:添加回调函数处理完成后的操作 + future.add_done_callback(self._archive_callback) + # 将任务添加到待处理列表 + self.pending_tasks.append(future) + # 清理已完成的任务 + self._cleanup_completed_tasks() + + def _archive_message_task(self, msg: WxMsg): + """实际执行消息存档的任务函数""" try: # 使用 MessageStorageDB 类存档消息 result = self.message_db.archive_message(msg) - if result: - logger.info(f"消息存档成功: {msg.roomid}:{msg.sender}: {msg.content}") - else: - logger.error(f"消息存档失败: {msg.roomid}:{msg.sender}") + return { + 'success': result, + 'roomid': msg.roomid, + 'sender': msg.sender + } except Exception as e: logger.error(f"存档消息出错: {e}") + return { + 'success': False, + 'roomid': msg.roomid, + 'sender': msg.sender, + 'error': str(e) + } + + def _archive_callback(self, future): + """处理异步存档任务完成后的回调""" + try: + result = future.result() + if result['success']: + logger.info(f"消息存档成功: {result['roomid']}:{result['sender']}") + else: + error_msg = result.get('error', '未知错误') + logger.error(f"消息存档失败: {result['roomid']}:{result['sender']} - {error_msg}") + except Exception as e: + logger.error(f"处理存档回调时出错: {e}") + + def _cleanup_completed_tasks(self): + """清理已完成的任务,防止内存泄漏""" + # 过滤出已完成的任务 + completed_tasks = [task for task in self.pending_tasks if task.done()] + # 从待处理列表中移除已完成的任务 + for task in completed_tasks: + self.pending_tasks.remove(task) + + # 如果待处理任务过多,记录警告日志 + if len(self.pending_tasks) > 100: + logger.warning(f"待处理的存档任务数量过多: {len(self.pending_tasks)}") def write_to_db(self): """从Redis读取发言统计数据并写入数据库""" diff --git a/plugins/douyin_parser/main.py b/plugins/douyin_parser/main.py index a65fdaa..1e63ebc 100644 --- a/plugins/douyin_parser/main.py +++ b/plugins/douyin_parser/main.py @@ -255,7 +255,7 @@ class DouyinParserPlugin(MessagePluginInterface): try: api_url = "http://192.168.2.240:9081/api/hybrid/video_data" clean_url = self._clean_url(url) - params = {'url': clean_url, 'type': 'json'} + params = {'url': clean_url, 'minimal': True} self.LOG.info(f"[抖音] 请求API: {api_url}, 参数: {repr(params)}") proxy = {"http": self.http_proxy, "https": self.http_proxy} if self.http_proxy else None diff --git a/plugins/stats_dashboard/dashboard_server.py b/plugins/stats_dashboard/dashboard_server.py index ebeee62..0df7df6 100644 --- a/plugins/stats_dashboard/dashboard_server.py +++ b/plugins/stats_dashboard/dashboard_server.py @@ -159,6 +159,46 @@ class DashboardServer: self.logger.error(f"批量操作失败: {e}") return jsonify({"success": False, "error": str(e)}), 400 + # 添加:手动添加群组的API接口 + @app.route('/api/robot/add_group', methods=['POST']) + def api_add_group(): + try: + data = request.json + group_id = data.get('group_id') + + if not group_id or not group_id.strip(): + return jsonify({"success": False, "error": "群组ID不能为空"}), 400 + + group_id = group_id.strip() + + # 检查群组是否已存在 + if group_id in GroupBotManager.local_cache["group_list"]: + return jsonify({"success": False, "error": "该群组已存在"}), 400 + + # 添加群组到列表并启用机器人功能 + GroupBotManager.local_cache["group_list"].add(group_id) + r = self.db_manager.get_redis_connection() + r.sadd("group:list", group_id) + + # 设置ROBOT功能为启用状态 + GroupBotManager.set_group_permission(group_id, Feature.ROBOT, PermissionStatus.ENABLED) + + # 获取群组名称(如果可能) + group_name = self.contact_manager.get_nickname(group_id) + + return jsonify({ + "success": True, + "message": f"群组 {group_id} 已成功添加", + "group": { + "group_id": group_id, + "group_name": group_name, + "robot_status": "enabled" + } + }) + except Exception as e: + self.logger.error(f"添加群组失败: {e}") + return jsonify({"success": False, "error": str(e)}), 500 + @app.route('/api/plugin_stats') def api_plugin_stats(): days = request.args.get('days', 7, type=int) diff --git a/plugins/stats_dashboard/templates/robot_management.html b/plugins/stats_dashboard/templates/robot_management.html index f8fdfb1..c03ba7f 100644 --- a/plugins/stats_dashboard/templates/robot_management.html +++ b/plugins/stats_dashboard/templates/robot_management.html @@ -10,6 +10,13 @@
群机器人管理 + + 添加群组 + 关闭
+ + + + + + + + + + 取消 + 确定 + + {% endblock %} @@ -123,7 +146,18 @@ currentGroupName: '', searchQuery: '', selectedGroups: [], - permissionDialogVisible: false + permissionDialogVisible: false, + // 添加群组相关数据 + addGroupDialogVisible: false, + addGroupForm: { + groupId: '' + }, + addGroupRules: { + groupId: [ + { required: true, message: '请输入群组ID', trigger: 'blur' }, + { pattern: /^\S+$/, message: '群组ID不能包含空格', trigger: 'blur' } + ] + } } }, computed: { @@ -237,6 +271,38 @@ this.$message.error('更新权限失败: ' + error.message); }); }, + // 显示添加群组对话框 + showAddGroupDialog() { + this.addGroupForm.groupId = ''; + this.addGroupDialogVisible = true; + }, + + // 提交添加群组 + submitAddGroup() { + this.$refs.addGroupForm.validate((valid) => { + if (valid) { + axios.post('/api/robot/add_group', { + group_id: this.addGroupForm.groupId + }) + .then(response => { + if (response.data.success) { + this.$message.success(response.data.message); + // 添加新群组到列表 + if (response.data.group) { + this.groups.push(response.data.group); + } + this.addGroupDialogVisible = false; + } else { + this.$message.error(response.data.error || '添加失败'); + } + }) + .catch(error => { + console.error('添加群组失败:', error); + this.$message.error('添加群组失败: ' + (error.response?.data?.error || error.message)); + }); + } + }); + }, enableAllPermissions() { this.$confirm('确定要启用所有功能吗?', '提示', { confirmButtonText: '确定', @@ -419,4 +485,4 @@ } }); -{% endblock %} \ No newline at end of file +{% endblock %}