async def validate( self, method: str, data: dict, response: Any, ctx_api: Union["ABCAPI", "API"], ) -> Union[Any, NoReturn]: if isinstance(response, dict): return response elif isinstance(response, str): return json.loads(response) logger.info( "VK returned object of invalid type ({}). Request will be rescheduled with {}", type(response).__name__, ctx_api.request_rescheduler.__class__.__name__, ) return await self.validate( method, data, await ctx_api.request_rescheduler.reschedule(ctx_api, method, data, response), ctx_api, )
async def validate( self, method: str, data: dict, response: typing.Any, ctx_api: typing.Union["ABCAPI", "API"], ) -> typing.Union[typing.Any, typing.NoReturn]: if isinstance(response, dict): return response elif isinstance(response, str): return json.loads(response) logger.info( f"VK returned object of invalid type ({type(response)})." f"Request will be rescheduled with {ctx_api.request_rescheduler.__class__.__name__!r}" ) return await self.validate( method, data, await ctx_api.request_rescheduler.reschedule(ctx_api, method, data, response), ctx_api, )
def run_forever( self, loop: Optional[AbstractEventLoop] = None ) -> NoReturn: # type: ignore """Runs startup tasks and makes the loop running forever""" if not len(self.tasks): logger.warning("You ran loop with 0 tasks. Is it ok?") loop = loop or get_event_loop() try: [ loop.run_until_complete(startup_task) for startup_task in self.on_startup ] if self.auto_reload: loop.create_task(watch_to_reload(self.auto_reload_dir)) for task in self.tasks: loop.create_task(task) loop.run_forever() except KeyboardInterrupt: logger.info("Keyboard Interrupt") finally: [ loop.run_until_complete(shutdown_task) for shutdown_task in self.on_shutdown ] if loop.is_running(): loop.close()
async def watch_to_reload(check_dir: str): """ Coro which see changes in your code and restart him. :return: """ async for _ in awatch(check_dir): logger.info("Changes were found. Restarting...") restart()
async def run_polling(self, custom_polling: Optional[ABCPolling] = None ) -> NoReturn: polling = custom_polling or self.polling logger.info(f"Starting polling for {polling.api!r}") async for event in polling.listen(): # type: ignore logger.debug(f"New event was received: {event}") for update in event["updates"]: await self.router.route(update, polling.api)
async def run_polling(self, custom_polling: Optional["ABCPolling"] = None): polling = custom_polling or self.polling logger.info("Starting polling for {!r}", polling.api) async for event in polling.listen(): logger.debug("New event was received: {}", event) for update in event["updates"]: if not self.task_each_event: await self.router.route(update, polling.api) else: self.loop.create_task(self.router.route(update, polling.api))
async def run_polling(self, custom_polling: Optional["ABCPolling"] = None) -> NoReturn: polling = custom_polling or self.polling logger.info(f"Starting polling for {polling.api!r}") async for event in polling.listen(): # type: ignore logger.debug(f"New event was received: {event}") for update in event.get("updates", []): if not self.task_each_event: await self.router.route(update, polling.api) else: self.loop.create_task(self.router.route(update, polling.api))
async def handle_event(self, event: T_contra, ctx_api: "ABCAPI", state_dispenser: "ABCStateDispenser") -> Any: logger.debug("Handling event ({}) with message view".format( self.get_event_type(event))) context_variables: dict = {} handle_responses = [] handlers = [] mw_instances = await self.pre_middleware(event, context_variables) if mw_instances is None: logger.info("Handling stopped, pre_middleware returned error") return for handler_basement in self.get_handler_basements(event): event_model = self.get_event_model(handler_basement, event) if isinstance(event_model, dict): event_model["ctx_api"] = ctx_api else: setattr(event_model, "unprepared_ctx_api", ctx_api) result = await handler_basement.handler.filter(event_model) logger.debug("Handler {} returned {}".format( handler_basement.handler, result)) if result is False: continue elif isinstance(result, dict): context_variables.update(result) handler_response = await handler_basement.handler.handle( event_model, **context_variables) handle_responses.append(handler_response) handlers.append(handler_basement.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, event_model, context_variables, ) if handler_basement.handler.blocking: break await self.post_middleware(mw_instances, handle_responses, handlers)
async def handle_event(self, event: T_contra, ctx_api: "ABCAPI", state_dispenser: "ABCStateDispenser") -> None: # For user event mapping, consider checking out # https://dev.vk.com/api/user-long-poll/getting-started logger.debug("Handling event ({}) with message view".format( self.get_event_type(event))) context_variables: dict = {} message = await self.get_message(event, ctx_api) message.state_peer = await state_dispenser.cast( self.get_state_key(message)) for text_ax in self.default_text_approximators: message.text = text_ax(message) mw_instances = await self.pre_middleware(message, context_variables) if mw_instances is None: logger.info("Handling stopped, pre_middleware returned error") return 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 await self.post_middleware(mw_instances, handle_responses, handlers)
async def reschedule( self, ctx_api: Union["ABCAPI", "API"], method: str, data: dict, recent_response: Any, ) -> dict: logger.debug( "Usage of blocking rescheduler is assumed when VK doesn't respond to " "all requests for an amount of time. Starting..." ) attempt_number = 1 while not isinstance(recent_response, dict): logger.info(f"Attempt number {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 handle_event(self, event: dict, ctx_api: "ABCAPI", state_dispenser: "ABCStateDispenser") -> Any: logger.debug("Handling event ({}) with message view".format( event.get("event_id"))) context_variables: dict = {} message = message_min(event, ctx_api) message.state_peer = await state_dispenser.cast( self.get_state_key(event)) for text_ax in self.default_text_approximators: message.text = text_ax(message) if await self.pre_middleware(message, context_variables) is False: return logger.info( "Handling stopped, pre_middleware returned error") 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 await self.post_middleware(self, handle_responses, handlers)
async def handle_event( self, event: dict, ctx_api: "ABCAPI", state_dispenser: "ABCStateDispenser" ) -> Any: logger.debug("Handling event ({}) with message view".format(event.get("event_id"))) handler_basement = self.handlers[GroupEventType(event["type"])] context_variables: dict = {} event_model = handler_basement.dataclass(**event) if isinstance(event_model, dict): event_model["ctx_api"] = ctx_api else: setattr(event_model, "unprepared_ctx_api", ctx_api) if await self.pre_middleware(event_model, context_variables): return logger.info("Handling stopped, pre_middleware returned error") result = await handler_basement.handler.filter(event_model) logger.debug("Handler {} returned {}".format(handler_basement.handler, result)) if result is False: return elif isinstance(result, dict): context_variables.update(result) handler_response = await handler_basement.handler.handle(event_model, **context_variables) 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, event_model, context_variables, ) await self.post_middleware(self, [handler_response], [handler_basement.handler])
def run_forever(self) -> NoReturn: logger.info("Loop will be ran forever") self.loop_wrapper.add_task(self.run_polling()) self.loop_wrapper.run_forever(self.loop)