Бродил тут по интернетам в поисках новых блогов о программирование на delphi и натолкнулся  на блог о программирование на lazarus,  там была пара статей о том как начать делать бота для Telegram. Эта тема меня раньше как то не интересовала, но тут решил попробовать написать хотя бы маленького бота что бы разобраться с принципами работы. Побродив по интернету в поисках наработок по данному вопросу, я ничего интересного не нашел, в основном это были библиотеки для работы с telegram при помощи C#, Python, PHP для delphi нашел только один какой то пробный проект на github. Поэтому решил попробовать сделать все сам с нуля так сказать.

 

 Telegram - бесплатный кроссплатформенный мессенджер для смартфонов и других устройств, позволяющий обмениваться текстовыми сообщениями и медиафайлами различных форматов. Создан Павлом Дуровым не за долго до ухода из вконтакта. В феврале 2016 года один из создателей Telegram Павел Дуров заявил, что мессенджером пользуются уже более 100 миллионов человек, при этом сервис доставляет около 15 миллиардов сообщений ежедневно. 

 

Что бы начать создавать бота необходимо его зарегистрировать в  системе Telegram. 

Для этого необходимо установить на телефон само приложение (либо воспользоваться веб версией клиента ) и добавить в контакты бота BotFather через чат с ним можно управлять своими ботами.

Сначала вводится команда /newbot Затем система предложит ввести имя для бота, если имя систему устроит она предложит указать пользовательское имя для бота с обязательным окончанием имени на bot или _bot, если все продет успешно то система вам выдать уникальный идентификатор бота, который затем можно будет использовать для работы. Он примерно такого вида 12345678:AAHOjf*****ROYb03utz*********. Более подробно можно почитать тут

telephon screen

 

Общение с системой происходит посредством HTTPS запросов GET и POST, в качестве параметров запроса можно передавать 

  • URL query string
  • application/x-www-form-urlencoded
  • application/json (кроме загрузки файлов)
  • multipart/form-data (для загрузки файлов)

Если запрос выполнен удачно то в ответ система вернет json объект

{"ok":true,"result":{[]}}

Где поле ok будет равно true.

Для работы с запросами я решил  использовать набор бесплатных компонентов Synapse, а для парсинга JSON объектов использовать superobject. Поскольку работа с сервисом  осуществляется посредством протокола https, то также потребуются библиотеки OpenSSL,   собрать из исходников можно тут, я же просто вбил название библиотеки в поиск windows и нашел на компе несколько штук из которых выбрал наиболее последнюю версию. Выкладываю для скачивания. ссылка

Поскольку раньше мне не доводилось работать с synapse то пришлось обратиться к интернету, там нашлась подборка статей  по работе с данной библиотекой. 

После скачивания всего и вся я создал простой проект приложения в среде delphi. 

 В раздел uses добавил  httpsend, ssl_openssl, superobject  и начал экспериментировать.

Поскольку для работы с сервисом используется шифрованное соединение то для начала создается компонент httpsend с использованием шифрования.

var
http: THTTPSend;
begin
  http := THTTPSend.Create;
  Http.Sock.CreateWithSSL(TSSLOpenSSL);
  Http.Sock.SSLDoConnect;

Затем данные объект можно использовать для работы с запросами. 

 

В качестве первого запроса я решил получить информацию о боте.

Выполняется это посредством запроса.

https://api.telegram.org/bot<код вашего бота >/getMe

 В коде это выглядело так 

var
  s: string;
  jo: ISuperObject;
  list: TStringList;
begin
  s := 'https://api.telegram.org/bot' + bot_key + '/GetMe';
  if http.HTTPMethod('GET', s) then
  begin
    list := TStringList.Create;
    list.LoadFromStream(http.Document);
    jo := SO(list.Text);
    if jo.B['ok'] = true then
    begin
      Label1.Caption := jo.S['result.id'];
      Label2.Caption := jo.S['result.first_name'];
      Label3.Caption := jo.S['result.username'];
    end;

  end;
  list.Free;
end;

 В качестве результата сервис  возвращает JSON обьект, который распарсивается при помощи объекта ISuperObject. 

Затем попробовал отправить сообщение, но для его отправки необходимо сначала написать что то боту с телефона или через веб клиент иначе не получить идентификатор чата с которым бот будет общаться. Для этого используется запрос вида

https://api.telegram.org/bot<код вашего бота >/getUpdates

В запрос передаются параметры 

 chat_id Идентификатор первого сообщения с которого необходимо получать данные, должен быть на единицу больше чем последнее полученное сообщение. 
 offsetlimit  Ограничитель на количество возвращаемых обновлений, по умолчанию равен 100
timeout  Таймаут в секундах для длительных запросов

 

 

