~fnux/telegram-tl-elixir

2a22570ebe09f011e5f36e0132dee42fd570328d — Timothée Floure 4 years ago 7730ebb master
Improve documentation (mostly examples) + bump to version 0.2.1
5 files changed, 112 insertions(+), 32 deletions(-)

M README.md
M lib/tl/binary.ex
M lib/tl/schema.ex
M mix.exs
M test/tl_test.exs
M README.md => README.md +14 -5
@@ 1,17 1,25 @@
# Telegram-TL

This library allows you to serialize and deserialize elements of the
[TL Language](https://core.telegram.org/mtproto/TL). It was originally
[TL Language](https://core.telegram.org/mtproto/TL). Take a look to the
documentation of the `TL` module for basic usage.

*Since it dynamically match maps against TL schemas, it's far from
being efficient and is pretty slow. However, it 'just works'
the way it is so let's say it's okay for now. A 'static' version
directly generated from TL schemas may come later.*

The package and its documentation are on
[hex.pm](https://hex.pm/packages/telegram_tl). It was originally
designed to be used by
[telegram-mt-elixir](https://github.com/Fnux/telegram-mt-elixir).

The package and its documentation are on
[hex.pm](https://hex.pm/packages/telegram_tl).


## Configuration

If no configuration is specified, the API layer 57 **[1]** will be used.
Although this library was only tested with the above layer version, you can
Although this library was only tested with layer versions 23 and 57, you can
specify a custom source in you `config.exs` :

```


@@ 21,4 29,5 @@ config :telegram_tl, tl_path: "/path/to/mtproto.json",

```

**[1]** : the last documented version is [API layer 23](https://core.telegram.org/schema?layer=23).
**[1]** : the last documented version (on [telegram.org](https://telegram.org/))
is [API layer 23](https://core.telegram.org/schema?layer=23).

M lib/tl/binary.ex => lib/tl/binary.ex +37 -10
@@ 1,10 1,19 @@
defmodule TL.Binary do
  @moduledoc """
    Helpers to work with binaries.
  A few methods extending erlang's `:binary` module.
  """

  @doc """
    Converts a (signed) integer to its binary representation.
  Converts a (signed) integer to its binary representation.

  ## Examples

  ```
  iex> TL.Binary.encode_signed 666
  <<2, 154>>
  iex> TL.Binary.encode_signed -666
  <<253, 102>>
  ```
  """
  def encode_signed(int) do
    size = (:math.log2(abs(int))) / 8.0 |> Float.ceil |> round


@@ 12,8 21,17 @@ defmodule TL.Binary do
  end

  @doc """
    Converts the binary representation (of a signed integer) to its decimal
    representation.
  Converts the binary representation (of a signed integer) to its decimal
  representation.

  ## Examples

  ```
  iex> TL.Binary.decode_signed <<2, 154>>
  666
  iex> TL.Binary.decode_signed <<253, 102>>
  -666
  ```
  """
  def decode_signed(binary) do
    binary_length = byte_size binary


@@ 22,7 40,14 @@ defmodule TL.Binary do
  end

  @doc """
    Split a binary at the given index.
  Split a binary at the given index.

  ## Example

  ```
  iex> TL.Binary.binary_split <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>, 3
  {<<1, 2, 3>>, <<4, 5, 6, 7, 8, 9, 10>>}
  ```
  """
  def binary_split(binary, index) do
    left = :binary.part binary, 0, index


@@ 36,10 61,11 @@ defmodule TL.Binary do
  @doc """
  Build an integer from a list of bit positions.

  Example:
  ## Example

  ```
  iex> build_integer_from_bits_list([0,1,3,10])
  1035
  iex> TL.Binary.build_integer_from_bits_list([0,1,3,10])
  1035 # = 2^0 + 2^1 + 2^3 + 2^10
  ```
  """
  def build_integer_from_bits_list([bit_index|tail], value) do


@@ 50,9 76,10 @@ defmodule TL.Binary do
  @doc """
  Reverse the endianness of a binary.

  Example:
  ## Example

  ```
  iex> reverse_endianness(<<1,2,3>>)
  iex> TL.Binary.reverse_endianness(<<1,2,3>>)
  <<3,2,1>>
  ```
  """

M lib/tl/schema.ex => lib/tl/schema.ex +59 -16
@@ 5,7 5,7 @@ defmodule TL.Schema do
  Parse and search the MTProto TL-schema (See
  [core.telegram.org/schema/mtproto](https://core.telegram.org/schema/mtproto))
  and the API TL-schema (See
  [core.telegram.org/schema](https://core.telegram.org/schema)).
  [core.telegram.org/schema](https://core.telegram.org/schema) for API layer 23).
  """

  @default_api_layer 57


@@ 59,7 59,14 @@ defmodule TL.Schema do
  ### Public

  @doc """
    Return the version of the API layer used.
  Return the version of the API layer used.

  ## Example

  ```
  iex> TL.Schema.api_layer_version
  57
  ```
  """
  def api_layer_version do
    config = Application.get_env(:telegram_tl, :api_layer)


@@ 67,14 74,31 @@ defmodule TL.Schema do
  end

  @doc """
    Returns the MTProto TL-schema.
  Returns the MTProto TL-schema.

  ## Example

  ```
  iex> TL.Schema.tl
  %{"constructors" => [%{"id" => "481674261", "params" => [],
    "predicate" => "vector", "type" => "Vector t"},
                       %{"id" => "85337187", "params" => ... %},
                       ...]}
    ```
  """
  def tl do
    GenServer.call @name, :tl
  end

  @doc """
    Returns the Telegram API TL-schema.
  Returns the Telegram API TL-schema.

  ## Example

  ```
  iex> TL.Schema.api
  %{"constructors" => [%{"id" => "-1132882121", "params" => [],
    "predicate" => "boolFalse", "type" => "Bool"}, ...], ...}
  """
  def api do
    GenServer.call @name, :api


@@ 83,32 107,51 @@ defmodule TL.Schema do
  @doc """
  Search descriptors in the schema(s)

    * `key`
    * `container`
    * `key` : field name
    * `value` : field value

  ## Examples

  ```
  iex> TL.Schema.search "method", "messages.setTyping"
  {:match,
  [%{"id" => "-1551737264", "method" => "messages.setTyping",
    "params" => [%{"name" => "peer", "type" => "InputPeer"},
     %{"name" => "action", "type" => "SendMessageAction"}], "type" => "Bool"}]}
  iex> TL.Schema.search "id", "-1551737264"
  {:match,
  [%{"id" => "-1551737264", "method" => "messages.setTyping",
    "params" => [%{"name" => "peer", "type" => "InputPeer"},
     %{"name" => "action", "type" => "SendMessageAction"}], "type" => "Bool"}]}
  iex> TL.Schema.search "method", "unknown_method"
  {:nothing, nil}
  iex> TL.Schema.search "method_or_predicate", "messages.sendMedia" # to search in both method and predicates
  {:match, ...}
  ```
  """
  def search(key, container) do
    {tl_match, tl_value} = search(key, container, :tl)
  def search(key, value) do
    {tl_match, tl_value} = search(key, value, :tl)
    # If a match was found in the tl schema, return it. If not, search in
    # the api schema.
    if tl_match == :match do
      {:match, tl_value}
    else
      {api_match, api_value} = search(key, container, :api)
      {api_match, api_value} = search(key, value, :api)
      if api_match == :match, do: {:match, api_value}, else: {:nothing, nil}
    end
  end

  @doc """
    Search the schema(s).
  Search in a specific schema.

    * `key` - example : `"predicate"`
    * `content` - example : `"ping"`
    * `schema` - schema to search into, either `:tl` or `:api`.
  * `key` - example : `"predicate"`
  * `value` - example : `"ping"`
  * `schema` - schema to search into, either `:tl` or `:api`.
  """
  def search(key, content, schema) do
  def search(key, value, schema) do
    case schema do
      :tl -> search_schema(key, content, tl())
      :api -> search_schema(key, content, api())
      :tl -> search_schema(key, value, tl())
      :api -> search_schema(key, value, api())
      _ -> {:err, nil}
    end
  end

M mix.exs => mix.exs +1 -1
@@ 3,7 3,7 @@ defmodule TL.Mixfile do

  def project do
    [app: :telegram_tl,
     version: "0.2.0-beta",
     version: "0.2.1",
     elixir: "~> 1.5",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,

M test/tl_test.exs => test/tl_test.exs +1 -0
@@ 1,6 1,7 @@
defmodule TLTest do
  use ExUnit.Case
  doctest TL
  doctest TL.Binary

  test "Build : ping" do
    ping = TL.build "ping", %{:ping_id => 666666}