async def relogin(self, sleep=5, retries=None): self._ok = False unregister_session(self.qq) _retries = 0 while not retries or _retries < retries: _retries += 1 try: new_session_key = await self._auth() if not new_session_key: raise ApiError(Code.Unavailable) self._session_key = new_session_key self._api.update_session(new_session_key) res = await self._api.verify(qq=self._qq) if not res or res.get('code') != 0: raise ApiError(Code.Unavailable, "Verify failed") if self._enable_ws: asyncio.create_task(self.set_report_ws()) return True except ApiError as e: logger.info( f'Failed to login by {e}, retry in {sleep}s or exit ...') await asyncio.sleep(sleep)
async def connect(self): retries = 0 session_key = await self._auth() while not session_key and (retries < self._max_retries or self._max_retries < 0): retries += 1 logger.info( f"Connection failed. Retrying {retries}th time in {self._retry_interval}s ..." ) await asyncio.sleep(self._retry_interval) session_key = await self._auth() if not session_key: logger.critical(f"Connection failed. Exiting ...") return self._session_key = session_key self._api = api.HttpApi(self._api_root, session_key, 30) res = await self._api.verify(qq=self._qq) if not res or res.get('code') != 0: raise api.ApiError(api.Code.Unavailable, "Verify Failed") self._ok = True register_session(self, self.qq) if self._enable_ws: asyncio.create_task(self.set_report_ws()) if self._enable_poll: asyncio.create_task(self.set_poll())
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 _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 wrapper(self, *args, **kwargs): while True: try: return await func(self, *args, **kwargs) except ApiError as e: if e.code == ApiError.CODE_SESSION_FAILED: logger.info('Re-login Mirai') if not await self.relogin(): return ApiResult(Code.Unavailable) if await self._api.verify(qq=self.qq): logger.info('Re-login Success') continue else: return ApiResult(Code.Unavailable) else: return ApiResult(e.code) except Exception as e: logger.exception(e) return ApiResult(Code.Unspecified, message=str(e))
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 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))
def add_service(self, service): self.services[service.name] = service logger.info(f'Succeeded to load Service "{service.key}" ')