Пример #1
0
    async def _event_processor(self, obj: dict, event_type: str):
        """
        LongPoll Events Processor
        :param event_type: VK Server Event Type
        :param obj: VK Server Event Object
        """

        logger.debug(
            '-> EVENT FROM {} TYPE "{}"',
            get_attr(obj, ["user_id", "from_id"]),
            event_type.upper(),
        )

        for rule in self.on.event.rules:
            if await rule.check(event_type):
                event = rule.data["data"](**obj)
                await rule.call(event, *rule.context.args,
                                **rule.context.kwargs)

                logger.info(
                    'New event "{}" compiled with decorator <{}> (from: {})'.
                    format(
                        event_type.upper(),
                        rule.call.__name__,
                        get_attr(obj, ["user_id", "from_id"]),
                    ))
                return True
Пример #2
0
    async def event_processor(self, obj: dict, event_type: str):
        """ Bot polling event processor
        #TODO Reduce difference
        :param event_type: VK Server Event Type
        :param obj: VK Server Event Object
        """

        logger.debug(
            '-> EVENT FROM {} TYPE "{}"',
            get_attr(obj, ["user_id", "from_id"]),
            event_type.upper(),
        )

        for rule in self.handler.event.rules:
            if await rule.check(event_type):
                event = rule.data["data"](**obj)
                await rule.call(event, *rule.context.args,
                                **rule.context.kwargs)

                logger.info(
                    'New event "{}" compiled with decorator <{}> (from: {})'.
                    format(
                        event_type.upper(),
                        rule.call.__name__,
                        get_attr(obj, ["user_id", "from_id"]),
                    ))
                break
Пример #3
0
    async def _branched_processor(self, message: Message,
                                  middleware_args: list):
        logger.debug(
            '-> BRANCHED MESSAGE FROM {} TEXT "{}"',
            message.peer_id,
            message.text.replace("\n", " "),
        )

        disposal, branch = await self.branch.load(message.peer_id)

        for n, member in disposal.items():
            rules = member[1]
            for rule in rules:
                if not await rule(message):
                    break
            else:
                task = types.MethodType(member[0], branch)
                args = [a for rule in rules for a in rule.context.args]
                kwargs = {
                    k: v
                    for rule in rules for k, v in rule.context.kwargs.items()
                }
                await task(message, *middleware_args, *args, **kwargs),
                break

        logger.info(
            'New BRANCHED "{0}" compiled with branch <{2}> (from: {1})'.format(
                message.text.replace("\n", " "),
                message.from_id,
                '"{}" with {} kwargs'.format(
                    branch.key,
                    branch.context if len(branch.context) < 100 else
                    branch.context[1:99] + "...",
                ),
            ))
Пример #4
0
 async def emulate(self, event: dict):
     """ Emulate event """
     logger.debug("Response: {}", event)
     for update in event.get("updates", []):
         update_code, update_fields = update[0], update[1:]
         await self.handle.parent_processor(update, update_code,
                                            update_fields)
Пример #5
0
    async def run(self, skip_updates: bool, wait: int = DEFAULT_WAIT):
        """ Run bot polling forever
        Can be manually stopped with:
        bot.stop()
        """
        self.__wait = wait
        logger.debug("Polling will be started. Is it OK?")
        if self.__secret is not None:
            logger.warning("You set up secret and started polling. Removing secret")
            self.__secret = None

        if not self.status.dispatched:
            self.middleware.add_middleware(self.on.pre)
            await self.on.dispatch(self.get_current_rest)
            self.status.dispatched = True

        if not skip_updates:
            await self.get_updates()

        await self.get_server()
        logger.info("Polling successfully started. Press Ctrl+C to stop it")

        while not self._stop:
            event = await self.make_long_request(self.long_poll_server)
            if isinstance(event, dict) and event.get("ts"):
                self.loop.create_task(self.emulate(event))
                self.long_poll_server["ts"] = event["ts"]
            else:
                await self.get_server()

        logger.error("Polling was stopped")