Делается это так примерно.  Поскольку у меня бот тестовый то я особо с кодом не заморачивался.

 

var
  s: string;
  list: TStringList;
  jo: ISuperObject;
  tod: TSuperArray;
  i: Integer;
begin
  http.Headers.Clear;
  http.Document.Clear;
  s := 'https://api.telegram.org/bot' + bot_key + '/getUpdates?offset=' + last_id;
  if http.HTTPMethod('GET', s) then
  begin
    list := TStringList.Create;
    list.LoadFromStream(http.Document);
    jo := SO(list.Text);
    if jo.B['ok'] = True then
    begin

      tod := jo['result'].AsArray;
      for I := 0 to tod.Length - 1 do
      begin
        last_id := tod[i].S['update_id'];
        Memo1.Lines.Add('kod: ' + tod[i].S['update_id'] + '  ' + tod[i].S['message.from.first_name'] + '  ' + tod[i].S['message.from.last_name'] + '  ' + tod[i].S['message.text']);
        with ListView1.Items.Add do
        begin
          Caption := tod[i].S['message.from.id'];
          SubItems.Add(tod[i].S['message.from.first_name'] + ' ' + tod[i].S['message.from.last_name']);
        end;
      end;

    end;

  end;
  list.Free;
end;

 

 

Данный код выдергивает текст и json объекта складывает в memo, а так же собирает в listview идентификаторы пользователей. Затем  выделенному в listview пользователю можно отсылать сообщение.

Сообщение отсылается посредством такого запроса.

https://api.telegram.org/bot<код вашего бота >/sendMessage

В качестве параметров передаются

 chat_id Идентификатор чата то есть пользователя которому отправляется сообщение
 text  Тест сообщения
 parse_mod  если отправляет текст с html или  markdown оформлением
 disable_web_page_preview  Показывать содержимое отправленных ссылок
disable_notification Отсутствие индикации при получение сообщения, у пользователей ios  это будет сообщение без оповещение, у пользователей android это будет сообщение без звука.
reply_to_message_id Идентификатор сообщения на которое был произведен ответ
reply_markup Дополнительные  пользовательские функции, подробнее тут 

 Не обязательно перечислять все параметры в  запросе можно использовать лишь  chat_id и text 

Код получился такой

var
  s: string;
begin
  if ListView1.SelCount = 0 then
  begin
    ShowMessage('выберете получателя сообщения');
    Exit;
  end;
  http.Document.Clear;
  http.Headers.Clear;
  s := Format('https://api.telegram.org/bot%s/sendmessage?chat_id=%s&text=%s', [bot_key, listview1.Selected.Caption, urlencode(edit1.Text)]);
  if http.HTTPMethod('GET', s) then
  Memo1.Lines.LoadFromStream(http.Document);
  end;

 Поскольку запрос передавался методом get то пришлось обработать отправляемый текст функцией urlencode  стянутой с просторов интернета

function UrlEncode(const S: string): string;
var
  i: integer;
  u: ansistring;
  r: ansistring;
begin
  r := '';
  u := ansistring(UTF8Encode(S));
  for i := 1 to Length(u) do
  begin
    case u[i] of
      'A'..'Z', 'a'..'z', '0'..'9', '-', '_', '.':
        r := r + u[i];
    else
      r := r + '%' + ansistring(IntToHex(Ord(u[i]), 2));
    end;
  end;
  Result := string(r);
end;

send message

 

Затем я попробовал отправить фото на телефон, пришлось изрядно повозиться, поскольку раньше не доводилось работать с http запросами на низком уровне.

Сам запрос отправки фото такой.

https://api.telegram.org/bot<код вашего бота >/sendPhoto

В качестве параметров передаются

chat_id Идентификатор чата то есть пользователя которому отправляется сообщение
photo Само фото, либо его идентификатор на серверах telegram
caption Подпись к фото
disable_notification Отсутствие индикации при получение сообщения, у пользователей ios  это будет сообщение без оповещение, у пользователей android это будет сообщение без звука.
reply_to_message_id Идентификатор сообщения на которое был произведен ответ
reply_markup Дополнительные  пользовательские функции, подробнее тут

 Опять же в качестве передаваемых параметров можно использовать не все параметры. Пришлось изрядно повозится с кодировками  структурой http  post запроса.

 Но вот такой корявенький код  получился

var
  s: AnsiString;
  f: TFileStream;
