加入功能,自动撤回,将异常信息发送后,5秒撤回
This commit is contained in:
@@ -8,6 +8,7 @@ from typing import Dict, Any, List, Optional, Tuple
|
|||||||
from plugin_common.message_plugin_interface import MessagePluginInterface
|
from plugin_common.message_plugin_interface import MessagePluginInterface
|
||||||
from plugin_common.plugin_interface import PluginStatus
|
from plugin_common.plugin_interface import PluginStatus
|
||||||
from utils.decorator.plugin_decorators import plugin_stats_decorator
|
from utils.decorator.plugin_decorators import plugin_stats_decorator
|
||||||
|
from utils.revoke.message_auto_revoke import MessageAutoRevoke
|
||||||
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
|
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
|
||||||
from utils.decorator.points_decorator import plugin_points_cost
|
from utils.decorator.points_decorator import plugin_points_cost
|
||||||
from wechat_ipad import WechatAPIClient
|
from wechat_ipad import WechatAPIClient
|
||||||
@@ -98,7 +99,7 @@ class XiurenImagePlugin(MessagePluginInterface):
|
|||||||
roomid = message.get("roomid", "")
|
roomid = message.get("roomid", "")
|
||||||
gbm: GroupBotManager = message.get("gbm")
|
gbm: GroupBotManager = message.get("gbm")
|
||||||
bot: WechatAPIClient = message.get("bot")
|
bot: WechatAPIClient = message.get("bot")
|
||||||
|
revoke: MessageAutoRevoke = message.get("revoke")
|
||||||
# 检查权限
|
# 检查权限
|
||||||
if roomid and gbm.get_group_permission(roomid, Feature.PIC) == PermissionStatus.DISABLED:
|
if roomid and gbm.get_group_permission(roomid, Feature.PIC) == PermissionStatus.DISABLED:
|
||||||
return False, "没有权限"
|
return False, "没有权限"
|
||||||
@@ -107,8 +108,10 @@ class XiurenImagePlugin(MessagePluginInterface):
|
|||||||
# 获取随机图片
|
# 获取随机图片
|
||||||
pic_path = self._get_random_pic()
|
pic_path = self._get_random_pic()
|
||||||
if not pic_path:
|
if not pic_path:
|
||||||
await bot.send_text_message((roomid if roomid else sender), f"❌未找到图片资源",
|
client_msg_id, create_time, new_msg_id = await bot.send_text_message((roomid if roomid else sender),
|
||||||
|
f"❌未找到图片资源",
|
||||||
sender)
|
sender)
|
||||||
|
revoke.add_message_to_revoke(roomid, client_msg_id, create_time, new_msg_id, 30)
|
||||||
return False, "未找到图片资源"
|
return False, "未找到图片资源"
|
||||||
|
|
||||||
# 发送图片
|
# 发送图片
|
||||||
|
|||||||
9
robot.py
9
robot.py
@@ -16,6 +16,7 @@ from plugin_common.message_plugin_interface import MessagePluginInterface
|
|||||||
from plugin_common.plugin_interface import PluginStatus
|
from plugin_common.plugin_interface import PluginStatus
|
||||||
from plugin_common.plugin_manager import PluginManager
|
from plugin_common.plugin_manager import PluginManager
|
||||||
from plugin_common.plugin_registry import PluginRegistry
|
from plugin_common.plugin_registry import PluginRegistry
|
||||||
|
from utils.revoke.message_auto_revoke import MessageAutoRevoke
|
||||||
from utils.robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
from utils.robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
||||||
|
|
||||||
from db.connection import DBConnectionManager
|
from db.connection import DBConnectionManager
|
||||||
@@ -46,7 +47,7 @@ class Robot(Job):
|
|||||||
self.nickname = None
|
self.nickname = None
|
||||||
self.alias = None
|
self.alias = None
|
||||||
self.phone = None
|
self.phone = None
|
||||||
|
self.message_auto_revoke: MessageAutoRevoke = None
|
||||||
self.LOG.info(f"DB+REDIS 连接池开始初始化")
|
self.LOG.info(f"DB+REDIS 连接池开始初始化")
|
||||||
# 使用单例模式获取实例
|
# 使用单例模式获取实例
|
||||||
self.db_manager = DBConnectionManager.get_instance(
|
self.db_manager = DBConnectionManager.get_instance(
|
||||||
@@ -140,6 +141,7 @@ class Robot(Job):
|
|||||||
self.LOG.info("启动wechat_ipad bot")
|
self.LOG.info("启动wechat_ipad bot")
|
||||||
# 调用登录接口
|
# 调用登录接口
|
||||||
self.ipad_bot = wechat_ipad.WechatAPIClient(server_ip, server_port)
|
self.ipad_bot = wechat_ipad.WechatAPIClient(server_ip, server_port)
|
||||||
|
self.message_auto_revoke = MessageAutoRevoke(self.ipad_bot)
|
||||||
wxid = self.ipad_config.get("wxid", "")
|
wxid = self.ipad_config.get("wxid", "")
|
||||||
device_name = self.ipad_config.get("device_name", "")
|
device_name = self.ipad_config.get("device_name", "")
|
||||||
device_id = self.ipad_config.get("device_id", "")
|
device_id = self.ipad_config.get("device_id", "")
|
||||||
@@ -369,7 +371,7 @@ class Robot(Job):
|
|||||||
# 处理群聊命令或私聊命令
|
# 处理群聊命令或私聊命令
|
||||||
if from_user == self.wxid: # 自己发送的消息
|
if from_user == self.wxid: # 自己发送的消息
|
||||||
if is_group:
|
if is_group:
|
||||||
rsp = self.gbm.handle_command(group_id, content)
|
rsp = self.gbm.handle_command(group_id, content.clean_content)
|
||||||
if rsp is not None:
|
if rsp is not None:
|
||||||
await self.send_text(rsp, group_id)
|
await self.send_text(rsp, group_id)
|
||||||
else:
|
else:
|
||||||
@@ -518,7 +520,8 @@ class Robot(Job):
|
|||||||
"all_contacts": self.allContacts,
|
"all_contacts": self.allContacts,
|
||||||
"full_wx_msg": msg,
|
"full_wx_msg": msg,
|
||||||
"gbm": self.gbm,
|
"gbm": self.gbm,
|
||||||
"bot": self.ipad_bot
|
"bot": self.ipad_bot,
|
||||||
|
"revoke": self.message_auto_revoke
|
||||||
}
|
}
|
||||||
|
|
||||||
# 检查插件是否可以处理该消息
|
# 检查插件是否可以处理该消息
|
||||||
|
|||||||
0
utils/__init__.py
Normal file
0
utils/__init__.py
Normal file
0
utils/revoke/__init__.py
Normal file
0
utils/revoke/__init__.py
Normal file
47
utils/revoke/message_auto_revoke.py
Normal file
47
utils/revoke/message_auto_revoke.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
from typing import Optional
|
||||||
|
from utils.revoke.message_revoke_manager import MessageRevokeManager
|
||||||
|
from wechat_ipad import WechatAPIClient
|
||||||
|
|
||||||
|
|
||||||
|
class MessageAutoRevoke:
|
||||||
|
"""消息自动撤回工具类"""
|
||||||
|
|
||||||
|
def __init__(self, client: WechatAPIClient, default_delay: float = 90.0):
|
||||||
|
"""
|
||||||
|
初始化消息自动撤回工具
|
||||||
|
|
||||||
|
Args:
|
||||||
|
client: WechatAPIClient实例
|
||||||
|
default_delay: 默认撤回延时(秒)
|
||||||
|
"""
|
||||||
|
self.client = client
|
||||||
|
self.revoke_manager = MessageRevokeManager(default_delay)
|
||||||
|
# 设置撤回回调函数
|
||||||
|
self.revoke_manager.set_revoke_callback(self.client.revoke_message)
|
||||||
|
|
||||||
|
def add_message_to_revoke(self, wxid: str, client_msg_id: int, create_time: int, new_msg_id: int,
|
||||||
|
delay: Optional[float] = None) -> None:
|
||||||
|
"""
|
||||||
|
添加消息到撤回队列
|
||||||
|
|
||||||
|
Args:
|
||||||
|
wxid: 接收人wxid
|
||||||
|
client_msg_id: 消息ID
|
||||||
|
create_time: 消息创建时间
|
||||||
|
new_msg_id: 新消息ID
|
||||||
|
delay: 延迟撤回时间(秒),如果为None则使用默认值
|
||||||
|
"""
|
||||||
|
self.revoke_manager.add_message_to_revoke(wxid, client_msg_id, create_time, new_msg_id, delay)
|
||||||
|
|
||||||
|
def set_default_delay(self, delay: float) -> None:
|
||||||
|
"""
|
||||||
|
设置默认撤回延时
|
||||||
|
|
||||||
|
Args:
|
||||||
|
delay: 默认撤回延时(秒)
|
||||||
|
"""
|
||||||
|
self.revoke_manager.set_default_delay(delay)
|
||||||
|
|
||||||
|
def stop(self) -> None:
|
||||||
|
"""停止消息撤回任务"""
|
||||||
|
self.revoke_manager.stop()
|
||||||
118
utils/revoke/message_revoke_manager.py
Normal file
118
utils/revoke/message_revoke_manager.py
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
import asyncio
|
||||||
|
import time
|
||||||
|
from typing import Dict, List, Tuple, Optional, Callable
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
|
class MessageRevokeManager:
|
||||||
|
"""消息撤回管理器,用于管理需要延时撤回的消息"""
|
||||||
|
|
||||||
|
def __init__(self, default_delay: float = 90.0):
|
||||||
|
"""
|
||||||
|
初始化消息撤回管理器
|
||||||
|
|
||||||
|
Args:
|
||||||
|
default_delay: 默认撤回延时时间(秒),默认为90秒
|
||||||
|
"""
|
||||||
|
self.revoke_queue: List[Tuple[float, str, int, int, int]] = [] # (撤回时间, wxid, client_msg_id, create_time, new_msg_id)
|
||||||
|
self.default_delay = default_delay
|
||||||
|
self.running = False
|
||||||
|
self.task = None
|
||||||
|
self.logging = logger
|
||||||
|
self.revoke_callback = None
|
||||||
|
|
||||||
|
def add_message_to_revoke(self, wxid: str, client_msg_id: int, create_time: int, new_msg_id: int,
|
||||||
|
delay: Optional[float] = None) -> None:
|
||||||
|
"""
|
||||||
|
添加消息到撤回队列
|
||||||
|
|
||||||
|
Args:
|
||||||
|
wxid: 接收人wxid
|
||||||
|
client_msg_id: 消息ID
|
||||||
|
create_time: 消息创建时间
|
||||||
|
new_msg_id: 新消息ID
|
||||||
|
delay: 延迟撤回时间(秒),如果为None则使用默认值
|
||||||
|
"""
|
||||||
|
if delay is None:
|
||||||
|
delay = self.default_delay
|
||||||
|
|
||||||
|
revoke_time = time.time() + delay
|
||||||
|
self.revoke_queue.append((revoke_time, wxid, client_msg_id, create_time, new_msg_id))
|
||||||
|
self.revoke_queue.sort(key=lambda x: x[0]) # 按撤回时间排序
|
||||||
|
|
||||||
|
# 如果撤回任务未运行,则启动
|
||||||
|
if not self.running:
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def start(self) -> None:
|
||||||
|
"""启动消息撤回任务"""
|
||||||
|
if self.running:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.running = True
|
||||||
|
self.task = asyncio.create_task(self._process_revoke_queue())
|
||||||
|
self.logging.info("消息自动撤回任务已启动")
|
||||||
|
|
||||||
|
def stop(self) -> None:
|
||||||
|
"""停止消息撤回任务"""
|
||||||
|
if not self.running:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.running = False
|
||||||
|
if self.task:
|
||||||
|
self.task.cancel()
|
||||||
|
self.logging.info("消息自动撤回任务已停止")
|
||||||
|
|
||||||
|
def set_revoke_callback(self, callback: Callable) -> None:
|
||||||
|
"""
|
||||||
|
设置撤回回调函数
|
||||||
|
|
||||||
|
Args:
|
||||||
|
callback: 撤回消息的回调函数,接受wxid, client_msg_id, create_time, new_msg_id参数
|
||||||
|
"""
|
||||||
|
self.revoke_callback = callback
|
||||||
|
|
||||||
|
def set_default_delay(self, delay: float) -> None:
|
||||||
|
"""
|
||||||
|
设置默认撤回延时
|
||||||
|
|
||||||
|
Args:
|
||||||
|
delay: 默认撤回延时(秒)
|
||||||
|
"""
|
||||||
|
self.default_delay = delay
|
||||||
|
|
||||||
|
async def _process_revoke_queue(self) -> None:
|
||||||
|
"""处理撤回队列的异步任务"""
|
||||||
|
try:
|
||||||
|
while self.running:
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
|
# 检查是否有需要撤回的消息
|
||||||
|
while self.revoke_queue and self.revoke_queue[0][0] <= now:
|
||||||
|
revoke_time, wxid, client_msg_id, create_time, new_msg_id = self.revoke_queue.pop(0)
|
||||||
|
try:
|
||||||
|
# 通过回调函数调用实际的撤回方法
|
||||||
|
if self.revoke_callback and callable(self.revoke_callback):
|
||||||
|
await self.revoke_callback(wxid, client_msg_id, create_time, new_msg_id)
|
||||||
|
self.logging.info(f"已自动撤回消息: wxid={wxid}, msg_id={client_msg_id}")
|
||||||
|
except Exception as e:
|
||||||
|
self.logging.error(f"自动撤回消息失败: {e}")
|
||||||
|
|
||||||
|
# 如果队列为空,等待一段时间
|
||||||
|
if not self.revoke_queue:
|
||||||
|
self.running = False
|
||||||
|
self.logging.info("撤回队列为空,撤回任务已停止")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 计算下一个需要撤回的消息的等待时间
|
||||||
|
next_revoke_time = self.revoke_queue[0][0]
|
||||||
|
wait_time = max(0.1, next_revoke_time - time.time())
|
||||||
|
|
||||||
|
# 等待到下一个撤回时间
|
||||||
|
await asyncio.sleep(wait_time)
|
||||||
|
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
self.logging.info("消息撤回任务被取消")
|
||||||
|
except Exception as e:
|
||||||
|
self.logging.error(f"消息撤回任务异常: {e}")
|
||||||
|
self.running = False
|
||||||
@@ -142,7 +142,7 @@ class GroupBotManager:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def handle_command(group_id, command_str):
|
def handle_command(group_id, command_str):
|
||||||
"""统一处理群功能指令"""
|
"""统一处理群功能指令"""
|
||||||
print(f"PermissionStatus handle_command command_str: {command_str}")
|
# print(f"PermissionStatus handle_command command_str: {command_str}")
|
||||||
# 命令解析
|
# 命令解析
|
||||||
command_parts = command_str.strip().split("-")
|
command_parts = command_str.strip().split("-")
|
||||||
|
|
||||||
|
|||||||
@@ -93,12 +93,12 @@ class MessageMixin(WechatAPIClientBase):
|
|||||||
"NewMsgId": new_msg_id}
|
"NewMsgId": new_msg_id}
|
||||||
response = await session.post(f'http://{self.ip}:{self.port}/api/Msg/Revoke', json=json_param)
|
response = await session.post(f'http://{self.ip}:{self.port}/api/Msg/Revoke', json=json_param)
|
||||||
json_resp = await response.json()
|
json_resp = await response.json()
|
||||||
|
|
||||||
if json_resp.get("Success"):
|
if json_resp.get("Success"):
|
||||||
self.logging.info("消息撤回成功: 对方wxid:{} ClientMsgId:{} CreateTime:{} NewMsgId:{}",
|
self.logging.info("消息撤回成功: 对方wxid:{} ClientMsgId:{} CreateTime:{} NewMsgId:{}",
|
||||||
wxid,
|
wxid,
|
||||||
client_msg_id,
|
client_msg_id,
|
||||||
new_msg_id)
|
create_time,
|
||||||
|
new_msg_id) # 确保四个参数都正确传入
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self.error_handler(json_resp)
|
self.error_handler(json_resp)
|
||||||
@@ -144,8 +144,7 @@ class MessageMixin(WechatAPIClientBase):
|
|||||||
if json_resp.get("Success"):
|
if json_resp.get("Success"):
|
||||||
self.logging.info("发送文字消息: 对方wxid:{} at:{} 内容:{}", wxid, at, content)
|
self.logging.info("发送文字消息: 对方wxid:{} at:{} 内容:{}", wxid, at, content)
|
||||||
data = json_resp.get("Data")
|
data = json_resp.get("Data")
|
||||||
self.logging.info("send msg:{} ", data)
|
return data.get("List")[0].get("ClientMsgId"), data.get("List")[0].get("CreateTime"), data.get("List")[
|
||||||
return data.get("List")[0].get("ClientMsgid"), data.get("List")[0].get("Createtime"), data.get("List")[
|
|
||||||
0].get("NewMsgId")
|
0].get("NewMsgId")
|
||||||
else:
|
else:
|
||||||
self.error_handler(json_resp)
|
self.error_handler(json_resp)
|
||||||
|
|||||||
Reference in New Issue
Block a user