Пример #6
0
    async def dispatch(self, get_current_rest: typing.Callable = None) -> None:
        """
        Dispatch handlers from only-handlers and both-handlers
        :param get_current_rest: REST from vkbottle-rest
        :return:
        """

        self.message_handler.rules += self.message.rules + self.chat_message.rules
        self.message_handler.payload.rules += (
            self.message.payload.rules + self.chat_message.payload.rules
        )

        self.rules = self.message_handler.payload.rules + self.message_handler.rules

        if get_current_rest:

            # Check updates from timoniq/vkbottle-rest
            current_rest = await get_current_rest()
            if current_rest["version"] != __version__:
                logger.info(
                    "You are using old version of VKBottle. Update is found: {} | {}",
                    current_rest["version"],
                    current_rest["description"],
                )
        logger.debug("Bot successfully dispatched")
Пример #7
0
    async def run(self, wait: int = DEFAULT_WAIT):
        """ Run user polling forever
        Can be manually stopped with:
        >> user.stop()
        """
        self.__wait = wait
        logger.info("Polling will be started. Is it OK?")

        await self.get_server()
        self.on.dispatch()
        logger.debug("User Polling successfully started")

        while not self._stop:
            try:
                event = await self.make_long_request(self.long_poll_server)
                if isinstance(event, dict) and event.get("ts"):
                    self.__loop.create_task(self.emulate(event))
                    self.long_poll_server["ts"] = event["ts"]
                else:
                    await self.get_server()

            except (
                    aiohttp.ClientConnectionError,
                    aiohttp.ServerTimeoutError,
                    TimeoutError,
            ):
                # No internet connection
                logger.warning("Server Timeout Error!")

            except:
                logger.error(
                    "While user lp was running error occurred \n\n{}".format(
                        traceback.format_exc()))

        logger.error("Polling was stopped")
Пример #8
0
 def set_blueprints(self, *blueprints: Blueprint):
     """
     Add blueprints
     """
     for blueprint in blueprints:
         blueprint.create(familiar=(self.branch, self.extension, self.api))
         self.loop.create_task(self.dispatch(blueprint))
     logger.debug("Blueprints have been successfully loaded")
Пример #9
0
 def set_blueprints(self, *blueprints: Blueprint):
     """
     Add blueprints
     """
     for blueprint in blueprints:
         blueprint.create(api_instance=self.api, error_handler=self.error_handler)
         self.dispatch(blueprint)
     logger.debug("Blueprints have been successfully loaded")
Пример #10
0
 def set_blueprints(self, *blueprints: Blueprint) -> None:
     """
     Add blueprints
     """
     for blueprint in blueprints:
         blueprint.create(familiar=(self.branch, self.api))
         self.loop.run_until_complete(self.dispatch(blueprint))
     logger.debug("Blueprints have been successfully loaded")
Пример #11
0
 async def run_middleware(self, event: BaseModel, flag: MiddlewareFlags,
                          *middleware_args):
     for middleware in self.middleware:
         logger.debug(
             f"Executing middleware {middleware.__class__.__name__} ({str(flag)})"
         )
         yield await middleware.emulate_middleware(event, flag,
                                                   *middleware_args)
