Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11

Как написать Телеграм-бота на Rust за вечер

Пошаговая инструкция по созданию Телеграм-бота на Rust с использованием библиотеки teloxide. Вы узнаете, как зарегистрировать бота через BotFather, настроить обработку входящих сообщений, добавить кнопки и запустить проект на удалённом сервере.

510 открытий2К показов
Как написать Телеграм-бота на Rust за вечер

За 10 минут создадим чат-бота, научим его читать сообщения от пользователей и слать ответы. Ещё добавим кнопки и расскажем, как разместить бота на хостинге, чтобы он работал 24/7. Код пишем на Rust, используем библиотеку teloxide.

🔥 Помогал с публикацией Игорь Панасюк — Software Engineer и автор канала Igor Panasyuk | IGORoutine Programming.

Регистрация бота в Телеграм

Как написать Телеграм-бота на Rust за вечер 1

Откройте Телеграм и найдите @BotFather — это официальный бот, он создаёт других ботов. Отправьте ему команду /newbot.

BotFather сначала спросит имя бота, оно может быть любым. Далее придумайте username, чтобы он заканчивался на «bot», например hello_chat_bot. Если юзернейм свободен, BotFather пришлёт токен для управления. Выглядит токен как длинная строка: 8201115114:AAGNII8UA3kjcz9qvV8znl77pK-YldkWMmQ.

В BotFather есть несколько команд для настройки оформления:

  • /setname — меняет имя бота (то, что видят пользователи);
  • /setdescription — добавляет описание, которое отображается при первом запуске;
  • /setabouttext — добавляет короткий текст для страницы бота;
  • /setuserpic — загружает аватарку (квадратное изображение от 512×512 px).
Имя можно менять сколько угодно раз. Username (тот, что заканчивается на _bot) изменить нельзя.

Создаём Телеграм-бота на Rust

В качестве примера напишем эхо-бота. Он будет получать строку текста и её же присылать в ответ.

Создайте новый проект:

			cargo new telegram_echo_bot
cd telegram_echo_bot
		

Откройте Cargo.toml и добавьте зависимости:

			[dependencies]
teloxide = { version = "0.12", features = ["macros"] }
tokio = { version = "1", features = ["full"] }
log = "0.4"
pretty_env_logger = "0.5"
		

Создайте файл .env в корне проекта:

			TELOXIDE_TOKEN=токен_от_@BotFather
RUST_LOG=info
		

Откройте src/main.rs и вставьте код:

			use teloxide::prelude::*;

#[tokio::main]
async fn main() {
    pretty_env_logger::init();
    log::info!("Запускаем бота...");

    let bot = Bot::from_env();

    teloxide::repl(bot, |bot: Bot, msg: Message| async move {
        if let Some(text) = msg.text() {
            bot.send_message(msg.chat.id, text).await?;
        }
        Ok(())
    })
    .await;
}
		

teloxide::repl() запускает цикл обработки сообщений. Функция внутри получает сообщение и отправляет текст обратно пользователю.

msg.text() извлекает текст из сообщения. Если пользователь отправил стикер или фото, бот их проигнорирует. Как читать разные типы сообщений — разберём далее.

bot.send_message() отправляет ответ. Первый параметр — ID чата, второй — текст. Методы отправки с форматированием, кнопками и файлами рассмотрим в следующих разделах.

Скомпилируйте проект:

			cargo run
		

Откройте мессенджер, найдите своего бота по юзернейму и напишите ему любое сообщение. Если бот ответил, значит всё сделали правильно.

Перенос бота на хостинг

Сейчас бот работает локально на вашем компьютере. Чтобы он отвечал круглосуточно, нужен сервер. Есть три варианта:

  • Виртуальный сервер (VPS).
  • Облачные платформы.
  • Домашний сервер.

Проще и дешевле взять VPS, подойдёт любой Linux-сервер за 200-300 рублей/месяц.

После оплаты хостинга вы получите IP-адрес сервера, логин и пароль. Откройте терминал и подключитесь: ssh root@123.45.67.89, введите пароль.

Установите Rust:

			curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
		

Клонируйте проект с GitHub или создайте новый:

			git clone https://github.com/ваш_логин/telegram_echo_bot.git
cd telegram_echo_bot
		

Создайте на сервере файл .env с токеном:

			echo "TELOXIDE_TOKEN=ваш_токен" > .env
echo "RUST_LOG=info" >> .env
		

Соберите релизную версию:

			cargo build --release
		

Если закроете терминал, бот остановится. Чтобы он работал постоянно, используйте утилиту screen:

			screen -S bot
