Skip to content

Client for TDLib with Lazarus through the json interface

License

Notifications You must be signed in to change notification settings

dieletro/tdlib-lazarus

Repository files navigation

TDLib-lazarus

This Example was developed by Ruan Diego Lacerda Menezes for use and consumption of the Official Telegram TDLib API for use in Lazarus

Developer Support Group:

Description

Client for TDLib (Telegram database library) with Lazarus through the json interface.

Requirements

Install

Add to your Lazarus project:

superdate.pas
superobject.pas
supertimezone.pas
supertypes.pas
superxmlparser.pas

Declare in your Uses:

superobject;

Configuration

-- Windows

TDLib requires other third-parties libraries: OpenSSL and ZLib. These libraries must be deployed with tdjson library.

Copy the following libraries in the same directory where is your application:

Windows 64

tdjson-x64.dll
libcrypto-1_1-x64.dll
libssl-1_1-x64.dll
zlib1.dll

Windows 32

tdjson.dll	
libcrypto-1_1.dll	
libssl-1_1.dll	
zlib1.dll	

Linux64

Deploy the library libtdjson.so to your device and set the library path calling the method SetTDJsonPath.

Precompiled binaries included in the example project

  • Windows 64.
  • Windows 32.
  • Linux64.
  • OSX64.

Creating your Telegram Application

In order to obtain an API id and develop your own application using the Telegram API you need to do the following: Sign up for Telegram using any application. Log in to your Telegram core: https://my.telegram.org. Go to API development tools and fill out the form. You will get basic addresses as well as the api_id and api_hash parameters required for user authorization. For the moment each number can only have one api_id connected to it. These values must be set in Telegram.API property of Telegram component. In order to authenticate, you can authenticate as an user or as a bot, there are 2 properties which you can set to login to Telegram: PhoneNumber: if you login as an user, you must set your phone number (with international code), example: +5521997196000 DatabaseDirectory: allows to specify where is the tdlib database. Leave empty and will take the default configuration.

The following parameters can be configured:

  • ApplicationVersion: application version, example: 1.0
  • DeviceModel: device model, example: desktop
  • LanguageCode: user language code, example: en or pt, es, ...
  • SystemVersion: verison of operating system, example: windows.

Fundo3

Sample Code

type
  //Global Types Definitions
  MyPCharType = PAnsiChar;
  MyPVoid = IntPtr;

  //Definition of the Session
  TtgSession = record
    Name: String;
    ID: Integer;
    Client : MyPVoid;
  end;

var
  //Variable that receives the dll pointer
  tdjsonDll: TLibHandle = dynlibs.NilHandle;

const
  //DLL name associated with the test project
  {$IFDEF WINDOWS}
    {$IFDEF WIN32}                          //SharedSuffix = dll
       tdjsonDllName : String = 'tdjson.' + SharedSuffix;
    {$ENDIF}
    {$IFDEF WIN64}
       tdjsonDllName : String = 'tdjson-x64.' + SharedSuffix;
    {$ENDIF}
  {$ELSE}
    tdjsonDllName : String = 'libtdjson.so';
  {$ENDIF}

  //Setting the Receiver Timeout
  WAIT_TIMEOUT : double = 1.0; //1 seconds

var
  //should be set to 1, when updateAuthorizationState with authorizationStateClosed is received
  is_closed : integer  = 1;

  //Client Control
  FClient : MyPVoid;

  //Control Session...
  client_session : TtgSession;  

Declare dll functions and procedures

  //Defining DLL methods and functions
  function client_create: MyPVoid; stdcall; external 'tdjson-x64.dll' name 'td_json_client_create';
  procedure client_destroy(handle: MyPVoid); stdcall; external 'tdjson-x64.dll' name 'td_json_client_destroy';
  procedure client_send(handle: MyPVoid; data : MyPCharType); stdcall; external 'tdjson-x64.dll' name 'td_json_client_send';
  function client_receive(handle: MyPVoid; t: double ): MyPCharType; stdcall; external 'tdjson-x64.dll' name 'td_json_client_receive';
  function client_execute(handle: MyPVoid; data : MyPCharType): MyPCharType; stdcall; external 'tdjson-x64.dll' name 'td_json_client_execute';
  procedure set_log_verbosity_level(level: Int32); stdcall; external 'tdjson-x64.dll' name 'td_json_client_set_log_verbosity_level';
  procedure set_log_fatal_error_callback(callback : fatal_error_callback_type); stdcall; external 'tdjson-x64.dll' name 'td_json_client_set_log_fatal_error_callback';