begin
  if not od.Execute() then
    Exit;

  http.Document.Clear;
  http.Headers.Clear;
  //
  http.MimeType := 'multipart/form-data; boundary=' + bound;
  s := GetBoundary(true) + 'Content-Disposition: form-data; name="chat_id";' + sLineBreak + sLineBreak + ListView1.Selected.Caption + sLineBreak + sLineBreak;
  http.Document.Write(PAnsiChar(s)^, Length(s));
  s := GetBoundary(true) + 'Content-Disposition: form-data; name="photo"; filename=' + extractfilename(od.FileName) + sLineBreak + 'Content-Type: multipart/form-data' + sLineBreak + sLineBreak;
  http.Document.Write(PAnsiChar(s)^, Length(s));
  f := TFileStream.Create(od.FileName, fmOpenRead);
  f.Position := 0;
  http.Document.CopyFrom(f, f.Size);
  f.Free;
  s := sLineBreak + GetBoundary(true);
  http.Document.Write(PAnsiChar(s)^, Length(s));
  s := 'Content-Disposition: form-data; name="caption";' + sLineBreak + slinebreak + AnsiToUtf8('Тестовая фотка') + sLineBreak + getboundary(false);
  http.Document.Write(PAnsiChar(s)^, Length(s));
  s := Format('https://api.telegram.org/bot%s/sendphoto', [bot_key]);
  if http.HTTPMethod('POST', s) then
    Memo1.Lines.LoadFromStream(http.Document);

 Разделитель для передаваемых параметров запроса 

function GetBoundary(endf: Boolean): string;
begin
  if (endf) then
    Result := '--' + bound + sLineBreak
  else
    Result := '--' + bound + '--' + sLineBreak;

end;

 send photo

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

P.S.  Буквально в день написания статьи узнал что Павел Дуров раздает  миллион мертвых президентов  разработчикам самых интересных ботов  для Telegram. Более подробно можно почитать тут.

конкурс для разработчиков

Комментарии   

0 #24 fun online rpg game 07.06.2017 10:44
It's a pіty you don't haνe a donatе button! I'd ceгtainlү donate to tҺis outstanding blog!
I guess for noww i'll setle for bookmarkiing and adding your RSS feed to mmy
Googloᥱ account. I looҝ forwаrd too fresh updаtes аnd wwill share thiѕ website with my Fаcebook group.
Talk soon!
Цитировать
0 #23 fifa 18 news 03.06.2017 11:08
Wonderful ᴡebsite you havee here but I was curious about if you
knew of any commjunity forսmѕ that cover the same topics
disⲭussed in thos article? I'd really like too be a part
of online community where I can get fеedbaϲk from other knowledgeable
individᥙals that share the sаme inteгest. If yoᥙ have any recommendatіons , please
let me know. Тhanks a lot!
Цитировать
0 #22 Dorothea 27.05.2017 14:41
Wіth havin sо mᥙсh content do you ever run іnto any
issᥙes of plagorism oг copyright violation? My sie has a lot of comρletely unique content I've either ϲrewated mysef or outsourced bƄսt it seems a
lot oof it is pⲟpping it uup all over the web without
my permission. Do you know anyү ways to help reduϲe content
from being ripped off? I'd certainly appreciate
it.
Цитировать
0 #21 plaza.rakuten.co.jp 16.05.2017 06:59
You could definitely see your expertise within the paintings you write.
The arena hopes for more passionate writers like you who are not afraid to say how they believe.
Always go after your heart.
Цитировать
0 #20 Максим 06.03.2017 21:07
Не знаю о каком репозитории Вы писали - но хочу предложить, как вариант, посмотреть сюда: https://github.com/ms301/TelegAPI
Цитировать
0 #19 Дмитрий 21.12.2016 21:11
Спасибо.
Все доступно и понятно. Сделал бота под свои нужды за день с нуля
Цитировать
0 #18 Andi 28.11.2016 20:19
my email is
Цитировать
0 #17 Sasha 28.11.2016 17:11
Цитирую Andi:
hello..
my name andi, i'm come from Indonesia.
can you help me send full source code to me email
thanks very much for your attention and your help


Hello Andi, can you write you email?
Цитировать
0 #16 Sasha 28.11.2016 17:10
Цитирую Moolex:
Привет, повторно отправлю просьбу:
"можно тогда как нить заполучить проект для Delphi, который здесь расписан в виде одной папки со всеми необходимыми библиотеками и *.pas, чтобы можно было его развернуть и спокойно скомпилировать?
C++ Builder в принципе спокойно подключает файлы pas, с этим я уже разберусь..."
два раза написал письмо, так и не пришел ответ :(

привет, два раза отсылал на указанный ящик, два раза октазывает по причине переполнености ящика
Цитировать
0 #15 Andi 28.11.2016 16:14
hello..
my name andi, i'm come from Indonesia.
can you help me send full source code to me email
thanks very much for your attention and your help
Цитировать

Добавить комментарий


Защитный код
Обновить