./target/release/telegram_echo_bot
# Нажмите Ctrl+A, затем D чтобы выйти из screen
		

Теперь бот работает круглосуточно. Дальше научим его читать сообщения пользователей, отвечать на команды и добавим интерактивные кнопки с меню.

Чтение сообщений

Телеграм отправляет боту данные через API. Каждое сообщение приходит в виде объекта:

  • текст,
  • ID чата,
  • информация о пользователе,
  • время отправки.

Библиотека teloxide распарсила JSON от Телеграм и превратила его в удобные структуры. Нужен лишь обработчик, который срабатывает на новое сообщение:

			bot.on_message(|msg| {
    let text = msg.text();
    let chat_id = msg.chat.id;
    // Здесь работаем с текстом
});
		

Бот как-то должен узнавать о новых сообщениях от пользователей. Самый простой способ — метод getUpdates. Бот каждые несколько секунд спрашивает: «Есть что-то новое?». Получает ответ, обрабатывает сообщения и снова спрашивает.

Под капотом teloxide делает примерно следующее:

			loop {
    // 1. Запрос к API Telegram
    let updates = bot.get_updates()
        .offset(last_update_id + 1)
        .timeout(30) // ждём 30 секунд
        .send()
        .await?;
    
    // 2. Обработка каждого обновления
    for update in updates {
        if let Some(message) = update.message {
            println!("Новое сообщение: {:?}", message.text());
        }
        last_update_id = update.id;
    }
}
		

Есть другой вариант — вебхуки. Вы один раз говорите Телеграму: «Вот адрес моего сервера, присылай сюда все обновления».

Telegram сам шлёт обновления на ваш HTTPS-эндпоинт, вместо того чтобы бот опрашивал API (getUpdates). Преимущества в меньшей нагрузке и задержке, можно масштабировать через балансировщик и легко интегрировать в микросервисную архитектуру.
Игорь ПанасюкSoftware Engineer

С getUpdates сами решаете, когда проверять новые сообщения. С вебхуками Телеграм решает за вас — он шлёт данные сразу, как только что-то происходит. Если вы пишете бота для себя или учитесь, начните с getUpdates.

Отправка сообщений

Базовая отправка текста выглядит так:

			bot.send_message(chat_id, "Привет! Я получил твоё сообщение").await?;
		

chat_id — это идентификатор чата, откуда пришло сообщение. Бот отправит ответ туда же.

Телеграм ограничивает длину одного сообщения 4096 символами. Если попытаетесь отправить больше, API вернёт ошибку. Проблему решает функция, которая разбивает текст на части:

			fn split_message(text: &str, max_length: usize) -> Vec {
    let mut chunks = Vec::new();
    let mut current = String::new();
    
    for line in text.lines() {
        if current.len() + line.len() > max_length {
            chunks.push(current.clone());
            current.clear();
        }
        current.push_str(line);
        current.push('\n');
    }
    
    if !current.is_empty() {
        chunks.push(current);
    }
    
    chunks
}
		

Бот может отправлять не только текст. Методы send_photo, send_document, send_video работают с файлами до 50 МБ. Передавайте либо URL, либо загружайте файл с диска:

			bot.send_photo(chat_id, InputFile::file("/path/to/image.jpg")).await?;
		

Форматирование текста делайте через Markdown или HTML. Чтобы применить стили, укажите режим парсинга:

			bot.send_message(chat_id, "Жирный текст")
    .parse_mode(ParseMode::Html)
    .await?;
		

Иногда нужно отправить сообщение с задержкой. В Rust нет встроенного планировщика задач, но есть tokio::time::sleep:

			tokio::time::sleep(Duration::from_secs(5)).await;
bot.send_message(chat_id, "Прошло 5 секунд").await?;
		

Ещё бот умеет редактировать уже отправленные сообщения. Сохраните объект сообщения из ответа и используйте его id, чтобы обновлять информацию в чате без спама:

			let message_id = bot.send_message(chat_id, "Загрузка...").await?.id;
// Делаем что-то
bot.edit_message_text(chat_id, message_id, "Готово!").await?;
		

Добавление меню и кнопок

Бот, который только читает и отвечает текстом, — это скучно. Пользователи хотят тыкать на кнопки, листать меню.

Как написать Телеграм-бота на Rust за вечер 2

В Телеграме есть два типа кнопок:

  • Reply — появляются вместо обычной клавиатуры для ввода текста.
  • Inline — прикрепляются прямо к сообщению.

