استفاده از کتابخانه TDLib در Elixir

سلام به همه دوستان
بنده برای یک پروژه تازه Elixir رو شروع کردم و اصلا حرفه‌ای نیستم. تو این پروژه ما از کتابخانه tdlib استفاده کردیم اما متاسفانه هیچ کدی برای Sample نداده. برای تست اولیه من میخوام یک پیام ارسال کنم که به خطای عجیبی میخورم
نمونه کد:

defmodule TestTDLib.TelegramRequest.TDLibRequest do

require Logger
alias TDLib.{Method, Object}

@session :demosession
# @api_id Application.get_env(:tdlib_client, :api_id)
# @api_hash Application.get_env(:tdlib_client, :api_hash)
@disclaimer """
/!\ This is a simple, non-OTP way to interact with tdlib. It's definetly not
how you should do it, but it show you every step in a readable way.
"""

defp loop() do
receive do
  {:recv, msg} ->
   IO.inspect msg
    IO.puts Map.get(msg, :"@type") <> " received."
    case msg do
      %Object.UpdateAuthorizationState{authorization_state: auth_state} ->
        case auth_state do

          %Object.AuthorizationStateWaitTdlibParameters{} ->
            IO.puts "Query is: AuthorizationStateWaitTdlibParameters"
            :ignore # Handled by TDLib

          %Object.AuthorizationStateWaitEncryptionKey{} ->
            IO.puts "Query is: AuthorizationStateWaitEncryptionKey"
            :ignore # Handled by TDLib

          %Object.AuthorizationStateWaitPhoneNumber{} ->
            phone_number = IO.gets("Please provide phone number: ") |> String.trim
            query = %Method.SetAuthenticationPhoneNumber{
              phone_number: phone_number,
              allow_flash_call: false
            }
            IO.inspect query
            IO.puts "SetAuthenticationPhoneNumber is done"
            TDLib.transmit @session, query

          %Object.AuthorizationStateWaitCode{} ->
            code = IO.gets("Please authentication code: ") |> String.trim()
            query = %Method.CheckAuthenticationCode{code: code}
            IO.inspect query
            IO.puts "CheckAuthenticationCode is done"
            TDLib.transmit @session, query

          %Object.AuthorizationStateReady{} ->
            IO.puts "Authentification successful!"
          _ -> # Ignore anyother state
            :ignore
        end

      _ -> # Ignore any other message (there are a lot of them!)
        :ignore
    end
end

loop()
end

def run_demo() do
IO.puts @disclaimer
start? = IO.gets("Start demo client? [y/n]") |> String.trim()
unless start? in ["y", "Y"], do: System.halt()

# Hide 'debug' logs
# Logger.configure(level: :info)

config = struct(
  TDLib.default_config(), %{api_id: "979055", api_hash: "dd3a53efdedeb7e9aa1cb950d97d0ce8"}
)

# Open a new session
{:ok, _pid} = TDLib.open(@session, self(), config)

# Set TDLib (C++) verbosity to 0
TDLib.transmit @session, "verbose 0"

 loop()
end

defp test() do
receive do
  {:recv, msg} ->
   IO.inspect msg
    IO.puts Map.get(msg, :"@type") <> " received."
    case msg do
      %Object.UpdateAuthorizationState{authorization_state: auth_state} ->
        case auth_state do
          %Object.AuthorizationStateWaitTdlibParameters{} ->
            IO.puts "Query is: AuthorizationStateWaitTdlibParameters"
            :ignore # Handled by TDLib

          %Object.AuthorizationStateWaitEncryptionKey{} ->
            IO.puts "Query is: AuthorizationStateWaitEncryptionKey"
            :ignore # Handled by TDLib

          %Object.AuthorizationStateReady{} ->
            IO.puts "Authentification successful!"

            # chatId = IO.gets("Please chat_id code: ") |> String.trim()
            query = %Method.SendMessage{
              chat_id: Enter chat id,
              input_message_content: %Object.MessageText {
                text: "Test Elixir"
              }
            }
            query = Poison.encode!(query)
            IO.inspect query
            TDLib.transmit @session, query

          _ -> # Ignore anyother state
            :ignore
        end

      _ -> # Ignore any other message (there are a lot of them!)
        :ignore
    end
end

test()
end

def testLogin do
    IO.puts "Test Done"

    config = struct(
  TDLib.default_config(), %{api_id: "979055", api_hash: "dd3a53efdedeb7e9aa1cb950d97d0ce8"}
)

# Open a new session
{:ok, _pid} = TDLib.open(@session, self(), config)

  test()
  end 
end

این هم پیغام خطایی که میده:

Authentification successful!
"{\"reply_to_message_id\":null,\"reply_markup\":null,\"input_message_content\":{\"web_page\":null,\"text\":\"Test Elixir\",\"@type\":\"messageText\"},\"from_background\":null,\"disable_notification\":null,\"chat_id\":\"chatId\",\"@type\":\"sendMessage\"}"
%TDLib.Object.Ok{"@type": "ok"}
ok received.
[ 1][t 0][1576499647.201617002][ClientJson.cpp:78][&status.is_error()]	Failed to parse [request:{\042reply_to_message_id\042:null,\042reply_markup\042:null,\042input_message_content\042:{\042web_page\042:null,\042text\042:\042Test Elixir\042,\[email protected]\042:\042messageText\042},\042from_background\042:null,\042disable_notification\042:null,\042chat_id\042:\042chatId\042,\[email protected]\042:\042sendMessage\042}] [Error : 0 : Unknown class]

من الکسیر کار نکردم و نمیدونم این لایبرری چیه ولی اروری که داده Failed to parse هست.
احتمالا نوع دیتایی که به دستش رسیده، نامفهومه. مثلا منتظر json بوده چیز دیگه‌ای گرفته.

بله دوست عزیز خودم خطا رو دیدم و گوگل هم کردم. کد رو میدیدین حتی

query = Poison.encode!(query)

رو هم نوشتم!

1 Like

سلام به همه دوستان
مشکل رو خودم حل کردم. اگر کسی نیاز داشت بگه تا براش توضیح بدم

اگه لطف کنید توضیح بدید ممنون میشم.
برای کسی که ممکنه بعدا نیاز بهش داشته باشه.

بله حتما.
اول یک توضیح مختصر در مورد TDLib میدم. TDLib یک کتابخانه fully functional برای تلگرام می‌باشد که شما میتونین تقریبا همه کارها و دستورات تلگرام رو داره و شما با این دستورات میتونین به سرورهای تلگرام درخواست تون رو بزنین و جواب تون رو بگیرین. مثلا من تو این بحث میخواستم با Elixir یک درخواست ارسال پیام رو به یک Chat ID خاص بفرستم. حالا همون نمونه کد بالا رو درستش رو اینجا میزارم:

defmodule TestTDLib.TelegramRequest.TDLibRequest do

  require Logger
  alias TDLib.{Method, Object}

  @session :demosession

  @disclaimer """
  /!\ This is a simple, non-OTP way to interact with tdlib. It's definetly not
  how you should do it, but it show you every step in a readable way.
  """

  defp loop() do
    receive do
      {:recv, msg} ->
       IO.inspect msg
        IO.puts Map.get(msg, :"@type") <> " received."
        case msg do
          %Object.UpdateAuthorizationState{authorization_state: auth_state} ->
            case auth_state do

              %Object.AuthorizationStateWaitTdlibParameters{} ->
                IO.puts "Query is: AuthorizationStateWaitTdlibParameters"
                :ignore # Handled by TDLib

              %Object.AuthorizationStateWaitEncryptionKey{} ->
                IO.puts "Query is: AuthorizationStateWaitEncryptionKey"
                :ignore # Handled by TDLib

              %Object.AuthorizationStateWaitPhoneNumber{} ->
                phone_number = IO.gets("Please provide phone number: ") |> String.trim
                query = %Method.SetAuthenticationPhoneNumber{
                  phone_number: phone_number,
                  allow_flash_call: false
                }
                IO.inspect query
                IO.puts "SetAuthenticationPhoneNumber is done"
                TDLib.transmit @session, query

              %Object.AuthorizationStateWaitCode{} ->
                code = IO.gets("Please authentication code: ") |> String.trim()
                query = %Method.CheckAuthenticationCode{code: code}
                IO.inspect query
                IO.puts "CheckAuthenticationCode is done"
                TDLib.transmit @session, query

              %Object.AuthorizationStateReady{} ->
                IO.puts "Authentification successful!"

                query = %Method.SendMessage{
                  chat_id: chatID Int,
                  input_message_content: %Object.InputMessageText {
                    text: %Object.FormattedText {
                      text: "سلام. این پیام برای تست از طریق Elixir برای شما ارسال شده است"
                    }
                  }
                }
                IO.inspect query
                TDLib.transmit @session, query
              _ -> # Ignore anyother state
                :ignore
            end

          _ -> # Ignore any other message (there are a lot of them!)
            :ignore
        end
    end

    loop()
  end

  def run_demo() do
    IO.puts @disclaimer
    start? = IO.gets("Start demo client? [y/n]") |> String.trim()
    unless start? in ["y", "Y"], do: System.halt()

    # Hide 'debug' logs
    # Logger.configure(level: :info)

    config = struct(
      TDLib.default_config(), %{api_id: "apiID", api_hash: "apiHash"}
    )

    # Open a new session
    {:ok, _pid} = TDLib.open(@session, self(), config)

    # Set TDLib (C++) verbosity to 0
    TDLib.transmit @session, "verbose 0"

    loop()
  end

end
2 Likes

تابع لوپتون رو با GenServers بنویسید کداتون تمیز تر و همینطور کارایی بهتری خواهد داشت و درکش راحتره و هینطور شرط مربوطه که اونجا قرار دادید هم پترنش می یاد بیرون فانکشن و در چندین فانکشن دیگه خلاصه می شه

کد دیتابیس هم باید بیرون در یک فانکشن جدا

اینا نظرات شخصی من بود
موفق باشید

3 Likes

متاسفانه گفتم که من تازه کار تازه کارم و هیچ کدوم از مواردی که گفتین رو متوجه نشدم. این مثال رو هم با زحمت زیاد از اینجا درآوردم و کدهامو توش جا دادم.

1 Like

درود عزیز. بنده هدفم جسارت به شما نبوده و در مورد مثال شما صحبت نکردم. به نظرم روش نوشتن شما در یک زبان فانکشنال یکمی درست نیست. البته اساتید در اینجا هستند که اطلاعات زیادی دارند.

ولی من اگر جای شما بودم یکمی کد هارو داینامیک تر می نوشتم.

مثلا تابع ذخیره در دیتابیس باید جدا بشه.
مثلا عملیات ریاضی باید جدا بشه
یک سری کد های چند بار مصرف جدا کنید

و دسته بندی مناسبی شکل بدید و از پترن ها بیشتر استفاده کنید .

و همینطور اگر در مورد GenServer تحقیق بفرمایید شاید منظور منو بهتر درک بکنید

این کتاب خوبه ازش استفاده بشه
16%20pm

1 Like