13 KiB
Laniakea
Легковесная, простая в использовании и производительная обёртка для Telegram Bot API на Go. Она упрощает разработку ботов благодаря чистой системе плагинов, поддержке中间件, автоматической генерации команд и встроенному ограничителю скорости запросов.
✨ Возможности
- Простой и интуитивный API: Разработан для лёгкости использования, основан на практических примерах.
- Система плагинов: Организуйте функциональность бота в независимые, переиспользуемые плагины.
- Обработка команд: Легко регистрируйте команды и извлекайте аргументы.
- Поддержка промежуточных слоёв (Middleware): Выполняйте код до или после команд (например, логирование, проверка доступа).
- Автоматическая генерация команд: Генерируйте справку и списки команд автоматически.
- Встроенный ограничитель запросов (Rate Limiter): Защитите бота от превышения лимитов Telegram API (с обработкой
retry_after). - Контекст данных: Передавайте свой контекст базы данных или состояния в обработчики.
- Текучий интерфейс (Fluent Interface): Стройте цепочки методов для чистой конфигурации (например,
bot.ErrorTemplate(...).AddPlugins(...)).
📦 Установка
go get git.nix13.pw/scuroneko/laniakea
🚀 Быстрый старт (с пошаговыми комментариями)
Вот минимальный пример бота "echo/ping" с подробными комментариями.
package main
import (
"log"
"git.nix13.pw/scuroneko/laniakea" // Импортируем библиотеку Laniakea
)
// echo — это функция-обработчик команды.
// Она получает два параметра:
// - ctx: контекст сообщения (содержит информацию о сообщении, отправителе, чате и т.д.)
// - db: ваш пользовательский контекст базы данных (здесь мы используем NoDB — заглушку)
func echo(ctx *laniakea.MsgContext, db *laniakea.NoDB) {
// Отвечаем пользователю текстом, который он прислал, без префикса команды.
// ctx.Text содержит сообщение пользователя, из которого удалена часть с командой.
ctx.Answer(ctx.Text) // Ввод пользователя БЕЗ команды
}
func main() {
// 1. Создаём опции бота. Замените "TOKEN" на реальный токен от @BotFather.
opts := &laniakea.BotOpts{Token: "TOKEN"}
// 2. Инициализируем новый экземпляр бота.
// Используем laniakea.NoDB как тип контекста базы данных (база не нужна для примера).
bot := laniakea.NewBot[laniakea.NoDB](opts)
// Гарантируем освобождение ресурсов бота при выходе.
defer bot.Close()
// 3. Создаём новый плагин с именем "ping".
// Плагины помогают группировать связанные команды и промежуточные обработчики.
p := laniakea.NewPlugin[laniakea.NoDB]("ping")
// 4. Добавляем команду в плагин.
// p.NewCommand(echo, "echo") создаёт команду, которая вызывает функцию 'echo' по команде "/echo".
p.AddCommand(p.NewCommand(echo, "echo"))
// 5. Добавляем ещё одну команду, используя анонимную функцию (замыкание).
// Эта команда просто отвечает "Pong", когда пользователь отправляет "/ping".
p.AddCommand(p.NewCommand(func(ctx *laniakea.MsgContext, db *laniakea.NoDB) {
ctx.Answer("Pong")
}, "ping"))
// 6. Настраиваем бота: задаём шаблон ошибки и добавляем плагин.
// ErrorTemplate устанавливает формат для сообщений об ошибках (где %s будет заменён на текст ошибки).
// AddPlugins(p) регистрирует наш плагин "ping" в боте.
bot = bot.ErrorTemplate("Ошибка\n\n%s").AddPlugins(p)
// 7. Автоматически генерируем команды, такие как /start, /help и список всех зарегистрированных команд.
// Это необязательно, но очень полезно для большинства ботов.
if err := bot.AutoGenerateCommands(); err != nil {
log.Println(err)
}
// 8. Запускаем бота, начиная прослушивание обновлений (long polling).
bot.Run()
}
Как это работает
BotOpts: Содержит конфигурацию, например, токен API.NewBot[T]: Создаёт экземпляр бота. Параметр типа T позволяет передать пользовательский контекст базы данных (например, *sql.DB), который будет доступен во всех обработчиках. Используйте laniakea.NoDB, если он не нужен.NewPlugin: Создаёт логическую группу для команд и Middleware.AddCommand: Регистрирует команду. Первый аргумент — функция-обработчик (func(*MsgContext, T)), второй — имя команды (без слеша).- Функции-обработчики: Получают *MsgContext (детали сообщения, методы типа Answer) и ваш контекст базы данных T.
ErrorTemplate: Устанавливает шаблон для сообщений об ошибках. Плейсхолдер %s заменяется на текст ошибки.AutoGenerateCommands: Добавляет встроенные команды (/start, /help) и команду, показывающую список всех доступных команд.Run(): Запускает цикл опроса обновлений бота.
📖 Основные концепции
Плагины (Plugins)
Плагины — основной способ организации кода. Плагин может содержать несколько команд и Middleware.
plugin := laniakea.NewPlugin[MyDB]("admin")
plugin.AddCommand(plugin.NewCommand(banUser, "ban"))
bot.AddPlugins(plugin)
Команды (Commands)
Команда — это функция, которая обрабатывает конкретную команду бота (например, /start).
func myHandler(ctx *laniakea.MsgContext, db *MyDB) {
// Доступ к аргументам команды через ctx.Args ([]string)
// Ответ пользователю: ctx.Answer("какой-то текст")
}
Контекст сообщения (MsgContext)
Предоставляет доступ к входящему сообщению и полезные методы для ответа:
Answer(text string): Отправляет обычный текст, автоматически экранируя MarkdownV2.AnswerMarkdown(text string): Отправляет сообщение, отформатированное MarkdownV2 (экранирование на вашей стороне).AnswerText(text string): Отправляет сообщение без parse_mode.SendChatAction(action string): Отправляет действие "печатает", "загружает фото" и т.д.- Поля:
Text,Args,From,Chat,Msgи другие.
Контекст базы данных (Database Context)
Параметр типа T в NewBot[T] — мощная функция. Вы можете передать любой тип (например, пул соединений с БД), и он будет доступен в каждом обработчике команды и中间件.
type MyDB struct { /* ... */ }
db := &MyDB{...}
bot := laniakea.NewBot[*MyDB](opts, db) // Передаём экземпляр db
🧩 Промежуточные слои (Middleware)
Middleware — это функции, которые выполняются перед обработчиком команды. Они идеально подходят для сквозных задач, таких как логирование, контроль доступа, ограничение скорости запросов или модификация контекста.
Сигнатура
Функция middleware имеет ту же сигнатуру, что и обработчик команды, но должна возвращать bool:
func(ctx *MsgContext, db T) bool
- Если возвращается true, выполняется следующий middleware (или сама команда).
- Если возвращается false, цепочка выполнения немедленно прерывается (команда не запускается).
Добавление middleware
Используйте метод Use плагина для добавления одной или нескольких функций middleware. Они выполняются в порядке добавления.
plugin := laniakea.NewPlugin[MyDB]("admin")
plugin.Use(loggingMiddleware, adminOnlyMiddleware)
plugin.AddCommand(plugin.NewCommand(banUser, "ban"))
Примеры middleware
- Логирующий middleware – логирует каждое выполнение команды.
func loggingMiddleware(ctx *laniakea.MsgContext, db *MyDB) bool {
log.Printf("Пользователь %d выполнил команду: %s", ctx.FromID, ctx.Msg.Text)
return true // продолжаем к следующему middleware/команде
}
- Middleware только для администраторов – ограничивает доступ пользователям с определённой ролью.
func adminOnlyMiddleware(ctx *laniakea.MsgContext, db *MyDB) bool {
if !db.IsAdmin(ctx.FromID) { // предполагается, что db имеет метод IsAdmin
ctx.Answer("⛔ Доступ запрещён. Только для администраторов.")
return false // останавливаем выполнение
}
return true
}
Важные замечания
- Middleware может изменять MsgContext (например, добавлять пользовательские поля) перед запуском команды.
- Если нужно выполнить код после команды, это можно сделать внутри самой команды или использовать отложенный вызов (defer) в middleware, который оборачивает следующий вызов (более продвинутый подход).
⚙️ Расширенная настройка
Инлайн-клавиатуры: Создавайте клавиатуры с помощью laniakea.NewKeyboard() и AddRow(). Ограничение запросов: Передайте настроенный utils.RateLimiter через BotOpts для корректной обработки лимитов Telegram. Пользовательский HTTP-клиент: Предоставьте свой http.Client в BotOpts для точного контроля.
📝 Лицензия
Этот проект лицензирован под GNU General Public License v3.0 - подробности см. в файле LICENSE.
📚 Дополнительная информация
✅ Создано с ❤️ scuroneko