var
  frmLazteste: TfrmLazteste;

implementation

{$R *.lfm}

{ TfrmLazteste } 

Declare this functions:

  public
    //Treatment of the necessary methods and functions
    function td_execute(JsonUTF8: String): String;
    function td_send(JsonUTF8: String): String;
    function td_receive: String;
    function DLLInitialize: Boolean;

Implement this functions and procedures:

function TfrmLazteste.td_execute(JsonUTF8: String): String;
var
  JSonAnsiStr: AnsiString;
begin
  JSonAnsiStr := JsonUTF8;
  Result := client_execute(0, MyPCharType(JSonAnsiStr));
end;  

function TfrmLazteste.td_send(JsonUTF8: String): String;
var
  JsonAnsiStr: AnsiString;
begin
  JsonAnsiStr := JsonUTF8;
  client_send(FClient, MyPCharType(JsonAnsiStr));
  Result := JsonAnsiStr;
end; 

function TfrmLazteste.td_receive: String;
var
  ReturnStr, SDebug:  String;
  X, XParam, TLAuthState, TLEvent, TLUpdateMessage, TLContent, TLText: ISuperObject;
  JsonAnsiStr: AnsiString;
begin
{$REGION 'IMPLEMENTATION'}
  ReturnStr := client_receive(FClient, WAIT_TIMEOUT);

  TLEvent := SO(ReturnStr);

  if TLEvent <> NIl then
  Begin
    {$IFDEF DEBUG}
      SDebug := TLEvent.AsJSON;
    {$ENDIF}

    //# process authorization states
    if TLEvent.S['@type'] = 'updateAuthorizationState' then
    Begin
      TLAuthState := TLEvent.O['authorization_state'];

      //# if client is closed, we need to destroy it and create new client
      if TLAuthState.S['@type'] = 'authorizationStateClosed' then
        Exit;

      //# set TDLib parameters
      //# you MUST obtain your own api_id and api_hash at https://my.telegram.org
      //# and use them in the setTdlibParameters call
      if TLAuthState.S['@type'] = 'authorizationStateWaitTdlibParameters' then
      Begin
        X := nil;
        X := SO;
        X.S['@type'] := 'setTdlibParameters';
        X.O['parameters'] := SO;
        XParam := X.O['parameters'];
          XParam.B['use_test_dc'] := False;
          XParam.S['database_directory'] := 'tdlib';
          XParam.S['files_directory'] := 'myfiles';
          XParam.B['use_file_database'] := True;
          XParam.B['use_chat_info_database'] := True;
          XParam.B['use_message_database'] := True;
          XParam.B['use_secret_chats'] := true;

          JsonAnsiStr := '';
          JsonAnsiStr := txtAPI_ID.Text;
          XParam.I['api_id'] := StrToInt(JsonAnsiStr);

          JsonAnsiStr := '';
          JsonAnsiStr := txtAPI_HASH.Text;
          XParam.S['api_hash'] := JsonAnsiStr;

          XParam.S['system_language_code'] := 'pt';
          XParam.S['device_model'] := 'TInjectTDLibTelegram';
          {$IFDEF WIN32}
            XParam.S['system_version'] := 'WIN32';
          {$ENDIF}
          {$IFDEF WIN64}
            XParam.S['system_version'] := 'WIN64';
          {$ENDIF}
          XParam.S['application_version'] := '1.0';
          XParam.B['enable_storage_optimizer'] := True;
          XParam.B['ignore_file_names'] := False;

        //Send Request
        ReturnStr := td_send(X.AsJSON);
      End;

      //# set an encryption key for database to let know TDLib how to open the database
      if TLAuthState.S['@type'] = 'authorizationStateWaitEncryptionKey' then
      Begin
        X := nil;
        X := SO;
        X.S['@type'] := 'checkDatabaseEncryptionKey';
        X.S['encryption_key'] := '';

        //Send Request
        ReturnStr := td_send(X.AsJSON);
      End;

      //# enter phone number to log in
      if TLAuthState.S['@type'] = 'authorizationStateWaitPhoneNumber' then
      Begin
        //Clear Variable
        JsonAnsiStr:='';

        //Convert String to AnsiString Type
        JsonAnsiStr := txtPhoneNumber.Text;

        X := nil;
        X := SO;
        X.S['@type'] := 'setAuthenticationPhoneNumber';
        X.S['phone_number'] := JsonAnsiStr;

        //Send Request
        ReturnStr := td_send(X.AsJSON);
      End;

      //# wait for authorization code
      if TLAuthState.S['@type'] = 'authorizationStateWaitCode' then
      Begin
        //Clear Variable
        JsonAnsiStr:='';

        //Convert String to AnsiString Type
        JsonAnsiStr := InputBox('User Authorization', 'Enter the authorization code', '');

        X := nil;
        X := SO;
        X.S['@type'] := 'checkAuthenticationCode';
        X.S['code'] := JsonAnsiStr;

        //Send Request
        ReturnStr := td_send(X.AsJSON);
      End;

      //# wait for first and last name for new users
      if TLAuthState.S['@type'] = 'authorizationStateWaitRegistration' then
      Begin
        X := nil;
        X := SO;
        X.S['@type'] := 'registerUser';
        X.S['first_name'] := 'Ruan Diego';
        X.S['last_name'] := 'Lacerda Menezes';

        //send request
        ReturnStr := td_send(X.AsJSON);
      End;

      //# wait for password if present
      if TLAuthState.S['@type'] = 'authorizationStateWaitPassword' then
      Begin
        //Clear Variable
        JsonAnsiStr := '';

        //Convert String to AnsiString Type
        JsonAnsiStr := InputBox('User Authentication ',' Enter the access code', '');

        X := nil;
        X := SO;
        X.S['@type'] := 'checkAuthenticationPassword';
        X.S['password'] := JsonAnsiStr;

        //Send Request
        ReturnStr := td_send(X.AsJSON);
      End;

    End;

    if TLEvent.S['@type'] = 'error' then
    Begin
      //if an error is found, stop the process
      if is_Closed = 0 then
         is_Closed := 1
      else
          is_Closed := 0;

      Showmessage('An error was found:'+ #10#13 +
                  'code : ' + TLEvent.S['code'] + #10#13 +
                  'message : '+TLEvent.S['message']);
    end;

    //Handling New incoming messages
    if TLEvent.S['@type'] = 'updateNewMessage' then
    Begin
      TLUpdateMessage := TLEvent.O['message'];
      TLContent :=  TLUpdateMessage.O['content'];

      //If it's a text message
      if TLContent.S['@type'] = 'messageText' then
      Begin
        TLText := TLContent.O['text'];
        memReceivedMessages.Lines.Add('ChatID : '+TLUpdateMessage.I['chat_id'].ToString+ ' - '+
        'From UserId : '+TLUpdateMessage.I['sender_user_id'].ToString+' : '+TLText.S['text']);
      End;

    end;  
	
    //# handle an incoming update or an answer to a previously sent request
    if TLEvent.AsJSON() <> '' then
    Begin
      Result := 'RECEIVING : '+ TLEvent.AsString;
    End;

  End
  Else
  //# destroy client when it is closed and isn't needed anymore
  Client_destroy(FClient);

  {$ENDREGION 'IMPLEMENTATION'}