Пример #12
0
    async def _processor(self, obj: dict, client_info: dict):
        processor = dict(obj=obj, client_info=client_info)
        middleware_args = []

        message = Message(**{
            **obj, "text":
            init_bot_mention(self.group_id, obj["text"])
        },
                          client_info=client_info)

        async for mr in self.middleware.run_middleware(message):
            if self.status.middleware_expressions:
                if mr is False:
                    return
                elif mr is not None:
                    middleware_args.append(mr)

        if message.peer_id in await self.branch.queue:
            await self._branched_processor(obj, client_info, middleware_args)
            return

        logger.debug(
            '-> MESSAGE FROM {} TEXT "{}"',
            message.from_id,
            message.text.replace("\n", " "),
        )

        task = None
        for rules in self.on.rules:

            for rule in rules:
                if not await rule(message):
                    break

            else:

                args = [a for rule in rules for a in rule.context.args]
                kwargs = {
                    k: v
                    for rule in rules for k, v in rule.context.kwargs.items()
                }

                args = [message, *middleware_args, *args]

                task = await rules[0].call(*args, **kwargs)

                logger.info(
                    'New message "{}" compiled with decorator <{}> (from: {}/{})'
                    .format(
                        message.text.replace("\n", " "),
                        rules[0].call.__name__,
                        message.peer_id,
                        message.from_id,
                    ))
                break

        await self._handler_return(task, **processor)
Пример #13
0
    async def branch_processor(self, obj: dict, client_info: dict,
                               middleware_args: list):
        """ Process messages for users in branch storage
        #TODO Make a simple branch extendable processor
        #TODO Move middleware_args
        """
        obj["text"] = sub(r"\[club" + str(self.group_id) + r"\|.*?\] ", "",
                          obj["text"])

        message = Message(**obj, client_info=client_info)
        branch_checkup_key = message.dict()[self.branch.checkup_key.value]

        logger.debug(
            '-> BRANCHED MESSAGE FROM {} TEXT "{}"',
            message.peer_id,
            message.text.replace("\n", " "),
        )

        disposal, branch = await self.branch.load(branch_checkup_key)
        edited = None

        for n, member in disposal.items():
            rules = member[1]
            for rule in rules:
                if not await rule(message):
                    break
            else:
                task = types.MethodType(member[0], branch)
                args = [a for rule in rules for a in rule.context.args]
                kwargs = {
                    k: v
                    for rule in rules for k, v in rule.context.kwargs.items()
                }
                edited = await self.handler_return(
                    await task(message, *middleware_args, *args, **kwargs),
                    data={
                        "object": obj,
                        "client_info": client_info
                    },
                )
                break

        # FIXME
        if (edited is False
                and self.branch.__class__.generator is GeneratorType.DATABASE):
            if branch_checkup_key in await self.branch.queue:
                logger.debug("Updating branch context")
                await self.branch.add(branch_checkup_key, branch.key,
                                      **branch.context)

        logger.info(
            'New BRANCHED "{0}" compiled with branch <{2}> (from: {1})'.format(
                message.text.replace("\n", " "),
                message.from_id,
                repr(branch.key),
            ))
Пример #14
0
async def request(
    method: str,
    params: dict,
    token: str,
    session: HTTPRequest = None,
    error_handler: "VKErrorHandler" = None,
    request_instance=None,
):
    url = "{}{method}/?access_token={token}&v={version}".format(
        API_URL,
        method=method,
        token=token,
        version=API_VERSION,
    )

    session = session or HTTPRequest()
    response = await session.post(url, data=params or {})

    if not isinstance(response, dict):
        delay = 1

        while not isinstance(response, dict):
            logger.error(
                "\n---"
                f"{time.strftime('%m-%d %H:%M:%S', time.localtime())} - DELAY {delay * 5} sec\n"
                f"Check your internet connection. Maybe VK died, request returned: {response}"
                f"Error appeared after request: {method}")
            await asyncio.sleep(delay * 5)
            response = await session.post(url, data=params or {})

        logger.success(
            f"--- {time.strftime('%m-%d %H:%M:%S', time.localtime())}\n"
            f"- METHOD SUCCESS after {5 * sum(range(1, delay))} sec\n"
            f"RESPONSE: {response}\n")

    if "error" in response:
        logger.debug("Error after request {method}, response: {r}",
                     method=method,
                     r=response)
        exception = VKError(
            response["error"]["error_code"],
            response["error"]["error_msg"],
            from_attr(
                Categories,
                [method.split(".")[0],
                 to_snake_case(method.split(".")[1])]
                if "." in method else method,
                (request_instance, None),
            ),
            params,
            raw_error=response["error"],
        )
        if not error_handler:
            raise exception
        return await error_handler.handle_error(exception)
    return response
