Pull to refresh

Пишем 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.

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.