end; 

function DLLInitialize: Boolean;
begin
  //I initialize the Function Result to false
  Result := False;

  //Assigning the dll to the variable tdjsonDll
  tdjsonDll := SafeLoadLibrary(tdjsonDllName);

  //Checking if the variable was loaded with the DLL's Pointer
  if tdjsonDll = dynlibs.NilHandle then //DLL was not loaded successfully
  Begin
    raise Exception.CreateFmt('Cannot load Library "%s"'//+ sLineBreak
                             , [tdjsonDllName, GetLoadErrorStr]); //GetLoadErrorStr //GetLastError
    Exit;
  end;

  //Function return definition
  Result := tdjsonDll <> 0; 
end;

Creating a Client:

procedure TfrmLazteste.btnCreateClientClick(Sender: TObject);
begin

  if FClient = 0 then
  Begin
    FClient := client_create;

    with client_session do
    Begin
      Client := FClient;
      ID := MyPVoid(FClient);
      Name := 'Section Desktop TDLib TInjectTelegram';
    End;

    with memSend.Lines do
    Begin
      Add('Name : '+client_session.Name);
      Add('ID : '+client_session.ID.ToString);
      Add('*******Section Initialized********');
    end;

  End
  Else
    Showmessage('There is already a Created Customer!');

end; 

