对报错进行了修复, 新加几个装饰器,以及防撤回
This commit is contained in:
parent
e759e5fa9d
commit
f321ed6d85
@ -18,7 +18,6 @@ pip install --upgrade wcfauto
|
||||
|
||||
import logging
|
||||
from time import sleep
|
||||
|
||||
from wcfauto import Register, Wcf, WxMsg
|
||||
|
||||
logging.basicConfig(level='DEBUG', format="%(asctime)s %(message)s")
|
||||
@ -85,6 +84,34 @@ def main():
|
||||
异步消息函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
@receiver.group_changed_register(allow_other_receive=False)
|
||||
async def group_changed(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
群组信息变化函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
@receiver.revoke_message_register(allow_other_receive=False)
|
||||
async def group_changed(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
撤回消息函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
def judge(msg: WxMsg):
|
||||
"""
|
||||
消息判断函数
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
@receiver.custom_message_register(register_name='custom', msg_judge_func=judge, allow_other_receive=False)
|
||||
async def group_changed(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
自定义消息接收函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
# 开始接受消息
|
||||
receiver.run()
|
||||
@ -93,6 +120,7 @@ def main():
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
```
|
||||
|
||||
|||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
import logging
|
||||
from time import sleep
|
||||
|
||||
from wcfauto import Register, Wcf, WxMsg
|
||||
|
||||
logging.basicConfig(level='DEBUG', format="%(asctime)s %(message)s")
|
||||
@ -71,6 +70,34 @@ def main():
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
@receiver.group_changed_register(allow_other_receive=False)
|
||||
async def group_changed(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
群组信息变化函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
@receiver.revoke_message_register(allow_other_receive=False)
|
||||
async def group_changed(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
撤回消息函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
def judge(msg: WxMsg):
|
||||
"""
|
||||
消息判断函数
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
@receiver.custom_message_register(register_name='custom', msg_judge_func=judge, allow_other_receive=False)
|
||||
async def group_changed(bot: Wcf, msg: WxMsg):
|
||||
"""
|
||||
自定义消息接收函数装饰器
|
||||
"""
|
||||
print(msg)
|
||||
|
||||
# 开始接受消息
|
||||
receiver.run()
|
||||
|
||||
|
@ -5,3 +5,4 @@ from wcfauto.wcf import WcfV2 as Wcf
|
||||
from wcfauto.wcf import WxMsgV2 as WxMsg
|
||||
|
||||
__version__ = "39.0.3.0"
|
||||
|
||||
|
@ -5,3 +5,4 @@ from wcfauto.auto_res.core import load_function
|
||||
|
||||
|
||||
Register = load_function(Register)
|
||||
|
||||
|
@ -1,15 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from abc import abstractmethod
|
||||
from typing import Any, Callable
|
||||
|
||||
from typing import Callable, Any
|
||||
from wcfauto.event import Event
|
||||
from wcfauto.wcf import WcfV2 as Wcf
|
||||
from abc import abstractmethod
|
||||
from wcfauto.wcf import WcfV2 as Wcf, WxMsgV2 as WxMsg
|
||||
import logging
|
||||
|
||||
|
||||
class Register(Event):
|
||||
def __init__(self, debug=True, **kwargs):
|
||||
"""
|
||||
消息注册器
|
||||
"""
|
||||
def __init__(self,
|
||||
debug=True,
|
||||
**kwargs):
|
||||
super(Register, self).__init__()
|
||||
logging.basicConfig(level='DEBUG', format="%(asctime)s %(message)s")
|
||||
self._LOG = logging.getLogger("Demo")
|
||||
@ -18,8 +22,10 @@ class Register(Event):
|
||||
self._wcf = Wcf(debug=debug, **kwargs)
|
||||
|
||||
@abstractmethod
|
||||
def _process_msg(self, wcf: Wcf):
|
||||
def _process_msg(self,
|
||||
wcf: Wcf):
|
||||
"""
|
||||
外部不可访问接口
|
||||
有消息的时候,通知分发器分发消息
|
||||
:param wcf: Wcf
|
||||
:return: None
|
||||
@ -28,11 +34,17 @@ class Register(Event):
|
||||
|
||||
@abstractmethod
|
||||
def _register(self,
|
||||
func: Callable[[Any], Any]):
|
||||
kind: str,
|
||||
register_name: str,
|
||||
allow_other_receive: bool,
|
||||
judge_msg: Callable[[Any], Any]):
|
||||
"""
|
||||
外部不可访问接口
|
||||
消息处理工厂, 所有消息处理函数都会汇总在这里提交给事件分发器
|
||||
:param func: 被装饰的待处理消息函数
|
||||
:return: func
|
||||
:param kind: 用于区分被装饰函数属于异步或者同步函数, 主要用于消息分发函数中做区分主要两大类函数
|
||||
:param register_name: 函数类名 (用于一个装饰器用于装饰多个函数时, 将这些函数统一取名一个类名)
|
||||
:param allow_other_receive 是否允许其他消息函数(指函数类名不同且必须同为同一个 kind的消息函数(即同为异步或者同步))接收消息
|
||||
:param judge_msg 用来判断消息是否是本函数要求的消息
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@ -40,14 +52,21 @@ class Register(Event):
|
||||
def _processing_async_func(self,
|
||||
isGroup: bool,
|
||||
isDivision: bool,
|
||||
isPyq: bool):
|
||||
isPyq: bool,
|
||||
register_name: str,
|
||||
allow_other_receive: bool,
|
||||
judge_msg: Callable[[Any], bool]):
|
||||
"""
|
||||
异步函数消息处理函数, 用来接受非协程函数
|
||||
外部不可访问接口
|
||||
异步函数消息处理函数, 用来接受协程函数, 此函数为异步装饰器函数基函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
:param register_name 函数类名 (用于一个装饰器用于装饰多个函数时, 将这些函数统一取名一个类名)
|
||||
:param allow_other_receive 是否允许其他消息函数(指函数类名不同且必须同为同一个 kind的消息函数(即同为异步或者同步))接收消息
|
||||
:param judge_msg 用来判断消息是否是本函数要求的消息
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@ -55,14 +74,21 @@ class Register(Event):
|
||||
def _processing_universal_func(self,
|
||||
isGroup: bool,
|
||||
isDivision: bool,
|
||||
isPyq: bool):
|
||||
isPyq: bool,
|
||||
register_name: str,
|
||||
allow_other_receive: bool,
|
||||
judge_msg: Callable[[Any], bool]):
|
||||
"""
|
||||
同步函数消息处理函数, 用来接受非协程函数
|
||||
外部不可访问接口
|
||||
同步函数消息处理函数, 用来接受非协程函数, 此函数为同步装饰器函数基函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
:param register_name 函数类名 (用于一个装饰器用于装饰多个函数时, 将这些函数统一取名一个类名)
|
||||
:param allow_other_receive 是否允许其他消息函数(指函数类名不同且必须同为同一个 kind的消息函数(即同为异步或者同步))接收消息
|
||||
:param judge_msg 用来判断消息是否是本函数要求的消息
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@ -73,7 +99,7 @@ class Register(Event):
|
||||
isPyq: bool = False):
|
||||
"""
|
||||
外部可访问接口
|
||||
消息处理函数注册器, 用来接受同步函数
|
||||
[所有消息] 处理函数注册器, 用来接受同步函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
@ -89,7 +115,7 @@ class Register(Event):
|
||||
isPyq: bool = False):
|
||||
"""
|
||||
外部可访问接口
|
||||
消息处理函数注册器, 用来接受异步函数
|
||||
[所有消息] 处理函数注册器, 用来接受异步函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
@ -99,7 +125,68 @@ class Register(Event):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def run(self, *args, **kwargs):
|
||||
def revoke_message_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False,
|
||||
allow_other_receive: bool = True):
|
||||
"""
|
||||
外部可访问接口
|
||||
[撤回消息] 处理函数注册器, 用来接受异步函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
:param allow_other_receive 是否允许符合本函数要求的消息(撤回消息)被其他消息函数(指函数类名不同且
|
||||
必须同为同一个 kind的消息函数(即同为异步或者同步))接受
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def group_changed_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False,
|
||||
allow_other_receive: bool = True):
|
||||
"""
|
||||
外部可访问接口
|
||||
[群成员变动消息]处理函数注册器, 用来接受异步函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
:param allow_other_receive 是否允许符合本函数要求的消息(群成员消息)被其他消息函数(指函数类名不同且
|
||||
必须同为同一个 kind的消息函数(即同为异步或者同步))接受
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def custom_message_register(self,
|
||||
register_name: str,
|
||||
msg_judge_func: Callable[[WxMsg], bool],
|
||||
allow_other_receive: bool,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False):
|
||||
"""
|
||||
外部可访问接口
|
||||
[自定义消息]处理函数注册器, 用来接受异步函数
|
||||
参数:
|
||||
:param isGroup 对消息进行限制, 当为True时, 只接受群消息, 当为False时, 只接受私聊消息,
|
||||
注意! 仅当isDivision为 True时, isGroup参数生效
|
||||
:param isPyq 是否接受朋友圈消息
|
||||
:param isDivision 是否对消息分组
|
||||
:param register_name 注册函数类名, 注意不可为空, 注意函数类名决定最后消息分发结果, 因此每个新函数的类名应是不同的
|
||||
:param msg_judge_func 判断消息是否为符合自定义消息的函数 (函数直接受一个参数 WcfMsg作为参数, 返回值为 bool)
|
||||
在函数内编写需要符合自定义要求的函数, 但函数返回值必须为 bool类型, 符合要求返回 True,
|
||||
不符合要求返回 False
|
||||
:param allow_other_receive 是否允许符合本函数要求的消息(自定义符合消息)被其他消息函数(指函数类名不同且
|
||||
必须同为同一个 kind的消息函数(即同为异步或者同步))接受
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def run(self, pyq=True):
|
||||
"""
|
||||
启动程序, 开始接受消息
|
||||
"""
|
||||
|
@ -5,8 +5,7 @@ import functools
|
||||
import queue
|
||||
import traceback
|
||||
from threading import Thread
|
||||
from typing import Any, Callable
|
||||
|
||||
from typing import Callable, Any
|
||||
from wcfauto.wcf import WcfV2 as Wcf
|
||||
from wcfauto.wcf import WxMsgV2 as WxMsg
|
||||
|
||||
@ -18,6 +17,9 @@ def load_function(cls):
|
||||
cls._processing_universal_func = _processing_universal_func
|
||||
cls.message_register = message_register
|
||||
cls.async_message_register = async_message_register
|
||||
cls.revoke_message_register = revoke_message_register
|
||||
cls.group_changed_register = group_changed_register
|
||||
cls.custom_message_register = custom_message_register
|
||||
cls.run = run
|
||||
cls.stop_receiving = stop_receiving
|
||||
return cls
|
||||
@ -35,20 +37,33 @@ def _process_msg(self, wcf: Wcf):
|
||||
|
||||
|
||||
def _register(self,
|
||||
func: Callable[[Any], Any]):
|
||||
self._add_callback(func, self._wcf)
|
||||
# 此处必须返回被装饰函数原函数, 否则丢失被装饰函数信息
|
||||
return func
|
||||
kind: str,
|
||||
register_name: str,
|
||||
allow_other_receive: bool,
|
||||
judge_msg: Callable[[Any], Any]):
|
||||
def __register(func: Callable[[Any], Any]):
|
||||
self._add_callback(func,
|
||||
self._wcf,
|
||||
kind=kind,
|
||||
register_name=register_name,
|
||||
allow_other_rec=allow_other_receive,
|
||||
judge_msg=judge_msg)
|
||||
# 此处必须返回被装饰函数原函数, 否则丢失被装饰函数信息
|
||||
return func
|
||||
|
||||
return __register
|
||||
|
||||
|
||||
def _processing_async_func(self,
|
||||
isGroup: bool,
|
||||
isDivision: bool,
|
||||
isPyq: bool,):
|
||||
isPyq: bool,
|
||||
register_name: str,
|
||||
allow_other_receive: bool,
|
||||
judge_msg: Callable[[Any], bool]):
|
||||
def _async_func(func):
|
||||
|
||||
@functools.wraps(func)
|
||||
@self._register
|
||||
@self._register('async', register_name, allow_other_receive, judge_msg)
|
||||
async def __async_func(bot: Wcf, message: WxMsg):
|
||||
try:
|
||||
# 判断被装饰函数是否为协程函数, 本函数要求是协程函数
|
||||
@ -71,17 +86,19 @@ def _processing_async_func(self,
|
||||
def _processing_universal_func(self,
|
||||
isGroup: bool,
|
||||
isDivision: bool,
|
||||
isPyq: bool, ):
|
||||
isPyq: bool,
|
||||
register_name: str,
|
||||
allow_other_receive: bool,
|
||||
judge_msg: Callable[[Any], bool]):
|
||||
def _universal_func(func):
|
||||
|
||||
@functools.wraps(func)
|
||||
@self._register
|
||||
@self._register('universal', register_name, allow_other_receive, judge_msg)
|
||||
def universal_func(bot: Wcf, message: WxMsg):
|
||||
try:
|
||||
# 判断被装饰函数是否为协程函数, 本函数要求是协程函数
|
||||
if asyncio.iscoroutinefunction(func):
|
||||
raise ValueError(
|
||||
f'这里应使用非协程函数, 而被装饰函数-> ({func.__name__}) <-协程函数')
|
||||
raise ValueError(f'这里应使用非协程函数, 而被装饰函数-> ({func.__name__}) <-协程函数')
|
||||
if message.is_pyq() and isPyq:
|
||||
return func(bot, message)
|
||||
if not isDivision:
|
||||
@ -92,7 +109,6 @@ def _processing_universal_func(self,
|
||||
return func(bot, message)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return None
|
||||
return universal_func
|
||||
return _universal_func
|
||||
|
||||
@ -101,18 +117,80 @@ def message_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False):
|
||||
return self._processing_universal_func(isGroup, isDivision, isPyq)
|
||||
return self._processing_universal_func(isGroup,
|
||||
isDivision,
|
||||
isPyq,
|
||||
register_name='common',
|
||||
allow_other_receive=True,
|
||||
judge_msg=lambda x: True)
|
||||
|
||||
|
||||
def revoke_message_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False,
|
||||
allow_other_receive: bool = True):
|
||||
def judge_msg(msg):
|
||||
if msg['isRevokeMsg'] and msg['revokmsgid'] is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
return self._processing_async_func(isGroup,
|
||||
isDivision,
|
||||
isPyq,
|
||||
register_name='revokeMessage',
|
||||
allow_other_receive=allow_other_receive,
|
||||
judge_msg=judge_msg)
|
||||
|
||||
|
||||
def group_changed_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False,
|
||||
allow_other_receive: bool = True):
|
||||
def judge_msg(msg):
|
||||
if msg['isGroup'] and msg['data']['type'] == 10000:
|
||||
if '加入了群聊' in msg['data']['content'] or '出了群聊' in msg['data']['content']:
|
||||
return True
|
||||
return False
|
||||
|
||||
return self._processing_async_func(isGroup,
|
||||
isDivision,
|
||||
isPyq,
|
||||
register_name='groupChanged',
|
||||
allow_other_receive=allow_other_receive,
|
||||
judge_msg=judge_msg)
|
||||
|
||||
|
||||
def custom_message_register(self,
|
||||
register_name: str,
|
||||
msg_judge_func: Callable[[WxMsg], bool],
|
||||
allow_other_receive: bool,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False):
|
||||
return self._processing_async_func(isGroup,
|
||||
isDivision,
|
||||
isPyq,
|
||||
register_name=register_name,
|
||||
allow_other_receive=allow_other_receive,
|
||||
judge_msg=msg_judge_func)
|
||||
|
||||
|
||||
def async_message_register(self,
|
||||
isGroup: bool = False,
|
||||
isDivision: bool = False,
|
||||
isPyq: bool = False):
|
||||
return self._processing_async_func(isGroup, isDivision, isPyq)
|
||||
return self._processing_async_func(isGroup,
|
||||
isDivision,
|
||||
isPyq,
|
||||
register_name='common',
|
||||
allow_other_receive=True,
|
||||
judge_msg=lambda x: True)
|
||||
|
||||
|
||||
def run(self, *args, **kwargs):
|
||||
self._wcf.enable_receiving_msg(*args, pyq=True, **kwargs)
|
||||
def run(self, pyq=True):
|
||||
self._wcf.enable_receiving_msg(pyq=pyq)
|
||||
Thread(target=self._process_msg, name="GetMessage", args=(self._wcf,), daemon=True).start()
|
||||
self._LOG.debug("开始接受消息")
|
||||
self._wcf.keep_running()
|
||||
|
@ -4,3 +4,8 @@ from wcfauto.event.event import Event
|
||||
from wcfauto.event.core import load_function
|
||||
|
||||
Event = load_function(Event)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import asyncio
|
||||
import traceback
|
||||
from typing import Callable, Any
|
||||
from wcfauto.wcf import WcfV2 as Wcf
|
||||
from wcfauto.wcf import WxMsgV2 as WxMsg
|
||||
import asyncio
|
||||
from threading import Thread
|
||||
|
||||
|
||||
@ -11,17 +14,32 @@ def load_function(cls):
|
||||
return cls
|
||||
|
||||
|
||||
def _add_callback(self, func, bot):
|
||||
def _add_callback(self,
|
||||
func: Callable[[Any], Any],
|
||||
bot: Wcf,
|
||||
kind: str,
|
||||
register_name: str,
|
||||
allow_other_rec: bool,
|
||||
judge_msg: Callable[[WxMsg], bool]):
|
||||
"""
|
||||
消息处理函数加载器
|
||||
:param func: 消息处理函数
|
||||
:param args: 消息处理函数参数
|
||||
:param kwargs: 消息处理函数参数
|
||||
:param func: 装饰器装饰的函数
|
||||
:param bot: Wcf类
|
||||
:param kind: 装饰器所处类别, 分为异步和同步
|
||||
:param register_name: 装饰器所处类别下的函数类名(主要区分不同装饰器的作用, 以及为其中的 allow_other_rec参数做准备)
|
||||
:param allow_other_rec: 是否允许消息分发到其他不同类名装饰器(该参数只对同一个类 kind中的不同函数类装饰器有效
|
||||
同步和异步装饰器属于互不干扰类型, 每个大类 kind中的参数只对该大类中的函数类装饰器有效)
|
||||
:param judge_msg: 判断是否为该装饰器所处理的消息的函数
|
||||
"""
|
||||
if func in self._message_callback_func_list: return
|
||||
self._message_callback_func_list.append(func)
|
||||
self._message_callback_func[func] = bot
|
||||
|
||||
self._cbFunc[func] = {
|
||||
'bot': bot,
|
||||
'kind': kind,
|
||||
'func_kind': register_name,
|
||||
'allow_other_rec': allow_other_rec,
|
||||
'judge_msg': judge_msg,
|
||||
}
|
||||
|
||||
|
||||
def _run_func(self):
|
||||
@ -31,29 +49,84 @@ def _run_func(self):
|
||||
try:
|
||||
async_func = []
|
||||
universal_func = []
|
||||
for ele in self._message_callback_func:
|
||||
# 将装饰器中的函数分为异步和同步
|
||||
for ele in self._cbFunc:
|
||||
if asyncio.iscoroutinefunction(ele):
|
||||
async_func.append(ele)
|
||||
else:
|
||||
universal_func.append(ele)
|
||||
|
||||
# 支持在这里自定义函数过滤消息, 以及使得否分发给所有函数
|
||||
def filter_message(universal_func_list, async_func_list, msg):
|
||||
"""
|
||||
根据每个装饰器的过滤要求过滤消息, 以及对分发的函数的限制
|
||||
"""
|
||||
# 对分类后的函数, 分别进行消息函数 函数类分类
|
||||
_join_thread_func = []
|
||||
_join_loop_func = []
|
||||
# 对函数类分类结果判断是否分类过, 若分过类直接跳过, 拒绝再次分类, 否则进行一遍筛选
|
||||
if not self._inCache:
|
||||
# 对传入的过滤函数按照 kind进行分组
|
||||
for f_ele in self._cbFunc:
|
||||
if self._kind_dict[self._cbFunc[f_ele]['kind']].get(self._cbFunc[f_ele]['func_kind'], None) is None:
|
||||
self._kind_dict[self._cbFunc[f_ele]['kind']][self._cbFunc[f_ele]['func_kind']] = {
|
||||
'kind': self._cbFunc[f_ele]['kind'],
|
||||
'func_kind': self._cbFunc[f_ele]['func_kind'],
|
||||
'allow_other_rec': self._cbFunc[f_ele]['allow_other_rec'],
|
||||
'judge_msg': self._cbFunc[f_ele]['judge_msg'],
|
||||
}
|
||||
self._kind_dict[self._cbFunc[f_ele]['kind']][self._cbFunc[f_ele]['func_kind']]['fun'] = []
|
||||
self._kind_dict[self._cbFunc[f_ele]['kind']][self._cbFunc[f_ele]['func_kind']]['fun'].append(f_ele)
|
||||
if f_ele not in (li := self._kind_dict[self._cbFunc[f_ele]['kind']][self._cbFunc[f_ele]['func_kind']]['fun']):
|
||||
li.append(f_ele)
|
||||
|
||||
self._inCache = True
|
||||
|
||||
# 判断任意两个大类 kind 中是否存在全函数类 allow_other_rec 都为 True 的情况, 若出现, 则不进行该大类的函数的消息限制分发, 消息分发给所有函数类
|
||||
if len(lis := ([al_ele['allow_other_rec'] for al_ele in self._kind_dict['async'].values()])) == 1 and lis[0]:
|
||||
self._loop_flag = True
|
||||
_join_loop_func = async_func_list
|
||||
|
||||
if len(lis := ([al_ele['allow_other_rec'] for al_ele in self._kind_dict['universal'].values()])) == 1 and lis[0]:
|
||||
self._thread_flag = True
|
||||
_join_thread_func = universal_func_list
|
||||
|
||||
# 进行仔细过滤, 对有消息分发限制的函数进行识别, 只把消息分发给符合限制的函数
|
||||
for f_ele in self._kind_dict.values():
|
||||
for k_ele in f_ele.values():
|
||||
if k_ele['kind'] == 'async' and not self._loop_flag:
|
||||
if k_ele['judge_msg'](msg):
|
||||
if not k_ele['allow_other_rec']:
|
||||
_join_loop_func = self._kind_dict[k_ele['kind']][k_ele['func_kind']]['fun']
|
||||
break
|
||||
else:
|
||||
_join_loop_func.extend(self._kind_dict[k_ele['kind']][k_ele['func_kind']]['fun'])
|
||||
elif k_ele['kind'] == 'universal' and not self._thread_flag:
|
||||
if k_ele['judge_msg'](msg) and not k_ele['allow_other_rec']:
|
||||
if not k_ele['allow_other_rec']:
|
||||
_join_thread_func = self._kind_dict[k_ele['kind']][k_ele['func_kind']]['fun']
|
||||
break
|
||||
else:
|
||||
_join_thread_func.extend(self._kind_dict[k_ele['kind']][k_ele['func_kind']]['fun'])
|
||||
return _join_thread_func, _join_loop_func
|
||||
|
||||
universal_func, async_func = filter_message(universal_func, async_func, self._message)
|
||||
|
||||
# 同步函数运行器
|
||||
def run_universal_func():
|
||||
for fn in universal_func:
|
||||
fn(self._message_callback_func[fn], self._message)
|
||||
fn(self._cbFunc[fn]['bot'], self._message)
|
||||
|
||||
if len(universal_func) != 0: Thread(target=run_universal_func).start()
|
||||
if len(async_func) == 0: return
|
||||
|
||||
# 异步函数运行器
|
||||
async def _run_callback():
|
||||
tasks = [asyncio.create_task(func(self._message_callback_func[func], self._message))
|
||||
for func in async_func]
|
||||
await asyncio.wait(tasks)
|
||||
_tasks = [asyncio.create_task(
|
||||
a_ele(
|
||||
self._cbFunc[a_ele]['bot'], self._message)) for a_ele in async_func]
|
||||
return await asyncio.wait(_tasks)
|
||||
|
||||
self._loop.run_until_complete(_run_callback())
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
||||
|
@ -1,14 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from abc import abstractmethod
|
||||
import logging
|
||||
from typing import Callable, Any
|
||||
from wcfauto.wcf import WcfV2 as Wcf
|
||||
from wcfauto.wcf import WxMsgV2 as WxMsg
|
||||
import asyncio
|
||||
|
||||
|
||||
class Event(object):
|
||||
_message_callback_func = {}
|
||||
_cbFunc = {}
|
||||
_loop_flag = False
|
||||
_thread_flag = False
|
||||
_inCache = False
|
||||
_message_callback_func_list = []
|
||||
_loop = asyncio.get_event_loop()
|
||||
_filter_cache = {}
|
||||
_kind_dict = {'async': {}, 'universal': {}}
|
||||
|
||||
def __init__(self):
|
||||
super(Event, self).__init__()
|
||||
@ -16,18 +23,29 @@ class Event(object):
|
||||
self._logger: logging = logging.getLogger()
|
||||
|
||||
@abstractmethod
|
||||
def _add_callback(self, func, *args, **kwargs):
|
||||
def _add_callback(self,
|
||||
func: Callable[[Any], Any],
|
||||
bot: Wcf,
|
||||
kind: str,
|
||||
register_name: str,
|
||||
allow_other_rec: bool,
|
||||
judge_msg: Callable[[WxMsg], bool]):
|
||||
"""
|
||||
消息处理函数加载器
|
||||
:param func: 消息处理函数
|
||||
:param args: 消息处理函数参数
|
||||
:param kwargs: 消息处理函数参数
|
||||
:param func: 装饰器装饰的函数
|
||||
:param bot: Wcf类
|
||||
:param kind: 装饰器所处类别, 分为异步和同步
|
||||
:param register_name: 装饰器所处类别下的函数类名(主要区分不同装饰器的作用, 以及为其中的 allow_other_rec参数做准备)
|
||||
:param allow_other_rec: 是否允许消息分发到其他不同类名装饰器(该参数只对同一个类 kind中的不同函数类装饰器有效
|
||||
同步和异步装饰器属于互不干扰类型, 每个大类 kind中的参数只对该大类中的函数类装饰器有效)
|
||||
:param judge_msg: 判断是否为该装饰器所处理的消息的函数
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _run_func(self):
|
||||
"""
|
||||
消息分发器, 将消息发送给所有消息处理函数
|
||||
消息分发器, 将消息发送给可接受消息的消息处理函数
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
51
clients/pyauto/wcfauto/msg_list.py
Normal file
51
clients/pyauto/wcfauto/msg_list.py
Normal file
@ -0,0 +1,51 @@
|
||||
# coding: utf-8
|
||||
# @Author: 小杨大帅哥
|
||||
import queue
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
class messageList(list):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(messageList, self).__init__(*args, **kwargs)
|
||||
self.__isRunning = True
|
||||
self.__th = None
|
||||
self.__time_step = 2*60
|
||||
self.__msg_queen = queue.Queue()
|
||||
self.start()
|
||||
|
||||
def append(self, item) -> None:
|
||||
self.__isRunning = True
|
||||
if item['data'].get('msgid', None) is None:
|
||||
return
|
||||
super(messageList, self).append({str(item['data']['msgid']): item})
|
||||
self.__msg_queen.put({'data': item, 'submit_time': time.time()})
|
||||
|
||||
def stop(self):
|
||||
self.__isRunning = False
|
||||
|
||||
def find_msg(self, msgid):
|
||||
msgid = str(msgid)
|
||||
for msg_ele in self:
|
||||
if str(msgid) == str(list(msg_ele.keys())[0]):
|
||||
return msg_ele[msgid]
|
||||
return None
|
||||
|
||||
def start(self):
|
||||
def _start():
|
||||
while True:
|
||||
if self.__isRunning:
|
||||
try:
|
||||
new_data = self.__msg_queen.get()
|
||||
now = time.time()
|
||||
if now - new_data['submit_time'] >= self.__time_step:
|
||||
self.remove({str(new_data['data']['data']['msgid']): new_data['data']})
|
||||
continue
|
||||
time.sleep(self.__time_step - (now - new_data['submit_time']))
|
||||
self.remove({str(new_data['data']['data']['msgid']): new_data['data']})
|
||||
except (queue.Empty, KeyboardInterrupt):
|
||||
pass
|
||||
self.__th = Thread(target=_start, name='run', daemon=True)
|
||||
self.__th.start()
|
||||
|
||||
|
||||
msg_list = messageList()
|
@ -2,12 +2,12 @@
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
from wcfauto.msg_list import msg_list
|
||||
from wcferry import Wcf, WxMsg
|
||||
|
||||
|
||||
class WcfV2(Wcf):
|
||||
def __init__(self, host: str, port: int = 10086, debug: bool = True) -> None:
|
||||
def __init__(self, host: str = None, port: int = 10086, debug: bool = True) -> None:
|
||||
super().__init__(host, port, debug)
|
||||
|
||||
def get_msg(self, block=True) -> WxMsg:
|
||||
@ -27,8 +27,9 @@ class WcfV2(Wcf):
|
||||
|
||||
class WxMsgV2(WxMsg):
|
||||
"""微信消息
|
||||
|
||||
Attributes:
|
||||
type (int): 消息类型,可通过 `get_msg_types` 获取
|
||||
type (int): 消息类型,可通过 `wcf类的 get_msg_types` 获取
|
||||
id (str): 消息 id
|
||||
xml (str): 消息 xml 部分
|
||||
sender (str): 消息发送人
|
||||
@ -39,8 +40,6 @@ class WxMsgV2(WxMsg):
|
||||
"""
|
||||
|
||||
def __init__(self, msg: WxMsg) -> None:
|
||||
# self._is_self = msg._is_self
|
||||
# self._is_group = msg._is_group
|
||||
self._type = msg.type
|
||||
self._id = msg.id
|
||||
self._ts = msg.ts
|
||||
@ -49,8 +48,8 @@ class WxMsgV2(WxMsg):
|
||||
self._sender = msg.sender
|
||||
self._roomid = msg.roomid
|
||||
self._content = msg.content
|
||||
self._thumb = msg.thumb
|
||||
self._extra = msg.extra
|
||||
self._thumb = msg.thumb.replace("\\", "/")
|
||||
self._extra = msg.extra.replace("\\", "/")
|
||||
self.__data = {'isSelf': True if self._is_self else False,
|
||||
'isGroup': True if self._is_group else False,
|
||||
'isPyq': True if self._type == 0 else False,
|
||||
@ -64,20 +63,54 @@ class WxMsgV2(WxMsg):
|
||||
'thumb': self._thumb if self._thumb else None,
|
||||
'extra': self._extra if self._extra else None,
|
||||
'time': int(time.time() * 1000),
|
||||
}, 'revokmsgid': None, 'isRevokeMsg': False, }
|
||||
}, 'revokmsgid': None, 'isRevokeMsg': False}
|
||||
self.__revokmsg_p()
|
||||
self.__initial()
|
||||
msg_list.append(self)
|
||||
|
||||
def __revokmsg_p(self):
|
||||
rmsg = self.__data['data']['content']
|
||||
rev_type = re.findall('<sysmsg type="(.*?)"\s?', rmsg)
|
||||
rev_w = re.findall("<replacemsg><!\[CDATA\[(.*?)]]></replacemsg>", rmsg)
|
||||
rev_type = re.findall(r'<sysmsg type="(.*?)"\s?', rmsg)
|
||||
rev_w = re.findall(r"<replacemsg><!\[CDATA\[(.*?)]]></replacemsg>", rmsg)
|
||||
if len(rev_type) == 0 or len(rev_w) == 0:
|
||||
return
|
||||
if rev_type[0] == 'revokemsg' and rev_w[0] == '你撤回了一条消息':
|
||||
if rev_type[0] == 'revokemsg' and '撤回了一条消息' in rev_w[0]:
|
||||
self.__data['data']['content'] = rev_w[0]
|
||||
self.__data['isRevokeMsg'] = True
|
||||
self.__data['revokmsgid'] = re.findall('<newmsgid>(.*?)</newmsgid>', rmsg)[0]
|
||||
|
||||
def __initial(self):
|
||||
try:
|
||||
if self.__data['data']['type'] == 51:
|
||||
op_id = re.findall(r"<op id='(\d+)'>", self.__data['data']['content'])[0]
|
||||
name = re.findall(r'<name>(.*?)</name>', self.__data['data']['content'])[0].strip()
|
||||
if name == 'lastMessage' and str(op_id) == '2':
|
||||
username = re.findall(r'<username>(.*?)</username>', self.__data['data']['content'])[0]
|
||||
self.__data['data']['xml'] = self.__data['data']['content']
|
||||
self.__data['data']['content'] = f'其他设备进入 [{username}] 聊天界面'
|
||||
return
|
||||
if name == 'HandOffMaster' and str(op_id) == '11':
|
||||
opcode = re.findall(r'opcode="(\d+)"', self.__data['data']['content'])[0]
|
||||
self.__data['data']['xml'] = self.__data['data']['content']
|
||||
title = '' or re.findall(r'<title><!\[CDATA\[(.*?)]]></title>', self.__data['data']['content'])[0]
|
||||
type_id = re.findall(r'<handoff\s+type="(\d+)"', self.__data['data']['content'])[0]
|
||||
type_map = {'2': '公众号文章', '3': '小程序'}
|
||||
if str(opcode) == '1':
|
||||
self.__data['data']['content'] = f'其他设备进入{type_map[str(type_id)]} [{title}]'
|
||||
elif str(opcode) == '2':
|
||||
self.__data['data']['content'] = f'其他设备离开{type_map[str(type_id)]} [{title}]'
|
||||
elif str(opcode) == '3':
|
||||
self.__data['data']['content'] = f'其他设备在{type_map[str(type_id)]} [{title}] 里进行跳转'
|
||||
elif str(opcode) == '4':
|
||||
self.__data['data']['content'] = f'其他设备进入{type_map[str(type_id)]} [{title}]'
|
||||
return
|
||||
if name == 'MomentsUnreadMsgStatus' or name == 'MomentsTimelineStatus':
|
||||
self.__data['data']['xml'] = self.__data['data']['content']
|
||||
self.__data['data']['content'] = f'其他设备进入朋友圈'
|
||||
return
|
||||
except:
|
||||
pass
|
||||
|
||||
def __str__(self) -> str:
|
||||
return repr(self.__data)
|
||||
|
||||
@ -139,3 +172,14 @@ class WxMsgV2(WxMsg):
|
||||
def is_text(self) -> bool:
|
||||
"""是否文本消息"""
|
||||
return self.type == 1
|
||||
|
||||
def get_revoke_msg(self) -> "WxMsg" or None:
|
||||
"""
|
||||
获取撤回的消息
|
||||
注意仅有撤回的消息在调用函数会返回消息内容, 自行修改 msg内容或者不是撤回的消息在调用该函数后会返回 None
|
||||
未撤回的消息调用该函数会返回 None
|
||||
:return: 返回被撤回的信息, 信息的类仍然是 WxMsg
|
||||
"""
|
||||
if self.__data['isRevokeMsg'] and (self.__data['revokmsgid'] is not None):
|
||||
return msg_list.find_msg(self.__data['revokmsgid'])
|
||||
return None
|
||||
|
Loading…
Reference in New Issue
Block a user