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