async def validate_request(self, request: dict) -> dict: """ Validates requests from Telegram, to change validations change API.request_validators (list of RequestValidator's) """ for validator in self.request_validators: request = await validator.validate(request) logger.debug("API request was validated") return request # type: ignore
async def validate_response( self, method: str, data: dict, response: typing.Union[dict, str] ) -> typing.Union[typing.Any, typing.NoReturn]: """ Validates response from Telegram, to change validations change API.response_validators (list of ResponseValidator's) """ for validator in self.response_validators: response = await validator.validate(method, data, response, self) logger.debug("API response was validated") return response # type: ignore
def restart(): args = sys.argv[:] logger.debug("Restarting: %s" % " ".join(args)) args.insert(0, sys.executable) if sys.platform == "win32": args = ['"%s"' % arg for arg in args] os.chdir(_startup_cwd) os.execv(sys.executable, args)
async def route(self, update: dict, ctx_api: "ABCAPI"): logger.debug("Routing update {}".format(update)) for view in self.views.values(): try: if not await view.process_update(update): continue await view.handle_update(update, ctx_api, self.state_dispenser) except BaseException as e: await self.error_handler.handle(e)
def synchronous_wrapper(*args, **kwargs): try: return func(*args, **kwargs) except exception as e: if exception_handler is not None: return exception_handler(e, *args, **kwargs) elif just_log: logger.error( f"{func.__name__} (handling with swear) has thrown an exception: \n\n{traceback.format_exc()}" ) elif just_return: return e finally: logger.debug(f"Function {func.__name__} was handled with swear")
async def handle_update(self, update: dict, ctx_api: "ABCAPI", state_dispenser: "ABCStateDispenser") -> Any: logger.debug("Handling update ({}) with message view".format( update.get("update_id"))) context_variables = {} message = message_min(update, ctx_api) message.state_peer = await state_dispenser.cast( self.get_state_key(update)) for text_ax in self.default_text_approximators: message.text = text_ax(message) for middleware in self.middlewares: response = await middleware.pre(message) if response == MiddlewareResponse(False): return elif isinstance(response, dict): context_variables.update(response) handle_responses = [] handlers = [] for handler in self.handlers: result = await handler.filter(message) logger.debug("Handler {} returned {}".format(handler, result)) if result is False: continue elif isinstance(result, dict): context_variables.update(result) handler_response = await handler.handle(message, **context_variables) handle_responses.append(handler_response) handlers.append(handler) return_handler = self.handler_return_manager.get_handler( handler_response) if return_handler is not None: await return_handler(self.handler_return_manager, handler_response, message, context_variables) if handler.blocking: break for middleware in self.middlewares: await middleware.post(message, self, handle_responses, handlers)
async def run_polling(self, custom_polling: Optional[ABCPolling] = None, apis_count: int = 0) -> NoReturn: polling = custom_polling or self.polling logger.info("Polling will be started!") async for update in polling.listen(): # type: ignore logger.debug("New update: {}", update) if self.apis: self.api = self.apis[apis_count] if not self.task_each_update: await self.router.route(update, self.api) else: self.loop.create_task(self.router.route(update, self.api))
async def request(self, method: str, data: typing.Optional[dict] = None) -> dict: """Makes a single request opening a session""" data = await self.validate_request(data) async with self.http as session: response = await session.request_text( "POST", url=self.request_url + method, json=data, ) logger.debug("Request {} with {} data returned {}".format( method, data, response)) return await self.validate_response(method, data, response)
def run_multibot(bot: Bot, apis: Iterable[ABCAPI], polling_type: Type[ABCPolling] = BotPolling): """Add run_polling with polling constructed from derived apis :param bot: Bot main instance (api is not required) :param apis: Iterable of apis :param polling_type: polling type to be ran """ for i, api_instance in enumerate(apis): logger.debug(f"Connecting API (index: {i})") polling = polling_type().construct(api_instance) api_instance.http = SingleSessionManager(AiohttpClient) bot.apis = apis bot.loop_wrapper.add_task( bot.run_polling(custom_polling=polling, apis_count=i)) bot.loop_wrapper.run_forever(bot.loop)
async def request_many( self, requests: typing.Iterable[APIRequest] # type: ignore ) -> typing.AsyncIterator[dict]: """ Makes many requests opening one session """ async with self.http as session: for request in requests: method, data = request.method, await self.validate_request( request.data) # type: ignore response = await session.request_text( "POST", url=self.request_url + method, json=data, ) logger.debug("Request {} with {} data returned {}".format( method, data, response)) yield await self.validate_response(method, data, response)
async def reschedule( self, ctx_api: typing.Union["ABCAPI", "API"], method: str, data: dict, recent_response: typing.Any, ) -> dict: logger.debug( "Tottle uses request_rescheduler when Telegram " "doesn't respond properly for an amount of time. Starting..." ) attempt_number = 1 while not isinstance(recent_response, dict): logger.info(f"Attempt №{attempt_number}. Making request...") blocking_sleep(self.delay * attempt_number) recent_response = await ctx_api.request(method, data) attempt_number += 1 logger.debug(f"Attempt succeed? - {isinstance(recent_response, dict)}") logger.info(f"Finally succeed after {self.delay ** attempt_number} seconds!") return recent_response
async def cast(self, peer_id: Optional[int]) -> Optional[StatePeer]: if peer_id is None: return None logger.debug(f"Casting state for peer_id {peer_id}") return await self.get(peer_id)