Выбирайте Reply для основного меню, Inline — для быстрых действий внутри конкретного сообщения. Кнопки можно располагать в несколько рядов, добавлять эмодзи, делать их адаптивными.

Создадим простое меню с двумя кнопками:

			use teloxide::types::{KeyboardButton, KeyboardMarkup};

let keyboard = KeyboardMarkup::new(vec![
    vec![KeyboardButton::new("Показать погоду")],
    vec![KeyboardButton::new("Случайный факт")],
]);

bot.send_message(msg.chat.id, "Выберите действие:")
    .reply_markup(keyboard)
    .await?;
		

Кнопки отправляют обычный текст в чат. Ваш бот получит сообщение «Показать погоду» и обработает его как команду.

Inline-кнопки отправляют callback-запросы:

			use teloxide::types::{InlineKeyboardButton, InlineKeyboardMarkup};
let buttons = InlineKeyboardMarkup::new(vec![
    vec![InlineKeyboardButton::callback("Да", "answer_yes")],
    vec![InlineKeyboardButton::callback("Нет", "answer_no")],
]);
		

«Да» — это текст на кнопке, «answer_yes» — данные, которые получит бот. Чтобы поймать нажатие, нужен обработчик callback-запросов.

Ограничения ботов и ddos-атаки

Telegram API ограничивает количество сообщений, которые бот отправляет одному пользователю или в группу. Если превысите лимит, получите ошибку 429:

  • 30 сообщений в секунду.
  • 20 сообщений в минуту в один чат.

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

Основное правило — не держать бота напрямую за getUpdates, а использовать вебхуки с ограничением соединений и прокси. Telegram уже фильтрует большую часть мусорного трафика, но важно добавить rate limit (например, через nginx) и иметь таймауты.
Игорь ПанасюкSoftware Engineer

Добавьте простую защиту: храните HashMap с user_id и временем последнего сообщения. Если пользователь пишет чаще раза в секунду — игнорируйте его запросы. Ещё один вариант — подключить Redis и вести счётчики запросов там.

Библиотеки для создания ботов на Rust

В экосистеме Rust для тг-ботов есть три основные библиотеки.

teloxide

Вы пишете bot.answer("Привет") — библиотека сама формирует HTTP-запрос, отправляет его в Телеграм API, обрабатывает ответ и возвращает результат.

У teloxide есть встроенная система диалогов. Например, бот спрашивает имя, пользователь отвечает, бот запоминает ответ и спрашивает возраст. Библиотека следит за тем, на каком шаге находится каждый пользователь.

Ещё в teloxide есть диспетчер команд. Вы пишете функцию start(), помечаете её атрибутом #[command], и библиотека автоматически вызывает эту функцию, когда пользователь отправляет /start. Не нужно вручную парсить текст сообщения и проверять, что там написано.

Минус — teloxide тянет за собой много зависимостей. Поэтому увеличивается время компиляции, размер бинарника тоже.

Размер бинарного файла напрямую на производительность не влияет — Rust-компилятор делает статическую линковку, так что даже 20 МБ бинарник работает с той же скоростью. Если размер критичен при деплое, можно попробовать собирать с флагами, которые удаляют служебную информацию из бинарника.
Игорь ПанасюкSoftware Engineer

frankenstein

Генерирует структуры данных из официальной спецификации Telegram Bot API. Вы получаете типы SendMessage, Message, User — они точно соответствуют тому, что описано в документации Telegram.

Библиотека не добавляет абстракций. Хотите отправить сообщение — создаёте структуру SendMessageParams, заполняете chat_id и text, вызываете метод api.send_message(). Хотите обработать команду — сами проверяете, начинается ли текст сообщения со /start.

frankenstein компилируется быстрее teloxide и создаёт меньший бинарник.

teloxide-core

Основа teloxide без диспетчера команд и системы диалогов. Вы работаете напрямую с методами API, но библиотека всё ещё помогает с типами и обработкой ошибок.

Используйте teloxide-core, если архитектура вашего бота не вписывается в teloxide и вы не хотите писать всю логику с нуля в frankenstein.

Подведём итоги

Вы создали бота, который читает сообщения, отвечает на команды, показывает кнопки и работает на сервере. База готова — добавляйте логику под свои задачи:

  • Подключите базу данных (PostgreSQL через tokio-postgres или SQLite через rusqlite).
  • Добавьте HTTP-запросы к внешним API (reqwest).
  • Настройте логирование в файл (log4rs).

Код из статьи — это каркас. Теперь у вас есть работающая основа, которую можно развивать в любом направлении.

Следите за новыми постами
Следите за новыми постами по любимым темам
510 открытий2К показов