Packages
smppex
2.3.0
3.3.0
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
retired
3.1.0
retired
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.4.0
2.3.3
2.3.2
2.3.1
2.3.0
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.0
2.0.1
2.0.0
1.0.1
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
SMPP 3.4 protocol and framework implemented in Elixir
Current section
Files
Jump to
Current section
Files
lib/smppex/pdu/oserl.ex
defmodule SMPPEX.Pdu.Oserl do
@moduledoc """
Module for converting SMPPEX Pdu structs to format used by [Oserl](https://github.com/iamaleksey/oserl) library.
"""
alias SMPPEX.Pdu
alias SMPPEX.Pdu.Oserl, as: OserlPdu
alias SMPPEX.Pdu.NetworkErrorCode
alias SMPPEX.Protocol.TlvFormat
require Record
Record.defrecord(:network_error_code, type: 0, error: 0)
@type t :: {
command_id :: non_neg_integer,
command_status :: non_neg_integer,
sequence_number :: non_neg_integer,
[{field_name :: atom, field_value :: term}]
}
@spec to(pdu :: Pdu.t()) :: OserlPdu.t()
@doc """
Converts SMPPEX Pdu to Oserl format.
Unknown optional values are ignored, since Oserl stores them by symbolic names.
"""
def to(pdu) do
{
Pdu.command_id(pdu),
Pdu.command_status(pdu),
Pdu.sequence_number(pdu),
fields_to_list(pdu)
}
end
@spec from(oserl_pdu :: OserlPdu.t()) :: Pdu.t()
@doc """
Converts PDU from Oserl format to SMPPEX Pdu.
"""
def from({command_id, command_status, sequence_number, field_list} = _oserl_pdu) do
converted_field_list =
field_list
|> Enum.map(&preprocess/1)
|> Enum.reject(&is_nil/1)
|> Enum.map(&list_to_string/1)
{mandatory, optional} = list_to_fields(converted_field_list, %{}, %{})
Pdu.new(
{command_id, command_status, sequence_number},
mandatory,
optional
)
end
defp fields_to_list(pdu) do
(pdu |> Pdu.mandatory_fields() |> Map.to_list() |> Enum.map(&string_to_list(&1))) ++
(pdu |> Pdu.optional_fields() |> Map.to_list() |> ids_to_names)
end
defp list_to_fields([], mandatory, optional), do: {mandatory, optional}
defp list_to_fields([{name, value} | list], mandatory, optional) do
case kind(name) do
{:optional, id} -> list_to_fields(list, mandatory, Map.put(optional, id, value))
:mandatory -> list_to_fields(list, Map.put(mandatory, name, value), optional)
end
end
defp kind(id) when is_integer(id), do: {:optional, id}
defp kind(name) when is_atom(name) do
case TlvFormat.id_by_name(name) do
{:ok, id} -> {:optional, id}
:unknown -> :mandatory
end
end
defp ids_to_names(by_ids, by_names \\ [])
defp ids_to_names([], by_names), do: by_names
defp ids_to_names([{name, value} | by_ids], by_names) when is_atom(name),
do: ids_to_names(by_ids, [{name, value} | by_names])
defp ids_to_names([{id, value} | by_ids], by_names) when is_integer(id) do
case TlvFormat.name_by_id(id) do
{:ok, name} -> ids_to_names(by_ids, [string_to_list({name, value}) | by_names])
:unknown -> ids_to_names(by_ids, [{id, value} | by_names])
end
end
defp list_to_string({key, value}) when is_list(value), do: {key, :erlang.list_to_binary(value)}
defp list_to_string({key, value}), do: {key, value}
defp string_to_list({key, value}) when is_binary(value),
do: {key, :erlang.binary_to_list(value)}
defp string_to_list({key, value}), do: {key, value}
defp preprocess({:network_error_code, network_error_code(type: type_code, error: error_code)}),
do: {:network_error_code, NetworkErrorCode.encode(type_code, error_code)}
defp preprocess({:network_error_code, []}), do: nil
defp preprocess({key, value}), do: {key, value}
end