async def handle_event(source: EventProvider, event: Event, **kwargs): """Handle a event received from protocol To avoid blocking awaiting, creating a task to run this :param source: :param event: :return: """ if not isinstance(event, Event): logger.error(f'A non-event {event} passed to handle_event!') return logger.debug(f'Handling {event.type} {event}') res = [] async for result in engine.forward(event=event, source=source, **kwargs): if isinstance(result, Exception): try: raise result except Exception as e: logger.error(f'Error handling event {event} {e}') logger.exception(e) elif result: res.append(result) return res
async def _ws(): async with aiohttp.ClientSession() as client: async with client.ws_connect( f"{self._api_root}all?sessionKey={self._session_key}", **kwargs) as ws: while True: try: event = await ws.receive_json() except TypeError: if ws.closed: logger.warning( 'Websocket closed, try relogin in 10s') await asyncio.sleep(10) await self.relogin() return logger.error(f"TypeError in parsing ws event") continue if not event: continue logger.debug(f"[event] {event}") try: event = self.as_event(event) if event: self.handle_event_nowait(event) except Exception as e: logger.critical(e) return
async def _poll(): while True: try: res = await self._fetch_message() if res.ok: for event in res.data: self.handle_event_nowait(event) except Exception as e: logger.error(e) finally: await asyncio.sleep(interval)
async def _auth(self): try: async with aiohttp.request("POST", self._api_root + 'auth', json={'authKey': self._auth_key}) as resp: if 200 <= resp.status < 300: result = json.loads(await resp.text()) logger.info(f'Login Mirai: {result}') if result.get('code') == 0: return result['session'] except Exception as e: logger.error(e) return
async def unload_plugin(key: Union[str, Plugin], forced: bool = False) -> bool: """Unload a Plugin :param key: Plugin object or module path or name :param forced: Forced to unload :return: Success or not """ plugin = get_plugin(key) if isinstance(key, str) else key if not plugin: logger.warning(f"Plugin {key} not exists") return False plugin_name = plugin.name await meta_provider.send( MetaEvent(MetaEventType.PluginUnload, plugin=plugin)) for service in plugin.services.values(): try: remove_service(service) except Exception as e: logger.exception(e) logger.error(f'Failed to unload service "{service}", error: {e}') result = remove_plugin(plugin) if not result and not forced: return False if plugin.path: for module in list( filter(lambda x: x.startswith(plugin.path), sys.modules.keys())): del sys.modules[module] meta_provider.send_nowait( MetaEvent(MetaEventType.PluginUnloaded, plugin=plugin)) logger.info(f'Succeeded to unload Plugin "{plugin_name}"') return True
async def load_plugin(*, module_path: str = None, plugin_dir: str = None) -> Optional[Plugin]: """Load a Plugin by Plugin module path or Plugin directory :param module_path: :param plugin_dir: :return: """ if not plugin_dir: if not module_path: raise ValueError() elif module_path.startswith('.'): plugin_dir = '.' + module_path.replace('.', '/') else: plugin_dir = './' + module_path.replace('.', '/') else: if plugin_dir.startswith('.'): module_path = plugin_dir.replace('/', '.')[1:] else: module_path = plugin_dir.replace('/', '.') logger.info(f'Loading Plugin {module_path} from {plugin_dir} ...') try: plugin_info_path = os.path.join(os.path.expanduser(plugin_dir), ajenga.config.PLUGIN_INFO_FILE) with open(plugin_info_path, encoding='utf-8') as f: plugin_info = json.load(f) if plugin_info.get('name') and get_plugin(plugin_info['name']): logger.error(f'Plugin {plugin_info["name"]} already exists') return None plugin = Plugin(plugin_info, path=module_path) set_current_plugin(plugin) add_plugin(plugin) except Exception as e: logger.exception(e) logger.error(f'Failed to load Plugin config from {plugin_dir}') return None try: module = importlib.import_module(module_path) plugin.load(module) add_plugin(plugin, True) except Exception as e: logger.exception(e) logger.error(f'Failed to load Plugin module from {module_path}') await unload_plugin(plugin, True) return None await meta_provider.send(MetaEvent(MetaEventType.PluginLoad, plugin=plugin)) meta_provider.send_nowait( MetaEvent(MetaEventType.PluginLoaded, plugin=plugin)) logger.info(f'Succeeded to load Plugin "{plugin.name}"') return plugin
async def wrapper(self, *args, **kwargs): try: return await func(self, *args, **kwargs) except Exception as e: logger.exception(e) if (not _ALLOW_RETRY): if isinstance(self, CQSession): self.handle_event_nowait( ApiNotSuccessfulEvent(func.__name__, self.qq, args, kwargs)) return ApiResult(Code.Unspecified, message=str(e)) logger.info("Retrying...") try: return await func(*args, **kwargs) except Exception as e: logger.exception(e) logger.error("Retrying failed") if isinstance(self, CQSession): self.handle_event_nowait( ApiNotSuccessfulEvent(func.__name__, self.qq, args, kwargs)) return ApiResult(Code.Unspecified, message=str(e))