View Categories

Отправка

В данной библиотеке, в отличие от многих других, отправка запроса на сервер Telegram идёт не через query string, а в теле запроса типа application/json. Это означает, что отправляемый текст не должен быть urlencoded и не имеет прочих ограничений, и может отправляться в неизменном виде - это сильно экономит время и ресурс контроллера. Также это избавляет от проблем с отправкой сообщений в стилях HTML и Markdown.

ID чата и тип Value #

В большинстве команд отправки нужен id чата - уникальный номер чата или группы в Telegram. Это число выходит за рамки типа данных long, поэтому в библиотеке используется тип данных Value (документация). Он принимает как числа любого типа, так и строки. Таким образом id чата при работе с FastBot2 можно хранить как в строках в любом виде, так и в целочисленной переменной типа int64_t (long long) - очень удобно для взаимодействия и хренения в энергонезависимой памяти (EEPROM/Flash). Например:

Value val;
val = "1234567898765";
val = 1234567898765;

При разборе обновлений id чата является типом Text, который в свою очередь может конвертироваться в int64_t:

int64_t chat_id;

void update(fb::Update& u) {
    u.message().from().id() == 12345678ll;  // сравнение
    chat_id = u.message().from().id();      // сохранение в переменную
}

Поэтому для отправки можно использовать id в любом виде.

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

FastBot2 удобно оборачивает почти весь API по отправке сообщения в класс fb::Message. Типичный сценарий использования:

  • Создать fb::Message
  • Заполнить обязательные параметры - text и chatID
  • По желанию заполнить другие параметры
  • Отправить в sendMessage
fb::Message msg;
msg.text = "some text";
msg.chatID = 123456677889;  // или в виде строки
bot.sendMessage(msg);

Возможна укороченная запись, Message имеет конструктор с минимальными обязательными параметрами:

bot.sendMessage(fb::Message("hello!", "12312424353"));

Асинхронность и ID сообщения #

ID отправленного ботом сообщения можно получить из lastBotMessage(). Нужно понимать, что у каждого чата свой счётчик ID сообщений. Библиотека получает ID отправленного сообщения из ответа сервера, поэтому есть несколько важных моментов.

Сообщение может быть отправлено двумя способами:

  • Синхронно (по умолчанию) - библиотека ждёт и обрабатывает ответ сервера внутри отправки сообщения, поэтому сразу после вызова sendMessage функция lastBotMessage() возвращает актуальный ID отправленного сообщения
  • Асинхронно - библиотека не ждёт ответа от сервера и получит его в следующем tick(), т.е. lastBotMessage() не выдаст достоверный ID сразу после отправки

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

fb::Message msg("hello", 1234567);
bot.sendMessage(msg, false);            // асинхронно
Serial.println(bot.lastBotMessage());   // ID может быть некорректным

bot.sendMessage(msg);                   // синхронно
// библиотека дождётся ответа от предыдущего сообщения перед отправкой нового
Serial.println(bot.lastBotMessage());   // реальный ID

Редактирование сообщений #

Для редактирования текста сообщений используется следующая конструкция:

fb::TextEdit et;
et.text = "edited text";
et.chatID = 123423234;
et.messageID = 234;
bot.editText(et);

Вот так например бот будет удалять сообщения юзера и вместо этого менять текст своего последнего сообщения на текст сообщения юзера:

// удалить сообщение юзера
bot.deleteMessage(u.message().chat().id(), u.message().id());

// редактировать
if (bot.lastBotMessage()) {
    fb::TextEdit et;
    et.text = u.message().text().toString();
    et.chatID = u.message().chat().id();
    et.messageID = bot.lastBotMessage();
    bot.editText(et);
} else {
    // отправить сообщение, если бот не знает id своего последнего сообщения
    bot.sendMessage(fb::Message(u.message().text(), u.message().chat().id()));
}

Отдельно можно редактировать меню сообщения через MenuEdit, см. следующую страницу документации.

Отправка нескольким ID #

Если ID хранятся в текстовом виде в виде CSV списка, то можно использовать парсер Text:

fb::Message msg;
msg.text = "hello!";

su::TextParser ids("546343285;1234853;8796453678;38347567", ';');
while (ids.parse()) {
    msg.chatID = ids;
    bot.sendMessage(msg);
}

Если id - это массив int64_t - то всё проще:

int64_t ids[..];    // массив id
int ids_len;        // фактическая длина

// ...
fb::Message msg;
msg.text = "hello!";

for (int i = 0; i < ids_len; i++) {
    msg.chatID = ids[i];
    bot.sendMessage(msg);
}

Отправка вручную #

Библиотека поддерживает самостоятельную сборку пакетов для отправки на сервер согласно API Telegram. Для сборки используется линейный сборщик json строк gson::string - вот документация. Создание и отправка пакета выглядит так:

  • Начать пакет с указанием команды
  • Собрать пакет, указав нужные данные
  • Отправить пакет

Отправка сообщения в чат:

// Все команды API Telegram доступны в tg_cmd
fb::Packet p = bot.beginPacket(tg_cmd::sendMessage);

