Files
biliup/common/event.py
T
2020-12-03 18:17:04 +08:00

168 lines
5.3 KiB
Python

# encoding: UTF-8
# 系统模块
import inspect
from collections import Generator
from concurrent.futures.thread import ThreadPoolExecutor
from dataclasses import dataclass, field
from queue import Queue
from threading import *
import functools
class EventManager(Thread):
def __init__(self, context=None):
"""初始化事件管理器"""
super().__init__(name='Synchronous')
if context is None:
context = {}
self.context = context
# 事件对象列表
self.__eventQueue = Queue()
# 事件管理器开关
self.__active = True
# 事件处理线程池1
self._pool1 = ThreadPoolExecutor(3, thread_name_prefix='Asynchronous1')
# 事件处理线程池2
self._pool2 = ThreadPoolExecutor(3, thread_name_prefix='Asynchronous2')
# 阻塞函数列表
self.__block = []
# 这里的__handlers是一个字典,用来保存对应的事件的响应函数
# 其中每个键对应的值是一个列表,列表中保存了对该事件监听的响应函数,一对多
self.__handlers = {}
self.__method = {}
def run(self):
while self.__active:
event = self.__eventQueue.get()
if event is not None:
self.__event_process(event)
def __event_process(self, event):
"""处理事件"""
# 检查是否存在对该事件进行监听的处理函数
if not self.__active or event.type_ not in self.__handlers:
return
# 若存在,则按顺序将事件传递给处理函数执行
for handler in self.__handlers[event.type_]:
if handler.__qualname__ in self.__block:
if event.type_ == 'download':
self._pool1.submit(handler, event)
else:
self._pool2.submit(handler, event)
else:
handler(event)
def stop(self):
"""停止"""
# 将事件管理器设为停止
self.__active = False
self.__eventQueue.put(None)
self._pool1.shutdown()
self._pool2.shutdown()
def add_event_listener(self, type_, handler):
"""绑定事件和监听器处理函数"""
# 尝试获取该事件类型对应的处理函数列表,若无则创建
try:
handlerlist = self.__handlers[type_]
except KeyError:
handlerlist = []
self.__handlers[type_] = handlerlist
# 若要注册的处理器不在该事件的处理器列表中,则注册该事件
if handler not in handlerlist:
handlerlist.append(handler)
def remove_event_listener(self, type_, handler):
"""移除监听器的处理函数"""
try:
handler_list = self.__handlers[type_]
for method in handler_list:
# 如果该函数存在于列表中,则移除
if handler.__qualname__ == method.__qualname__:
handler_list.remove(method)
# 如果函数列表为空,则从引擎中移除该事件类型
if not handler_list:
del self.__handlers[type_]
except KeyError:
pass
def send_event(self, event):
"""发送事件,向事件队列中存入事件"""
self.__eventQueue.put(event)
def register(self, type_, block=False):
classname = inspect.getouterframes(inspect.currentframe())[1][3]
def callback(result):
if not result:
pass
elif isinstance(result, (tuple, Generator)):
for event in result:
self.send_event(event)
else:
self.send_event(result)
def appendblock(fc, blk):
if blk:
self.__block.append(fc.__qualname__)
if classname == '<module>':
def decorator(func):
appendblock(func, block)
@functools.wraps(func)
def wrapper(event):
_event = func(*event.args)
callback(_event)
return _event
self.add_event_listener(type_, wrapper)
return wrapper
else:
def decorator(func):
appendblock(func, block)
self.__method.setdefault(type_, [])
self.__method[type_].append(func.__name__)
@functools.wraps(func)
def wrapper(this, event):
_event = func(this, *event.args)
callback(_event)
return _event
return wrapper
return decorator
def server(self):
def decorator(cls):
sig = inspect.signature(cls)
kwargs = {}
for k in sig.parameters:
kwargs[k] = self.context[k]
instance = cls(**kwargs)
for type_ in self.__method:
for handler in self.__method[type_]:
self.add_event_listener(type_, getattr(instance, handler))
self.__method.clear()
return cls
return decorator
@dataclass
class Event:
"""事件对象"""
type_: str # 事件类型
args: tuple = ()
dict: dict = field(default_factory=dict) # 字典用于保存具体的事件数据
event_manager = EventManager()