Перейти к содержанию

Handling-View

View являются блокирующими менеджерами хендлеров. Если process_event у view вернул True то другие view уже не будут проверяться

Процедура поиска view обрабатывающего ивент проста:

Сначала обрабатывается process_view который должен вернуть boolean-значение. Если вернулось True то поиск view прекращается и вызывается handle_event который отвечает за подбор хендлера

Во View рекомендуются 2 аттрибута:

  • handlers - список из ABCHandler
  • middlewares - список из BaseMiddleware

Эти аттрибуты впоследствии рекомендуется использовать в handle_event для запуска мидлварей и поиска хендлера

register_middleware(BaseMiddleware)

Добавляет мидлварь в view.middlewares

Написание view

View - это как большой хендлер, имплементирующий индивидуальную логику работы с мидлварями, стейт менеджером и производными хендлеров

Кастомные view нужны обычно для создания среды обработки какого-то ивента или группы ивентов

Посмотреть пример view для сообщений можно здесь

Для view рекомендуется 3 атрибута:

  • handlers - лист из ABCHandler
  • middlewares - лист из BaseMiddleware
  • handler_return_manager - BaseReturnManager
from vkbottle import ABCView, MiddlewareResponse
from vkbottle_types.events.bot_events import PollVoteNew

class VoteView(ABCView):
    def __init__(self):
        self.handlers = []
        self.middlewares = []

    async def process_event(self, event: dict) -> bool:
        # Эта функция принимает ивент в форме словаря,
        # она должна определить подходит ли ивент под 
        # текущий view или нет и вернуть соответствующее
        # boolean-значение
        return event["type"] == "poll_vote_new"

    async def handle_event(
        self, event: dict, ctx_api: "ABCAPI", state_dispenser: "ABCStateDispenser"
    ):
        # Эта функция полностью обрабатывает
#       # полученный ивент
        vote = PollVoteNew(**event)

        # Здесь можно обозначить стейт-каст
        # по определенному ключу для объекта
        vote.object.state_peer = await state_dispenser.cast(vote.object.user_id)

        # Здесь можно имплементировать стандартное поведение мидлварей
        # Например, если мидлварь вернул `MiddlewareResponse(False)`
        # обработка сразу останавливается
        for middleware in self.middlewares:
            response = await middleware.pre(vote)
            if response == MiddlewareResponse(False):
                return

        # `handlers` и `handle_responses` нужны для post мидлварей
        handlers = []
        handler_responses = []

        for handler in self.handlers:
            if not await handler.filter(vote):
                continue

            handler_responses.append(await handler.handle(vote))
            handlers.append(handler)

            if handler.blocking:
                break

        # Запуск post-мидлварей
        for middleware in self.middlewares:
            await middleware.post(vote, self, handler_responses, handlers)

Поздравляю вы написали свой view! Теперь можно перейти к регистрации хендлеров, но для этого потребуется их создать, можно воспользоваться FromFuncHandler:

from vkbottle.bot import Bot, rules, BotLabeler
from vkbottle.dispatch.handlers import FromFuncHandler
from vkbottle_types.events.bot_events import PollVoteNew
from typing import Dict


class MyLabeler(BotLabeler):
    def views(self) -> Dict[str, "ABCView"]:
        # Из views должны быть возвращены все view которые
        # будут позже обрабатываться роутером
        return {"vote_view": my_view}


async def vote_up(vote: PollVoteNew):
    print("{} со стейтом {} голосует за {}".format(
        vote.object.user_id, 
        vote.object.state_peer, 
        vote.object.option_id
    ))

async def vote_up_admin(vote: PollVoteNew):
    print("Админ проголосовал за {}", vote.object.option_id)

my_view = VoteView()
my_view.handlers = [
    FromFuncHandler(vote_up_admin, rules.FuncRule(lambda v: v.object.user_id in admin_ids)),
    FromFuncHandler(vote_up)
]

bot = Bot()
bot.labeler = MyLabeler()
admin_ids = [1]

Бот с VoteView готов