// все ключи объектов API Telegram доступны в tg_api
p.addString(tg_api::text, "message text");
p.addInt(tg_api::chat_id, 12312341231);
bot.sendPacket(p);

Установка команд бота, способ 1 (с элементом json строки):

fb::Packet p = bot.beginPacket(tg_cmd::setMyCommands);
p.beginArr(tg_api::commands);
p.addText(R"(
    {"command":"help","description":"Помощь по командам"},
    {"command":"info","description":"Информация о настройках"}
)");
p.endArr();
bot.sendPacket(p);

Установка команд бота, способ 2 (полностью нативная сборка):

fb::Packet p = bot.beginPacket(tg_cmd::setMyCommands);
p.beginArr(tg_api::commands);
p.beginObj().addString(tg_api::command, "help").addString(tg_api::description, "Помощь по командам").endObj();
p.beginObj().addString(tg_api::command, "info").addString(tg_api::description, "Информация о настройках").endObj();
p.endArr();
bot.sendPacket(p);

Второй способ #

Подходит для json пакетов, собранных отдельно. Использует больше памяти, чем beginPacket-sendPacket (дублирует пакет перед отправкой). Отправлять можно как json объект вида {"key":"value"...}, так и список значений без фигурных скобок (библиотека добавит их сама): "key":"value".... Например:

// свой пакет
bot.sendCommand(tg_cmd::sendMessage, "{\"chat_id\":1234567864,\"text\":\"hello text\"}");

// сборка в gson::string
gson::string g;
g[tg_api::chat_id] = 1234567864;
g[tg_api::text] = "hello text";
bot.sendCommand(tg_cmd::sendMessage, g);

Дополнение стандартных типов #

Во всех стандартных типах библиотеки (Message, Location и проч.) есть поле json, в которое можно добавлять данные, не предусмотренные библиотекой, но предусмотренные Telegram API. Например:

fb::Message msg("version 3", CHAT_ID);
msg.json[tg_api::business_connection_id] = "12345";
msg.json[tg_api::message_effect_id] = "asdadawdwd";
bot.sendMessage(msg);

Важный момент - нельзя добавлять данные, которые добавляются библиотекой, например поля text и chat_id - телеграм не примет такой запрос с дублирующимися ключами!

Разбор ответа сервера #

Все методы отправки запросов возвращают результат типа fb::Result - если запрос был синхронный (по умолчанию), то в результате будет распарсенный ответ сервера. Это позволяет отправлять запросы и получать результат на следующей же строчке кода. Например запрос getMe:

fb::Result res = bot.sendCommand(tg_cmd::getMe);
Serial.println(res[tg_apih::first_name]);  // имя бота
Serial.println(res[tg_apih::username]);    // ник бота
// res.stringify(Serial);                 // вывести весь пакет
// Serial.println(res.getRaw());          // вывести ответ сервера текстом как он есть

Для уменьшения использования оперативной памяти рекомендуется оборачивать все запросы с разбором результата в блоки кода {}, чтобы результат освобождал память после использования:

{
    fb::Result res = bot.sendCommand(tg_cmd::getMe);
    Serial.println(res[tg_apih::first_name]);
}
{
    gson::string g;
    g[tg_api::chat_id] = 1234567864;
    fb::Result res = bot.sendCommand(tg_cmd::getChat, g);
    Serial.println(res[tg_apih::title]);
}
{
    fb::Result res = bot.sendMessage(fb::Message("hello!", "12312424353"));
    res.stringify(Serial);
}

Также освободить память можно, вызвав reset():

fb::Result res1 = bot.sendCommand(tg_cmd::getMe);
Serial.println(res1[tg_apih::first_name]);
res1.reset();

gson::string g;
g[tg_api::chat_id] = 1234567864;
fb::Result res2 = bot.sendCommand(tg_cmd::getChat, g);
Serial.println(res2[tg_apih::title]);
res2.reset();

fb::Result res3 = bot.sendMessage(fb::Message("hello!", "12312424353"));
res3.stringify(Serial);
res3.reset();

HTML и Markdown #

Режимы текста HTML и Markdown поддерживают только конкретные теги, см. API Telegram:

Для настройки режима нужно просто указать его:

fb::Message msg;
msg.mode = fb::Message::Mode::MarkdownV2;
msg.text...

Markdown #

Для режима Markdown нужно соблюдать некоторые правила:

  • Любой символ может быть экранирован с помощью \, чтобы выводиться просто символом, а не разметкой MD. Например "test\\_" выведет test_, без экранирования будет ошибка
  • Внутри блоков кода символы <code> </code> и \ должны быть экранированы с помошью `
  • Внутри блока ссылки в (круглых скобках) все ) и \ должны быть экранированы с помошью \
  • Во всех остальных случаях символы _, *, [, ], (, ), ~, <code> </code>, >, #, +, -, =, |, {, }, ., ! должны быть экранированы с помошью `

FastBot2 не экранирует символы! Это нужно делать самостоятельно
Например для вывода текста [hello] - world! нужно писать "\\[hello\\] \\- world\\!"

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Прокрутить вверх