Как стать автором
Обновить

Пишем Telegram Bot на Delphi XE 7

Пишем Telegram Bot на Delphi XE 7

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

Опишем Основные модули которые будем использовать

  • idHTTP - нам нужен для взаимодействия через протокол http

  • SuperObject - используем для работы с json

  • IdIOHandler, idIOHandlerSocket и остальные мы используем чтобы можно было использовать протокол защищенный https

uses
    System.Classes,System.SysUtils,IdHTTP,SuperObject,
    IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL;

Объявим постоянные константы, которые не будем менять

 const
    BaseUrl ='https://api.telegram.org/bot';
    API='ваш api ключ';

Объявим переменные

var
   JsObject: ISuperObject;
   THttp : TIdHTTP;
   SSL : TIdSSLIOHandlerSocketOpenSSL;

Обьявим процедуру

type
 TCallbackProc = procedure(user_id,user_name,user_message:String);

Объявим Основной поток и функции которые будем использовать

 type
 TTelegramBot = class(TThread)
   public
    task_pos: Integer; // Позиция в гриде
    cur_status : String; // Текущии Статус

    constructor Create(Asyspended: Boolean);
    destructor Destroy;
   private
   CallProcedure : TCallbackProc;
   response : String; // Ответ Который вернул бот без распарсивания
   user_id : String; // useid пользователя написавшего
   user_name : String; // имя пользователя который написал нам
   user_message : String; // сообщение которое написал пользователь
   Procedure Status(); // Процедура обработки статусов от бота
     protected
    procedure Execute; override;
 end;
 
type
 TTelegramObject = class(TObject)
   public
    Connected : Boolean;
   function StartListen(CallProc:TCallbackProc):TTelegramBot;
   Function SendMessageTelegram(IDUser,Text: String):String;
   Function ConnectTelegramBot():Boolean;

 end;

Опишем Функцию которая будем создавать и запускать наш обьект TelegramBot и возвращать экземпляр обьекта для остановки сервиса

Function TTelegramObject.StartListen(CallProc:TCallbackProc):TTelegramBot;
var
  TBot:  TTelegramBot;
begin

    TBot:= TTelegramBot.Create(false);
    TBot.Priority := tpLowest;
    TBot.FreeOnTerminate := True;
    TBot.CallProcedure :=  CallProc;
    TBot.task_pos:=1;
    TBot.Resume;

    Result := TBot;
end;

Опишем Функцию которая будем производить соединение с Telegram и возвращать результат положительный либо отрицаательный

// Подключимся к боту через токен
Function TTelegramObject.ConnectTelegramBot():Boolean;
var res : Boolean;
    conf: TConf;
begin
   try
     res := true;
     THttp:=TIdHTTP.Create;
     THttp.ProtocolVersion := pv1_1;
     THttp.Request.BasicAuthentication := false;
     THttp.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';


   conf := PinguinServerForm.Conf;

    if(conf.proxy_enable)then
    begin
     THttp.ProxyParams.ProxyServer := conf.proxy_server;
     THttp.ProxyParams.ProxyPort := conf.proxy_port;
     THttp.ProxyParams.ProxyUsername := conf.proxy_username;
     THttp.ProxyParams.ProxyPassword := conf.proxy_password;
    end;

    SSL:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
     SSL.SSLOptions.Method := sslvSSLv3;
     SSL.SSLOptions.SSLVersions := [sslvSSLv3];
     SSL.SSLOptions.Mode := sslmUnassigned;

     SSL.SSLOptions.VerifyMode := [];
     SSL.SSLOptions.VerifyDepth := 0;

   //  SSL.SSLOptions.RootCertFile := 'D:/YOURPUBLIC.pem';
    // SSL.SSLOptions.CertFile := 'D:/YOURPUBLIC.pem';


     THttp.IOHandler:=SSL;
     JsObject:=SO(THTTP.Get(BaseUrl+API+'/GetMe'));
  if JsObject.B['ok']=True then //Ауторизация успешна
  begin   res:= true;    end;



  finally
     Connected := res;
     Result := res;
    THttp.Free;
     SSL.Free;
  end;
end;

Опишем Функцию Отправки Сообщения в Telegrambot с возвратом ошибки если она произошла

// Отправим Сообщение Пользователю зная его ID
 Function TTelegramObject.SendMessageTelegram(IDUser,Text: String):String;
var
  JsObject: ISuperObject;
  zapros:String;
  conf : Tconf;
