В продолжении статьи Telegram Bot API. Часть 1 продолжим разбираться с API Telegram. Как я и говорил, в этой статье я покажу вам как отсылать и принимать сообщения из нашей программы.
С отправкой сообщений проблем возникнуть не должно, составить запрос не составляет особого труда. Единственный нюанс, бот может писать сообщения лишь тем пользователям которые написали ему первыми.
Запрос выглядит следующим образом:
https://api.telegram.org/botВашТокен/sendmessage?chat_id=IDЧата&text=Текст сообщения;
Где брать Токен, мы уже узнали в первой статье. ID Чата мы получаем из принятого сообщения, чуть ниже разберем подробнее.
При выполнении запроса на отправку сообщения, в случае удачной отправки, в ответ мы должны получить отправленное нам сообщение в формате JSON:
{"ok":true,"result":{"message_id":103,"from":{"id":....,"first_name":"Lazarus_Bot","username":"devlaz_bot"},"chat":{"id":.....,"first_name":"\u041e\u043b\u0435\u0433","username":"EOleg","type":"private"},"date":1460455425,"text":"devlaz.ru","entities":[{"type":"url","offset":0,"length":9}]}}
После отправки сообщения, в программе я проверяю статус «ok»=True
Хочу обратить внимание что обмен данными с Telegram происходит в кодировке UTF8, наш Lazarus как раз по умолчанию работает именно в этой кодировке, поэтому проблем возникнуть не должно.
Итак для того чтобы отправить сообщение из программы я создал процедуру:
procedure TFormMain.SendMessage(IDUser,Text: String); var JsObject: ISuperObject; zapros:String; begin zapros:='/sendmessage?'+'chat_id='+IDUser+'&'+'text='+Text; try JsObject:=SO(THTTP.Get(BaseUrl+API+Zapros)); if JsObject.B['ok']=True then begin FormMain.MemoLog.Lines.add(TimeToStr(now)+' Бот написал '+JsObject.s['result.chat.username']+' : '+JsObject.s['result.text']); end; except ShowMessage('Ошибка отправки сообщения!'); end; end;
Теперь для отправки сообщения в программе я просто вызываю данную процедура:
SendMessage("ID Чата","Наше сообщение");
Обратите внимание что я не стал описывать процесс создания THttp, SSL, а так же переменные BaseUrl и API которые мы в прошлой статье добавили в Const. В принципе вопросов не должно возникнуть, с отправкой все просто.
Для того чтобы принять сообщения требуется постоянно слать запрос на обновления GetUpdate. Разработчики позаботились о возможности выставить таймаут на запрос, чтобы он как бы замирал в ожидании события.
Для начала давайте посмотрим как выглядит сам запрос:
https://api.telegram.org/botВашТокен/getUpdates?offset=ID_последнего_сообщения&timeout=30
Offset задает последнее обработанное сообщение + 1, его мы узнаем после выполнения запроса.
Timeout задает сколько мы будем ждать ответа от сервера. Я поставил оптимальное значение 30 сек. Вы можете использовать любое удобное для вас.
В ответ на данный запрос мы должны получить примерно следующий ответ:
{"ok":true,"result":[]}
Если сообщений нет или:
{"ok":true,"result":[{"update_id":158553581, "message":{"message_id":104,"from":{"id":1281487,"first_name":"\u041e\u043b\u0435\u0433","username":"EOleg"},"chat":{"id":1281487,"first_name":"\u041e\u043b\u0435\u0433","username":"EOleg","type":"private"},"date":1460470734,"text":"Hello"}}]}
Здесь нас интересуют следующие данные:
update_id: к данному значению мы прибавляем единицу и забиваем при следующим запросе в Offset иначе мы будем постоянно получать данное сообщение (Оно будет не прочитанным)
«chat»:{«id»:1281487: Это и есть тот самый «ID чата» который требуется указывать при отправке сообщения.
«text» : Это текст присланного сообщения.
Выполнять данный запрос советую в отдельном потоке, чтобы избежать зависания программы из-за Timeout
Сам код выглядит так:
procedure TGetUpdate.Execute; var RHttp:TIdHTTP; RSSL:TIdSSLIOHandlerSocketOpenSSL; Offset:integer=0; JsObject1, JsObject2: ISuperObject; begin RHttp:=TIdHTTP.Create; RSSL:=TIdSSLIOHandlerSocketOpenSSL.Create; RHttp.IOHandler:=RSSL; while True do begin JsObject1:=SO(RHTTP.Get(BaseUrl+API+'/getUpdates?offset='+IntToStr(Offset)+'&timeout=30')); JsObject2:= JsObject1.A['result'].N[0]; Offset:=JsObject2.i['update_id'] + 1; //В случае если сообщений не было, Offset станет равным 1. if Offset<>1 then begin if JsObject2.s['message.text']<>'' then Memo1.lines.add(JsObject2.s['message.from.username']+' '+ //Это имя написавшего боту JsObject2.s['message.from.id']+' : '+ //Его ИД по которому можем ему написать JsObject2.s['message.text']); //Текст сообщения end; if GetUpdate.Terminated then break; end; RHttp.Free; RSSL.Free; end;
И так мы разобрались как отсылать и принимать сообщения, в следующей статье я покажу как принимать файлы.
Ведется разработка библиотеки для работы с Telegram API https://github.com/Al-Muhandis/fp-telegram , также как плагин к brookframework https://github.com/Al-Muhandis/brook-telegram
Акцент пока сделан на получении обновлений через webhook. Используются только родные инструменты fpc. Если есть желание можете присоединиться
Ты лучший
Пока не написали статью об отправке картинок, подскажите, пож., как же их отправлять? Все просто, если картинка есть где-то в интернете (отправляем BaseUrl+API+’/sendphoto?chat_id=’+ID+’&photo=’+URL), но что делать, если картинка лежит в файле (сгенерирована самим ПО только что)?
неужели класть на любой сервер, чтобы потом отправлять с помощью URL ?
спасибо…
И спасибо за отличный блог и статьи.
Если использовать библиотеку fp-telegram, то можно отправить фото потоком TFileStream, предварительно загрузив поток из файла. После чего передать поток в параметре APhotoStream
TStream function sendPhotoStream(chat_id: Int64; const AFileName: String; APhotoStream: TStream;
const ACaption: String; ReplyMarkup: TReplyMarkup = nil): Boolean;
У Вас не продлен сертификат Let’s Encrypt. Рекомендую CDN Cloudflare. ТАм автоматом включается защищенный режим. Никаких доп. действий по продлению или регистрации
Бред. Отсылать сообщения из делфи вообще не актуально — все делается в телеграмм. Делфи интересен только как обработчик команд от пользователя, который дал боту какую-либо команду.
И про постоянные запросы GetUpdate тоже полнейшая чушь — есть вебхуки, чтобы телеграмм сам отправлял запросы куда-либо. И в этом случае на Делфи надо писать серверную часть, а не клиента. Короче — статья для детских игр, не помогает в реальных проектах.