Starting a Service

procedure TfrmLazteste.btnStartClick(Sender: TObject);

  procedure Receiver;
  Begin
    while is_closed = 0 do
    Begin
       with frmLazteste do
         memReceiver.Lines.Add(td_receive);
    End;
  end;

begin

  if FClient = 0 then
  Begin
    Showmessage('Create a client to start the service');
  end
  Else
  Begin
    is_Closed := 0;

      with TThread.CreateAnonymousThread(TProcedure(@Receiver)) do
        begin
          FreeOnTerminate := True;
          Start;
        end;

    memSend.Lines.Add('Service Started!!!');

  end;

end;

Stop Service

procedure TfrmLazteste.btnStopClick(Sender: TObject);
begin
  if is_closed = 1 then
    Showmessage('No active service to stop!')
  Else
  begin
    is_closed := 1;
    memSend.Lines.Add('Service Paused!!!');
  end;
end; 

Set Log Verbosy

procedure TfrmLazteste.btnLogVerbosyClick(Sender: TObject);
var
  JSonAnsiStr: AnsiString;
  X: ISuperObject;
begin
  //# setting TDLib log verbosity level to 1 (errors)
  X := SO;
  X.S['@type'] := 'setLogVerbosityLevel';
  X.I['new_verbosity_level'] := 1;
  X.D['@extra'] := 1.01234;

  //Convert String to AnsiString Type
  JSonAnsiStr := X.AsJSon;

  memSend.Lines.Add('SENDING : '+X.AsJSon);
  memSend.Lines.Add('');

  memReceiver.Lines.Add('RECEIVING : '+td_execute(JSonAnsiStr));
  memReceiver.Lines.Add('');

end; 

Send

procedure TfrmLazteste.btnSendClick(Sender: TObject);
var
  JSonAnsiStr : AnsiString;
  X: ISuperObject;
begin
  if is_closed = 1 then
    Showmessage('No active service to send!')
  Else
  begin
    X := SO;
    X.S['@type'] := 'getAuthorizationState';
    X.D['@extra'] := 1.01234;

    JSonAnsiStr := X.AsJSon;

    memSend.Lines.Add('SENDING : '+X.AsJSon);
    memSend.Lines.Add('');

    td_send(JSonAnsiStr);
  end;
end; 

SendMessage

procedure TfrmLazteste.btnSend1Click(Sender: TObject);
var
  X: ISuperObject;
  JSonAnsiStr: AnsiString;
begin
  if is_closed = 1 then
    Showmessage('No active service to send!')
  Else
  begin
    //ChatID from the TInjectTelegram Group for you to use and test
    //-1001387521713
    X := SO;
    X.S['@type'] := 'sendMessage';
    X.S['chat_id'] := txtChatIdToSend.Text; //ChatID To Send Message Here...
    X.O['input_message_content'] := SO;
    X.O['input_message_content'].S['@type'] := 'inputMessageText';
    X.O['input_message_content'].O['text'] := SO;
    X.O['input_message_content'].O['text'].S['@type'] := 'formattedText';
    X.O['input_message_content'].O['text'].S['text'] := txtMsgToSend.Text; //Your Message TExt here...

    JSonAnsiStr := X.AsJSon;

    memSend.Lines.Add('SENDING : '+X.AsJSon);
    memSend.Lines.Add('');

    td_send(JSonAnsiStr);
  end;

end;   

Ruan Diego Lacerda Menezes (dieletro).

  1. Contatos

License

MIT

Authors

The tdlib-lazarus is designed by Ruan Diego Lacerda Menezes

About

Client for TDLib with Lazarus through the json interface

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages