Skip to content

Latest commit

 

History

History
580 lines (458 loc) · 15.8 KB

README.md

File metadata and controls

580 lines (458 loc) · 15.8 KB

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