Сигналы
Сигналы — своего рода кастомные события. "А зачем это нужно?" — возникает очевидный вопрос. Представим, что вы имеете достаточно сложную архитектуру, и поскольку пишете в своего рода функциональном стиле, рефакторите свою логику на более мелкие части (тобишь другие функции), и, скорее всего, разделяя их в разные файлы. Чтобы не погрязнуть в туче импортов, вы можете пометить свою функцию как обработчик сигнала и из любого места в вашем коде вызвать его через имя и передать нужные аргументы
Помимо своих сигналов, вы можете обрабатывать и встроенные сигналы, например, startup
, вызываемый во время запуска бота и shutdown
во время выключения бота
Чтобы создать обработчик сигнала (своего или встроенного), воспользуйтесь следующей командой
$ bot signal startup
Added a hander on a signal startup into path src/startup.py
Вы заметите, что появился (в нашем случае) файл src/startup.py
(и добавился импорт в __init__.py
) вот с таким содержимым
import vkquick as vq
@vq.Signal("startup")
def startup():
"""
Handler to signal `startup`
"""
Появился новый декоратор Signal
, как раз-таки и говорящий о том, что эта функция — обработчик сигнала. Теперь, когда мы будем запускать нашего бота, перед его началом работы вызовется эта функция (сам обработчик может быть и sync, и async)
Теперь попробуем создать свой собственный сигнал
$ bot signal example
Added a hander on a signal example into path src/startup.py
Выглядит он почти точно также (кроме имени), как и startup
, описанный выше. Немного поменяем содержимое, добавив принт
import vkquick as vq
@vq.Signal("example")
def example():
"""
Handler to signal `example`
"""
print("Called signal `example`")
Теперь можно создать команду, вызывающую этот сигнал
$ bot com call_example
Added a command call_example into path src/call_example
Для того, чтобы вызвать сигнал, надо вызвать корутинный метод у bot
. Считается устаревшим с v0.2
. Будет удален в v1
async def resolve(self, name: str, /, *args, **kwargs)
Либо воспользоваться корутинной функцией, добавленной в v0.2
:
async def signal(self, name: str, /, *args, **kwargs)
Где name
— имя сигнала (в нашем случае example
), а *аргс и **kwargs — передаваемые параметры в обработчик. Поэтому сделаем команду async
и добавим вызов сигнала:
import vkquick as vq
from . import config
@vq.Cmd(names=config.NAMES)
@vq.Reaction("message_new")
async def call_example(bot: vq.Bot):
"""
Handler to command `call_example`
"""
await bot.signals.resolve("example")
# либо
await vq.signal("example")
Запускаем бота ($ bot run --reload --debug
), переходим в лс и пишем call_example
, после чего смотрим в консоль и видим, что появился вывод Called signal `example`
, что говорит нам о том, что обработчк сигнала вызвался успешно
Note
Вы также можете вернуть своим сигналом какое-либо значение и далее использовать его
Todo
В v0.3 появится встроенный сигнал, вызываемый после получения нового события
Todo
В планах есть своего рода репиторы (repeators), которые автоматически повторяют тот или иной сигнал (а может и не сигнал) через каждый n
промежуток