Пример #15
0
    async def message_processor(
        self,
        update: dict,
        update_code: int,
        update_fields: typing.List[int],
    ) -> None:
        """ Process message events. Use base fields to make a dataclass
        Params described in parent_processor
        """
        # Expanding data
        fields = ("message_id", "flags", *ADDITIONAL_FIELDS)
        data = dict(zip(fields, update_fields))
        middleware_args = []

        if self.expand_models:
            data.update(await self.expand_data(update_code, data))

        message = Message(**data)

        # Executing middleware
        async for mr in self.middleware.run_middleware(message,
                                                       MiddlewareFlags.PRE):
            if self.status.middleware_expressions:
                if mr is False:
                    return
                elif mr is not None:
                    middleware_args.append(mr)

        # Executing branch queue
        if message.dict()[
                self.branch.checkup_key.value] in await self.branch.queue:
            return await self.branch_processor(message, middleware_args)

        # Rule checkup
        for rules in self.handler.message_rules:
            rule = rules[0]  # API Complexity #FIXME
            check = await rule.check(update)

            if check is not None:
                args, kwargs = [], {}

                if isinstance(check, tuple):
                    check = await self.filter(message, check)
                    if not check:
                        continue
                    args, kwargs = check

                task = await rule.call(message, *args, **kwargs)
                await self.handler_return(task, data)
                break

        async for mr in self.middleware.run_middleware(message,
                                                       MiddlewareFlags.POST,
                                                       *middleware_args):
            logger.debug(f"POST Middleware handler returned: {mr}")
Пример #16
0
 def dispatch(self, user: AnyUser) -> None:
     """
     Concatenate handlers to current user object
     :param user:
     :return:
     """
     self.on.concatenate(user.on)
     self.error_handler.handled_errors.update(user.error_handler.handled_errors)
     self.middleware.middleware += user.middleware.middleware
     self.branch.add_branches(user.branch.branches)
     logger.debug("Bot has been successfully dispatched")
Пример #17
0
 def get_id_by_token(token: str, loop: asyncio.AbstractEventLoop) -> int:
     """
     Get group id from token
     :param token:
     :return:
     """
     logger.debug("Making API request users.get to get user_id")
     response = loop.run_until_complete(request("users.get", {}, token))
     if "error" in response:
         raise VKError(0, "Token is invalid")
     return response["response"][0]["id"]
Пример #18
0
    async def _branched_processor(self, obj: dict, client_info: dict,
                                  middleware_args: list):
        """
        Branched messages processor manager
        :param obj: VK Server Event Object
        """
        obj["text"] = sub(r"\[club" + str(self.group_id) + r"\|.*?\] ", "",
                          obj["text"])

        answer = Message(**obj, client_info=client_info)

        logger.debug(
            '-> BRANCHED MESSAGE FROM {} TEXT "{}"',
            answer.peer_id,
            answer.text.replace("\n", " "),
        )

        disposal, branch = await self.branch.load(answer.peer_id)
        edited = None

        for n, member in disposal.items():
            rules = member[1]
            for rule in rules:
                if not await rule(answer):
                    break
            else:
                task = types.MethodType(member[0], branch)
                args = [a for rule in rules for a in rule.context.args]
                kwargs = {
                    k: v
                    for rule in rules for k, v in rule.context.kwargs.items()
                }
                edited = await self._handler_return(
                    await task(answer, *middleware_args, *args, **kwargs),
                    obj,
                    client_info,
                )
                break

        if edited is False and self.branch.generator is GeneratorType.DATABASE:
            if answer.peer_id in await self.branch.queue:
                await self.branch.add(answer.peer_id, branch.key,
                                      **branch.context)

        logger.info(
            'New BRANCHED "{0}" compiled with branch <{2}> (from: {1})'.format(
                answer.text.replace("\n", " "),
                answer.from_id,
                '"{}" with {} kwargs'.format(
                    branch.key,
                    branch.context if len(branch.context) < 100 else
                    branch.context[1:99] + "...",
                ),
            ))