begin
   zapros:='/sendmessage?'+'chat_id='+IDUser+'&'+'text='+Text;
   try

     THttp:=TIdHTTP.Create;
     THttp.ProtocolVersion := pv1_0;
     conf := PinguinServerForm.Conf;

    if(conf.proxy_enable)then
    begin
     THttp.ProxyParams.ProxyServer := conf.proxy_server;
     THttp.ProxyParams.ProxyPort := conf.proxy_port;
     THttp.ProxyParams.ProxyUsername := conf.proxy_username;
     THttp.ProxyParams.ProxyPassword := conf.proxy_password;
    end;  
      
     SSL:=TIdSSLIOHandlerSocketOpenSSL.Create;
     THttp.IOHandler:=SSL;

     JsObject:=SO(THTTP.Get(BaseUrl+API+Zapros));
     if JsObject.B['ok']=True then
     begin
     Result := ' Бот написал '+JsObject.s['result.chat.username']+' : '+JsObject.s['result.text'];
     end;   
   except on E:EXCEPTION do begin
       Result := e.Message+' Ошибка отправки сообщения!';
                            end;
   end;

    THttp.Free;
     SSL.Free;


end;

Опишем Функцию которая будем проверять есть ли новый сообщения которые написали боту в Telegram

 procedure TTelegramBot.Execute;
var
  RHttp:TIdHTTP;
  RSSL:TIdSSLIOHandlerSocketOpenSSL;
  Offset:integer;
  JsObject1, JsObject2: ISuperObject;
  conf : Tconf;
begin
  Offset := 0;
  RHttp:=TIdHTTP.Create;

     conf := PinguinServerForm.Conf;

    if(conf.proxy_enable)then
    begin
     THttp.ProxyParams.ProxyServer := conf.proxy_server;
     THttp.ProxyParams.ProxyPort := conf.proxy_port;
     THttp.ProxyParams.ProxyUsername := conf.proxy_username;
     THttp.ProxyParams.ProxyPassword := conf.proxy_password;
    end;


  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
      begin
      cur_status := '';
      user_id := JsObject2.s['message.from.id']; //Его ИД по которому можем ему написать
      user_name := JsObject2.s['message.from.first_name']+' '+JsObject2.s['message.from.last_name']; //Это имя написавшего боту
      user_message :=  JsObject2.s['message.text'];  //Текст сообщения
      Synchronize(Status); // Сообщим что есть ответ
      end;
     end;
   if Terminated then break;
  end;
 RHttp.Free;
 RSSL.Free;
end;

Ниже привожу, весь код полностью


unit telegrambot_unit;

interface

  uses
    System.Classes,System.SysUtils,IdHTTP,SuperObject,
    IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL;


  const
    BaseUrl ='https://api.telegram.org/bot';
    API='ваш api key';

   var
   JsObject: ISuperObject;
   THttp : TIdHTTP;
   SSL : TIdSSLIOHandlerSocketOpenSSL;

type
 TCallbackProc = procedure(user_id,user_name,user_message:String);


  type
 TTelegramBot = class(TThread)
   public
    task_pos: Integer; // Позиция в гриде
    cur_status : String; // Текущии Статус

    constructor Create(Asyspended: Boolean);
    destructor Destroy;
   private
   CallProcedure : TCallbackProc;
   response : String; // Ответ Который вернул бот без распарсивания
   user_id : String; // useid пользователя написавшего
   user_name : String; // имя пользователя который написал нам
   user_message : String; // сообщение которое написал пользователь
   Procedure Status(); // Процедура обработки статусов от бота
     protected
    procedure Execute; override;
 end;


 type
 TTelegramObject = class(TObject)
   public
    Connected : Boolean;
   function StartListen(CallProc:TCallbackProc):TTelegramBot;
   Function SendMessageTelegram(IDUser,Text: String):String;
   Function ConnectTelegramBot():Boolean;

 end;

 implementation

 uses pinguin_unit;

// запуск Потоков для пинга аипи адресов
Function TTelegramObject.StartListen(CallProc:TCallbackProc):TTelegramBot;
var
  TBot:  TTelegramBot;
begin

    TBot:= TTelegramBot.Create(false);
    TBot.Priority := tpLowest;
    TBot.FreeOnTerminate := True;
    TBot.CallProcedure :=  CallProc;
    TBot.task_pos:=1;
    TBot.Resume;

    Result := TBot;
end;


// Подключимся к боту через токен
Function TTelegramObject.ConnectTelegramBot():Boolean;
var res : Boolean;
    conf: TConf;
