bugfix
This commit is contained in:
parent
fb25b4a28d
commit
6cf4dbb8cc
@ -3,196 +3,197 @@ import inspect
|
||||
import traceback
|
||||
import weakref
|
||||
from typing import Callable, Any
|
||||
from appPublic.log import debug, error, exception, warning
|
||||
|
||||
|
||||
class WeakCallback:
|
||||
|
||||
def __init__(self, func: Callable):
|
||||
def __init__(self, func: Callable):
|
||||
|
||||
self._is_coroutine = inspect.iscoroutinefunction(func)
|
||||
self._is_coroutine = inspect.iscoroutinefunction(func)
|
||||
|
||||
if inspect.ismethod(func):
|
||||
self._ref = weakref.WeakMethod(func)
|
||||
else:
|
||||
self._ref = weakref.ref(func)
|
||||
if inspect.ismethod(func):
|
||||
self._ref = weakref.WeakMethod(func)
|
||||
else:
|
||||
self._ref = weakref.ref(func)
|
||||
|
||||
self._hash = hash(func)
|
||||
self._hash = hash(func)
|
||||
|
||||
@property
|
||||
def is_coroutine(self):
|
||||
return self._is_coroutine
|
||||
@property
|
||||
def is_coroutine(self):
|
||||
return self._is_coroutine
|
||||
|
||||
def get(self):
|
||||
return self._ref()
|
||||
def get(self):
|
||||
return self._ref()
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, WeakCallback) and self._hash == other._hash
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, WeakCallback) and self._hash == other._hash
|
||||
|
||||
def __hash__(self):
|
||||
return self._hash
|
||||
def __hash__(self):
|
||||
return self._hash
|
||||
|
||||
|
||||
class EventDispatcher:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
continue_on_error=True,
|
||||
log_traceback=True,
|
||||
handler_timeout=None,
|
||||
error_handler=None,
|
||||
):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
continue_on_error=True,
|
||||
log_traceback=True,
|
||||
handler_timeout=None,
|
||||
error_handler=None,
|
||||
):
|
||||
|
||||
self._events = {}
|
||||
self._events = {}
|
||||
|
||||
self.continue_on_error = continue_on_error
|
||||
self.log_traceback = log_traceback
|
||||
self.handler_timeout = handler_timeout
|
||||
self.error_handler = error_handler
|
||||
self.continue_on_error = continue_on_error
|
||||
self.log_traceback = log_traceback
|
||||
self.handler_timeout = handler_timeout
|
||||
self.error_handler = error_handler
|
||||
|
||||
def bind(self, event_name: str, func: Callable):
|
||||
def bind(self, event_name: str, func: Callable):
|
||||
|
||||
if event_name not in self._events:
|
||||
self._events[event_name] = set()
|
||||
if event_name not in self._events:
|
||||
self._events[event_name] = set()
|
||||
|
||||
self._events[event_name].add(WeakCallback(func))
|
||||
self._events[event_name].add(WeakCallback(func))
|
||||
|
||||
def unbind(self, event_name: str, func: Callable):
|
||||
def unbind(self, event_name: str, func: Callable):
|
||||
|
||||
if event_name not in self._events:
|
||||
return
|
||||
if event_name not in self._events:
|
||||
return
|
||||
|
||||
target = WeakCallback(func)
|
||||
target = WeakCallback(func)
|
||||
|
||||
self._events[event_name] = {
|
||||
cb for cb in self._events[event_name]
|
||||
if cb != target
|
||||
}
|
||||
self._events[event_name] = {
|
||||
cb for cb in self._events[event_name]
|
||||
if cb != target
|
||||
}
|
||||
|
||||
if not self._events[event_name]:
|
||||
del self._events[event_name]
|
||||
if not self._events[event_name]:
|
||||
del self._events[event_name]
|
||||
|
||||
async def _run_error_handler(
|
||||
self,
|
||||
event_name,
|
||||
func,
|
||||
exc,
|
||||
):
|
||||
async def _run_error_handler(
|
||||
self,
|
||||
event_name,
|
||||
func,
|
||||
exc,
|
||||
):
|
||||
|
||||
if not self.error_handler:
|
||||
return
|
||||
if not self.error_handler:
|
||||
return
|
||||
|
||||
try:
|
||||
try:
|
||||
|
||||
if inspect.iscoroutinefunction(self.error_handler):
|
||||
await self.error_handler(
|
||||
event_name,
|
||||
func,
|
||||
exc,
|
||||
)
|
||||
else:
|
||||
self.error_handler(
|
||||
event_name,
|
||||
func,
|
||||
exc,
|
||||
)
|
||||
if inspect.iscoroutinefunction(self.error_handler):
|
||||
await self.error_handler(
|
||||
event_name,
|
||||
func,
|
||||
exc,
|
||||
)
|
||||
else:
|
||||
self.error_handler(
|
||||
event_name,
|
||||
func,
|
||||
exc,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[EventDispatcher] error_handler failed: {e}")
|
||||
except Exception as e:
|
||||
print(f"[EventDispatcher] error_handler failed: {e}")
|
||||
|
||||
async def _execute_handler(
|
||||
self,
|
||||
cb,
|
||||
event_name,
|
||||
data,
|
||||
):
|
||||
async def _execute_handler(
|
||||
self,
|
||||
cb,
|
||||
event_name,
|
||||
data,
|
||||
):
|
||||
|
||||
func = cb.get()
|
||||
func = cb.get()
|
||||
|
||||
if func is None:
|
||||
return False
|
||||
if func is None:
|
||||
return False
|
||||
|
||||
try:
|
||||
try:
|
||||
|
||||
if cb.is_coroutine:
|
||||
if cb.is_coroutine:
|
||||
|
||||
coro = func(data)
|
||||
coro = func(data)
|
||||
|
||||
if self.handler_timeout:
|
||||
await asyncio.wait_for(
|
||||
coro,
|
||||
timeout=self.handler_timeout,
|
||||
)
|
||||
else:
|
||||
await coro
|
||||
if self.handler_timeout:
|
||||
await asyncio.wait_for(
|
||||
coro,
|
||||
timeout=self.handler_timeout,
|
||||
)
|
||||
else:
|
||||
await coro
|
||||
|
||||
else:
|
||||
else:
|
||||
|
||||
if self.handler_timeout:
|
||||
if self.handler_timeout:
|
||||
|
||||
await asyncio.wait_for(
|
||||
asyncio.to_thread(func, data),
|
||||
timeout=self.handler_timeout,
|
||||
)
|
||||
await asyncio.wait_for(
|
||||
asyncio.to_thread(func, data),
|
||||
timeout=self.handler_timeout,
|
||||
)
|
||||
|
||||
else:
|
||||
func(data)
|
||||
else:
|
||||
func(data)
|
||||
|
||||
return True
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e:
|
||||
debug(
|
||||
f"[EventDispatcher] "
|
||||
f"handler failed: "
|
||||
f"event={event_name}, "
|
||||
f"handler={func}"
|
||||
)
|
||||
|
||||
print(
|
||||
f"[EventDispatcher] "
|
||||
f"handler failed: "
|
||||
f"event={event_name}, "
|
||||
f"handler={func}"
|
||||
)
|
||||
if self.log_traceback:
|
||||
debug(f'{trackback.format_exc()}')
|
||||
# traceback.print_exc()
|
||||
|
||||
if self.log_traceback:
|
||||
traceback.print_exc()
|
||||
await self._run_error_handler(
|
||||
event_name,
|
||||
func,
|
||||
e,
|
||||
)
|
||||
|
||||
await self._run_error_handler(
|
||||
event_name,
|
||||
func,
|
||||
e,
|
||||
)
|
||||
if not self.continue_on_error:
|
||||
raise
|
||||
|
||||
if not self.continue_on_error:
|
||||
raise
|
||||
return True
|
||||
|
||||
return True
|
||||
async def dispatch(
|
||||
self,
|
||||
event_name: str,
|
||||
data: Any = None,
|
||||
):
|
||||
|
||||
async def dispatch(
|
||||
self,
|
||||
event_name: str,
|
||||
data: Any = None,
|
||||
):
|
||||
if event_name not in self._events:
|
||||
return
|
||||
|
||||
if event_name not in self._events:
|
||||
return
|
||||
dead_callbacks = []
|
||||
|
||||
dead_callbacks = []
|
||||
for cb in list(self._events[event_name]):
|
||||
|
||||
for cb in list(self._events[event_name]):
|
||||
func = cb.get()
|
||||
|
||||
func = cb.get()
|
||||
if func is None:
|
||||
dead_callbacks.append(cb)
|
||||
continue
|
||||
|
||||
if func is None:
|
||||
dead_callbacks.append(cb)
|
||||
continue
|
||||
await self._execute_handler(
|
||||
cb,
|
||||
event_name,
|
||||
data,
|
||||
)
|
||||
|
||||
await self._execute_handler(
|
||||
cb,
|
||||
event_name,
|
||||
data,
|
||||
)
|
||||
for cb in dead_callbacks:
|
||||
self._events[event_name].discard(cb)
|
||||
|
||||
for cb in dead_callbacks:
|
||||
self._events[event_name].discard(cb)
|
||||
|
||||
if (
|
||||
event_name in self._events
|
||||
and not self._events[event_name]
|
||||
):
|
||||
del self._events[event_name]
|
||||
if (
|
||||
event_name in self._events
|
||||
and not self._events[event_name]
|
||||
):
|
||||
del self._events[event_name]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user