对报错进行了修复, 新加几个装饰器,以及防撤回

This commit is contained in:
Mr.yang 2023-10-08 22:02:57 +08:00
parent e759e5fa9d
commit f321ed6d85
11 changed files with 485 additions and 72 deletions

View File

@ -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()
```
|![碲矿](https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/TEQuant.jpg)|![赞赏](https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/QR.jpeg)|

View File

@ -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()

View File

@ -5,3 +5,4 @@ from wcfauto.wcf import WcfV2 as Wcf
from wcfauto.wcf import WxMsgV2 as WxMsg
__version__ = "39.0.3.0"

View File

@ -5,3 +5,4 @@ from wcfauto.auto_res.core import load_function
Register = load_function(Register)

View File

@ -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):
"""
启动程序, 开始接受消息
"""

View File

@ -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()

View File

@ -4,3 +4,8 @@ from wcfauto.event.event import Event
from wcfauto.event.core import load_function
Event = load_function(Event)

View File

@ -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()

View File

@ -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

View 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()

View File

@ -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