Пример #19
0
 def dispatch(self, bot: AnyBot):
     """
     Concatenate handlers to current bot object
     :param bot:
     :return:
     """
     self.on.concatenate(bot.on)
     self.error_handler.handled_errors.update(bot.error_handler.handled_errors)
     self.middleware.middleware += bot.middleware.middleware
     self.branch.add_branches(bot.branch.branches)
     logger.debug("Bot has been successfully dispatched")
Пример #20
0
 def _check_secret(self, event: dict, secret: typing.Optional[str] = None):
     """
     Match secret code with current secret
     :param event:
     :return:
     """
     if self.__secret or secret:
         logger.debug("Checking secret for event ({secret})",
                      secret=event.get("secret"))
         return event.get("secret") == (self.__secret or secret)
     return True
Пример #21
0
 async def dispatch(self, bot: AnyBot):
     """
     Concatenate handlers to current bot object
     :param bot:
     :return:
     """
     self.on.concatenate(bot.on)
     self.error_handler.handled_errors.update(bot.error_handler.handled_errors)
     self.middleware.middleware += bot.middleware.middleware
     for branch_name, disposal in (await bot.branch.branches).items():
         self.branch.add_branch(disposal[0], name=branch_name)
     logger.debug("Bot has been successfully dispatched")
Пример #22
0
 async def wrapper(*args, **kwargs):
     try:
         return await func(*args, **kwargs)
     except exception as e:
         if ignore:
             return e
         if exception_handler is not None:
             await exception_handler(e, *args, **kwargs)
         else:
             logger.error(traceback.format_exc())
     finally:
         logger.debug(
             f"{func.__name__} successfully handled with swear")
Пример #23
0
 def get_id_by_token(token: str, throw_exc: bool = True) -> typing.Union[int, bool]:
     """
     Get group id from token
     :param token:
     :param throw_exc:
     :return:
     """
     logger.debug("Making API request groups.getById to get group_id")
     response = asyncio.get_event_loop().run_until_complete(
         request("groups.getById", {}, token, throw_errors=False)
     )
     if "error" in response:
         if throw_exc:
             raise VKError(0, "Token is invalid")
         return False
     return response["response"][0]["id"]
Пример #24
0
    def concatenate(self, handler: "Handler"):
        """
        Concatenate handlers from current handler and another handler
        :param handler: another handler
        :return:
        """
        self.message.concatenate(handler.message)
        self.chat_message.concatenate(handler.chat_message)
        self.message_handler.concatenate(handler.message_handler)
        self.event.rules += handler.event.rules
        if not self._pre_p:
            self._pre_p = handler.pre

        logger.debug(
            "Bot Handler was concatenated with {handler}",
            handler=handler.__class__.__name__,
        )
Пример #25
0
    async def branch_processor(self, message: Message, middleware_args: list):
        """ Process messages for users in branch storage
        #TODO Make a simple branch extendable processor
        #TODO Move middleware_args
        """
        branch_checkup_key = message.dict()[self.branch.checkup_key.value]
        logger.debug(
            '-> BRANCHED MESSAGE FROM {} TEXT "{}"',
            branch_checkup_key,
            message.text.replace("\n", " "),
        )

        disposal, branch = await self.branch.load(branch_checkup_key)
        edited = None

        for n, member in disposal.items():
            rules = member[1]
            for rule in rules:
                if not await rule(message):
                    break
            else:
                task = types.MethodType(member[0], branch)
                args = [a for rule in rules for a in rule.context.args]
                kwargs = {
                    k: v
                    for rule in rules for k, v in rule.context.kwargs.items()
                }
                handler_return = await task(message, *middleware_args, *args,
                                            **kwargs)
                edited = await self.handler_return(handler_return,
                                                   message.dict())
                break

        # FIXME
        if edited is False and self.branch.generator is GeneratorType.DATABASE:
            if branch_checkup_key in await self.branch.queue:
                logger.debug("Updating branch context")
                await self.branch.add(branch_checkup_key, branch.key,
                                      **branch.context)

        logger.info(
            'New BRANCHED "{0}" compiled with branch <{2}> (from: {1})'.format(
                message.text.replace("\n", " "),
                branch_checkup_key,
                repr(branch.key),
            ))
