Устройство модуля
Каждый модуль реализует goroku.Module. Встраивание goroku.Base даёт значение по умолчанию для всего, кроме Name и Commands, — только эти два метода писать обязательно.
type Module interface {
Name() string
Strings() map[string]string
Init(client *CustomTelegramClient, db *Database) error
ClientReady() error
OnUnload() error
OnDlmod() error
Commands() map[string]CommandHandler
Watchers() []WatcherHandler
}Обязательные
Name
Идентичность модуля в .help, .unloadmod и интерфейсе настроек. Это же имя типа Go и ключ, под которым хранятся ваши данные.
func (m *Weather) Name() string { return "Weather" }Commands
Сопоставляет слово команды обработчику. Пользователь набирает слово после префикса, поэтому "weather" превращается в .weather.
func (m *Weather) Commands() map[string]goroku.CommandHandler {
return map[string]goroku.CommandHandler{
"weather": m.WeatherCmd,
"forecast": m.ForecastCmd,
}
}CommandHandler — это func(msg *goroku.Message) error. Возврат ошибки покажет её пользователю; диспетчер к тому же перехватывает паники, так что падение обработчика не уронит бота.
Необязательные, со значениями из Base
Strings
Текст для пользователя и источник для m.T. Два префикса ключей особые:
| Ключ | Смысл |
|---|---|
name | Отображаемое имя в .help |
_cls_doc | Что делает модуль |
_cmd_doc_<команда> | Что делает эта команда |
Все остальные ключи — ваши, доставайте их через m.T.
func (m *Weather) Strings() map[string]string {
return map[string]string{
"name": "Weather",
"_cls_doc": "Погода в городе",
"_cmd_doc_weather": "[город] — показать погоду",
"no_city": "❌ <b>Какой город?</b>",
}
}Init
Выполняется один раз при регистрации, до того как сработает любая команда. Base к этому моменту уже заполнил m.Client, m.DB и m.Translator, так что Init нужен только для вашей собственной настройки.
func (m *Weather) Init(client *goroku.CustomTelegramClient, db *goroku.Database) error {
if err := m.Base.Init(client, db); err != nil {
return err
}
m.cache = make(map[string]string)
return nil
}Вызывайте m.Base.Init первым
Загрузчик заполняет поля до вызова Init, поэтому в обычной работе этот вызов избыточен. Всё равно оставьте его: так модуль будет работать и когда его создают напрямую в тесте, минуя загрузчик.
ClientReady
Выполняется, когда соединение с Telegram установлено. Сюда — всё, чему нужен API при старте; Init может отработать раньше, чем клиент подключится.
func (m *Weather) ClientReady() error {
me := m.Client.Me()
_ = me
return nil
}OnUnload
Выполняется при удалении модуля. Здесь освобождайте горутины, таймеры и файловые дескрипторы.
func (m *Weather) OnUnload() error {
close(m.stop)
return nil
}WARNING
Паника в OnUnload перехватывается и логируется, но модуль всё равно удаляется. Не полагайтесь на OnUnload там, где очистка критична для корректности.
OnDlmod
Выполняется сразу после установки через .dlmod. Удобно для одноразового приветствия или начальной настройки.
Watchers
Обработчики, которые видят каждое сообщение, а не только команды. См. Вотчеры.
За пределами интерфейса
Часть возможностей подключается отдельными интерфейсами — просто объявите метод, и Goroku его подхватит:
| Интерфейс | Метод | Назначение |
|---|---|---|
ModuleWithMeta | CommandMetas() | Алиасы и ограничения |
ModuleWithConfigSchema | ConfigSchema() | Типизированные настройки |
ModuleWithConfigReady | ConfigReady(map[string]any) | Реакция на смену настроек |
ModuleWithTranslationAliases | TranslationAliases() | Дополнительные имена файлов перевода |
Полный список — в Опциональных интерфейсах.