Skip to content

Команди

Реєстрація

go
func (m *Weather) Commands() map[string]goroku.CommandHandler {
	return map[string]goroku.CommandHandler{
		"weather": m.WeatherCmd,
	}
}

Ключ мапи — слово команди. З префіксом за замовчуванням . це реєструє .weather. Регістр у ключах не важливий.

Імена команд і аліасів унікальні серед усіх завантажених модулів. Якщо weather уже зайнятий іншим модулем, реєстрація впаде з помилкою колізії, де названо конфліктне ім'я, а не мовчки перезапише чужу команду.

Аліаси

Додайте CommandMetas — це необов'язковий інтерфейс, оголосити метод достатньо:

go
func (m *Weather) CommandMetas() map[string]goroku.CommandMeta {
	return map[string]goroku.CommandMeta{
		"weather": {
			Aliases: []string{"w", "wx"},
		},
	}
}

Тепер працюють .weather, .w і .wx.

Обмеження місця виклику

Поля CommandMeta — це фільтри. Диспетчер перевіряє їх до запуску обробника, тому невідповідна команда просто не спрацьовує.

go
func (m *Weather) CommandMetas() map[string]goroku.CommandMeta {
	return map[string]goroku.CommandMeta{
		"weather": {
			Aliases:   []string{"w"},
			OnlyOwner: true,   // тільки ви
			OnlyGroups: true,  // тільки в групах
			NoForwarded: true, // ігнорувати переслані
		},
	}
}

Найуживаніші:

ПолеДія
OnlyOwnerТільки власник акаунта
OnlyPM / NoPMТільки / ніколи в приватних чатах
OnlyGroups, OnlyChannels, OnlyChatsОбмеження за типом чату
OnlyReply / NoReplyВимагати / забороняти відповідь на повідомлення
OnlyMedia, OnlyPhotos, OnlyVideos, OnlyDocsВимагати вкладення
NoMedia, NoStickers, NoAudio, NoDocВідхиляти вкладення
RatelimitЗастосовувати ліміти частоти за користувачем і чатом
Filterfunc(*Message) bool для всього іншого

Повний перелік — у CommandMeta.

Збіг за вмістом

go
"weather": {
	StartsWith: "місто ",
	Regex:      `^\d{5}$`,
},

Regex компілюється один раз під час реєстрації. Некоректний шаблон покладе реєстрацію, а не мовчки ніколи не збігатиметься.

Помилки

Поверніть помилку — і користувач її побачить:

go
func (m *Weather) WeatherCmd(msg *goroku.Message) error {
	city := msg.Args()
	if city == "" {
		return msg.Answer(m.T("no_city", "❌ <b>Яке місто?</b>"))
	}
	data, err := m.fetch(city)
	if err != nil {
		return fmt.Errorf("отримання погоди для %q: %w", city, err)
	}
	return msg.Answer(data)
}

Два різні результати:

  • msg.Answer(...) зі зрозумілим текстом — очікувана ситуація на кшталт відсутніх аргументів. Повертайте nil.
  • return err — щось справді зламалося. Goroku залогує це й покаже користувачу ❌ Помилка виконання команди: <ваш текст>.

Загортайте помилки контекстом (fmt.Errorf("...: %w", err)) — саме цей текст ви читатимете в лозі о третій ночі.

Ліміти частоти

За замовчуванням команди не обмежені. Вмикається на команду:

go
"weather": { Ratelimit: true },

Диспетчер застосує налаштовані вікна за користувачем і чатом та повідомить користувача про перевищення.

Паралельність

Обробники виконуються паралельно, кожен у своїй горутині з обмеженого пулу. Два наслідки:

  • Спільний стан на структурі модуля захищайте м'ютексом. Модуль — один екземпляр на всі чати.
  • Довга робота припустима й не блокує інші команди, але поважайте скасування через msg.Context(), інакше завершення бота затягнеться.
go
type Weather struct {
	goroku.Base
	mu    sync.Mutex
	cache map[string]string
}

func (m *Weather) WeatherCmd(msg *goroku.Message) error {
	m.mu.Lock()
	cached, ok := m.cache[msg.Args()]
	m.mu.Unlock()
	if ok {
		return msg.Answer(cached)
	}
	return m.fetchAndAnswer(msg)
}

Released under the GNU AGPL v3 License.