Пример #26
0
 async def wrapper(*args, **kwargs):
     try:
         return await func(*args, **kwargs)
     except exception as e:
         if ignore:
             return e
         if exception_handler is not None:
             await exception_handler(e, *args, **kwargs)
         elif just_log:
             logger.error(
                 "While {func} was handling error occurred \n\n{traceback}",
                 func=func.__name__,
                 traceback=traceback.format_exc(),
             )
     finally:
         logger.debug(
             f"{func.__name__} successfully handled with swear")
Пример #27
0
 async def _processor(self, update: dict, update_code: int, update_fields: list):
     try:
         data = update, update_code, update_fields
         if update_code not in list(map(int, UserEvents)):
             logger.warning("Undefined event {}", update_code)
             return
         event = UserEvents(update_code)
         logger.debug("New event: {} {}", event, update)
         if event is UserEvents.new_message:
             return await self._message_processor(*data)
         return await self._event_processor(*data)
     except VKError as e:
         await self.error_handler.handle_error(e)
     except:
         logger.error(
             "While user polling worked error occurred \n\n{traceback}",
             traceback=traceback.format_exc(),
         )
Пример #28
0
    async def emulate(
        self,
        event: dict,
        confirmation_token: str = None,
        secret: str = None,
    ) -> typing.Union[str, None]:
        """ Process all types of events
        :param event: VK Event (LP or CB)
        :param confirmation_token: code which confirm VK callback
        :param secret: secret key for callback
        :return: "ok"
        """
        if not self.status.dispatched:
            self.middleware.add_middleware(self.on.pre_p)
            await self.on.dispatch(self.get_current_rest)
            self.status.dispatched = True

        logger.debug("Event: {event}", event=event)

        if event is None:
            return

        if event.get("type") == "confirmation":
            if event.get("group_id") == self.group_id:
                return confirmation_token or "dissatisfied"

        updates = event.get("updates", [event])
        if not self._check_secret(event, secret=secret):
            logger.debug("Aborted. Secret is invalid")
            return "access denied"

        for update in updates:
            if not update.get("object"):
                continue
            try:
                self.loop.create_task(
                    self.handle.parent_processor(update, obj=update["object"]))
            except VKError as e:
                self.loop.create_task(self.error_handler.handle_error(e))

        return "ok"
Пример #29
0
    async def parent_processor(
        self, update: dict, update_code: int, update_fields: typing.List[int],
    ) -> bool:
        """ Classify and distribute user polling events as message and not message
        #TODO Reduce difference
        :param update: full event
        :param update_code: first element from update
        :param update_fields: fields stack
        """
        data = update, update_code, update_fields

        if update_code not in list(map(int, UserEvents)):
            logger.warning("Undefined event {}", update_code)
            return

        event = UserEvents(update_code)
        logger.debug("New event: {} {}", event, update)

        if event is UserEvents.new_message:
            return await self.message_processor(*data)
        return await self.event_processor(*data)
Пример #30
0
    async def __call__(
        self,
        method: str,
        params: dict,
        throw_errors: bool = None,
        response_model=None,
        raw_response: bool = False,
    ):
        response = await request(
            method,
            params,
            await self.token_generator.get_token(method=method, params=params),
            request_instance=self,
            error_handler=self.error_handler,
        )

        logger.debug("Response: {}", response)

        if not response_model or raw_response:
            return response["response"]
        return response_model(**response).response