Files
WechatHookBot/WechatHook/callbacks.py
2025-12-03 15:48:44 +08:00

193 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
回调处理器
实现 Socket 回调的装饰器和处理机制
"""
import copy
import ctypes
from ctypes import WINFUNCTYPE
from functools import wraps
from typing import Callable, List
from loguru import logger
# 全局回调列表
_GLOBAL_CONNECT_CALLBACK_LIST: List[Callable] = []
_GLOBAL_RECV_CALLBACK_LIST: List[Callable] = []
_GLOBAL_CLOSE_CALLBACK_LIST: List[Callable] = []
def CONNECT_CALLBACK(in_class: bool = False):
"""
连接回调装饰器
Args:
in_class: 是否是类方法
Usage:
@CONNECT_CALLBACK()
def on_connect(client_id):
pass
@CONNECT_CALLBACK(in_class=True)
def on_connect(self, client_id):
pass
"""
def decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
if in_class:
wrapper._wx_connect_handled = True
else:
_GLOBAL_CONNECT_CALLBACK_LIST.append(wrapper)
return wrapper
return decorator
def RECV_CALLBACK(in_class: bool = False):
"""
接收消息回调装饰器
Args:
in_class: 是否是类方法
Usage:
@RECV_CALLBACK()
def on_receive(client_id, message_type, data):
pass
@RECV_CALLBACK(in_class=True)
def on_receive(self, client_id, message_type, data):
pass
"""
def decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
if in_class:
wrapper._wx_recv_handled = True
else:
_GLOBAL_RECV_CALLBACK_LIST.append(wrapper)
return wrapper
return decorator
def CLOSE_CALLBACK(in_class: bool = False):
"""
断开连接回调装饰器
Args:
in_class: 是否是类方法
Usage:
@CLOSE_CALLBACK()
def on_close(client_id):
pass
@CLOSE_CALLBACK(in_class=True)
def on_close(self, client_id):
pass
"""
def decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
if in_class:
wrapper._wx_close_handled = True
else:
_GLOBAL_CLOSE_CALLBACK_LIST.append(wrapper)
return wrapper
return decorator
def add_callback_handler(callback_handler):
"""
添加回调处理器实例
Args:
callback_handler: 包含回调方法的对象
"""
import inspect
for name, method in inspect.getmembers(callback_handler, callable):
if hasattr(method, '_wx_connect_handled'):
_GLOBAL_CONNECT_CALLBACK_LIST.append(method)
logger.debug(f"注册连接回调: {name}")
elif hasattr(method, '_wx_recv_handled'):
_GLOBAL_RECV_CALLBACK_LIST.append(method)
logger.debug(f"注册接收回调: {name}")
elif hasattr(method, '_wx_close_handled'):
_GLOBAL_CLOSE_CALLBACK_LIST.append(method)
logger.debug(f"注册断开回调: {name}")
@WINFUNCTYPE(None, ctypes.c_void_p)
def wechat_connect_callback(client_id):
"""
微信连接回调C 函数)
Args:
client_id: 客户端 ID
"""
logger.info(f"[回调] 客户端连接: {client_id}")
for func in _GLOBAL_CONNECT_CALLBACK_LIST:
try:
func(client_id)
except Exception as e:
logger.error(f"连接回调执行失败: {e}")
@WINFUNCTYPE(None, ctypes.c_long, ctypes.c_char_p, ctypes.c_ulong)
def wechat_recv_callback(client_id, data, length):
"""
微信接收消息回调C 函数)
Args:
client_id: 客户端 ID
data: 消息数据JSON 字符串)
length: 数据长度
"""
try:
import json
# 深拷贝数据
data = copy.deepcopy(data)
json_data = data.decode('utf-8')
dict_data = json.loads(json_data)
msg_type = dict_data.get('type')
msg_data = dict_data.get('data', {})
logger.info(f"[回调] 收到消息: type={msg_type}, data={msg_data}")
# 调用所有注册的回调
for func in _GLOBAL_RECV_CALLBACK_LIST:
try:
func(client_id, msg_type, msg_data)
except Exception as e:
logger.error(f"接收回调执行失败: {e}")
except Exception as e:
logger.error(f"解析消息失败: {e}")
@WINFUNCTYPE(None, ctypes.c_ulong)
def wechat_close_callback(client_id):
"""
微信断开连接回调C 函数)
Args:
client_id: 客户端 ID
"""
logger.warning(f"[回调] 客户端断开: {client_id}")
for func in _GLOBAL_CLOSE_CALLBACK_LIST:
try:
func(client_id)
except Exception as e:
logger.error(f"断开回调执行失败: {e}")