begin
   try
     res := true;
     THttp:=TIdHTTP.Create;
     THttp.ProtocolVersion := pv1_1;
     THttp.Request.BasicAuthentication := false;
     THttp.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';


   conf := PinguinServerForm.Conf;

    if(conf.proxy_enable)then
    begin
     THttp.ProxyParams.ProxyServer := conf.proxy_server;
     THttp.ProxyParams.ProxyPort := conf.proxy_port;
     THttp.ProxyParams.ProxyUsername := conf.proxy_username;
     THttp.ProxyParams.ProxyPassword := conf.proxy_password;
    end;

    SSL:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
     SSL.SSLOptions.Method := sslvSSLv3;
     SSL.SSLOptions.SSLVersions := [sslvSSLv3];
     SSL.SSLOptions.Mode := sslmUnassigned;

     SSL.SSLOptions.VerifyMode := [];
     SSL.SSLOptions.VerifyDepth := 0;

   //  SSL.SSLOptions.RootCertFile := 'D:/YOURPUBLIC.pem';
    // SSL.SSLOptions.CertFile := 'D:/YOURPUBLIC.pem';


     THttp.IOHandler:=SSL;
     JsObject:=SO(THTTP.Get(BaseUrl+API+'/GetMe'));
  if JsObject.B['ok']=True then //Ауторизация успешна
  begin   res:= true;    end;



  finally
     Connected := res;
     Result := res;
    THttp.Free;
     SSL.Free;
  end;
end;

 // Отправим Сообщение Пользователю зная его ID
 Function TTelegramObject.SendMessageTelegram(IDUser,Text: String):String;
var
  JsObject: ISuperObject;
  zapros:String;
  conf : Tconf;
begin
   zapros:='/sendmessage?'+'chat_id='+IDUser+'&'+'text='+Text;
   try

     THttp:=TIdHTTP.Create;
     THttp.ProtocolVersion := pv1_0;
     conf := PinguinServerForm.Conf;

    if(conf.proxy_enable)then
    begin
     THttp.ProxyParams.ProxyServer := conf.proxy_server;
     THttp.ProxyParams.ProxyPort := conf.proxy_port;
     THttp.ProxyParams.ProxyUsername := conf.proxy_username;
     THttp.ProxyParams.ProxyPassword := conf.proxy_password;
    end;  

     {  THTTP.Get('http://192.168.1.15:1818/API/'+IDUser+'/'+Text);
        Result := 'Отправил сообщение через NODE TELEGRAM SERVER '+IDUser;
}
      
     SSL:=TIdSSLIOHandlerSocketOpenSSL.Create;
     THttp.IOHandler:=SSL;

     JsObject:=SO(THTTP.Get(BaseUrl+API+Zapros));
     if JsObject.B['ok']=True then
     begin
     Result := ' Бот написал '+JsObject.s['result.chat.username']+' : '+JsObject.s['result.text'];
     end;   
   except on E:EXCEPTION do begin
       Result := e.Message+' Ошибка отправки сообщения!';
                            end;
   end;

    THttp.Free;
     SSL.Free;


end;

 procedure TTelegramBot.Execute;
var
  RHttp:TIdHTTP;
  RSSL:TIdSSLIOHandlerSocketOpenSSL;
  Offset:integer;
  JsObject1, JsObject2: ISuperObject;
  conf : Tconf;
begin
  Offset := 0;
  RHttp:=TIdHTTP.Create;

     conf := PinguinServerForm.Conf;

    if(conf.proxy_enable)then
    begin
     THttp.ProxyParams.ProxyServer := conf.proxy_server;
     THttp.ProxyParams.ProxyPort := conf.proxy_port;
     THttp.ProxyParams.ProxyUsername := conf.proxy_username;
     THttp.ProxyParams.ProxyPassword := conf.proxy_password;
    end;


  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
      begin
      cur_status := '';
      user_id := JsObject2.s['message.from.id']; //Его ИД по которому можем ему написать
      user_name := JsObject2.s['message.from.first_name']+' '+JsObject2.s['message.from.last_name']; //Это имя написавшего боту
      user_message :=  JsObject2.s['message.text'];  //Текст сообщения
      Synchronize(Status); // Сообщим что есть ответ
      end;
     end;
   if Terminated then break;
  end;
 RHttp.Free;
 RSSL.Free;
end;

Procedure TTelegramBot.Status;
begin
   cur_status := '';
   PinguinServerForm.Log(user_name+' '+user_message,false);
   CallProcedure(user_id,user_name,user_message);
end;

 constructor TTelegramBot.Create(Asyspended: Boolean);
begin
  FreeOnTerminate := True;
  inherited Create(Asyspended);
end;

destructor TTelegramBot.Destroy;
begin
PinguinServerForm.Log('destroy thread telegram',false);
 // PinguinServerForm.DeleteARow(PinguinServerForm.GridTaskList, (task_pos - 1));
  inherited;
end;

end.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.