Packages
smppex
2.2.7
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/pp.ex
defmodule SMPPEX.Pdu.PP do
@moduledoc """
Module for colored pretty printing Pdu structs.
"""
alias IO.ANSI, as: C
alias SMPPEX.Pdu
alias SMPPEX.Protocol.TlvFormat
@pad ""
@indent " "
@field_inspect_limit 999_999
@spec format(pdu :: Pdu.t(), indent :: String.t(), pad :: String.t()) :: iolist
@doc """
Forms an iolist containing colored Pdu dump.
`indent` is the string prepended to each line of the dump ("#{@indent}" by default).
`pad` is the string prepended to nested lines of the dump together with `indent`.
The default is "#{@pad}".
## Example
iex> pdu = SMPPEX.Pdu.Factory.submit_sm({"from", 1, 1}, {"to", 1, 1}, "hello")
Then `pdu |> SMPPEX.Pdu.PP.format |> IO.puts` will print:
```
pdu: submit_sm
command_id: 4
command_status: 0 (ok)
sequence_number: 0
mandatory fields:
dest_addr_npi: 1
dest_addr_ton: 1
destination_addr: "to"
registered_delivery: 0
short_message: "hello"
source_addr: "from"
source_addr_npi: 1
source_addr_ton: 1
optional fields: []
```
"""
def format(pdu, indent \\ @indent, pad \\ @pad) do
[
"\n",
C.reset(),
pdu
|> pdu_lines
|> Enum.map(fn [section_head | section_lines] ->
[
pad,
section_head,
"\n",
section_lines
|> Enum.map(fn line ->
[pad, indent, line, "\n"]
end)
]
end)
]
end
defp pdu_lines(pdu) do
[
header(pdu),
mandatory_fields(pdu),
optional_fields(pdu)
]
end
defp header(pdu) do
[
name(pdu),
[pp_field_name("command_id"), ": ", pdu |> Pdu.command_id() |> inspect |> pp_val],
[pp_field_name("command_status"), ": ", pdu |> Pdu.command_status() |> pp_command_status],
[pp_field_name("sequence_number"), ": ", pdu |> Pdu.sequence_number() |> inspect |> pp_val]
]
end
defp name(pdu) do
["pdu: ", pp_command_name(pdu)]
end
defp mandatory_fields(pdu) do
[["mandatory fields:", pdu |> Pdu.mandatory_fields() |> pp_empty_list]] ++
(pdu |> Pdu.mandatory_fields() |> Map.to_list() |> pp_fields)
end
defp optional_fields(pdu) do
[["optional fields:", pdu |> Pdu.optional_fields() |> pp_empty_list]] ++
(pdu |> Pdu.optional_fields() |> Map.to_list() |> name_known_tlvs |> pp_fields)
end
defp name_known_tlvs(_, res \\ [])
defp name_known_tlvs([], res), do: Enum.reverse(res)
defp name_known_tlvs([{k, v} | left], res) do
case TlvFormat.name_by_id(k) do
{:ok, name} -> name_known_tlvs(left, [{name, v} | res])
:unknown -> name_known_tlvs(left, [{k, v} | res])
end
end
defp pp_empty_list(map) when map == %{}, do: " []"
defp pp_empty_list(_), do: ""
defp pp_command_status(status) do
case status do
0 -> [C.green(), C.bright(), "0 (ok)", C.reset()]
_ -> [C.red(), C.bright(), "#{status} (error)", C.reset()]
end
end
defp pp_field_name(field_name) do
[C.green(), field_name, C.reset()]
end
defp pp_val(str) do
[C.yellow(), str, C.reset()]
end
defp pp_fields(fields) do
fields
|> Enum.sort()
|> Enum.map(fn {key, val} ->
[
key |> to_string |> pp_field_name,
": ",
val |> inspect(limit: @field_inspect_limit) |> pp_val
]
end)
end
defp pp_command_name(pdu) do
name = pdu |> Pdu.command_name() |> to_string
[C.cyan(), C.bright(), name, C.reset()]
end
end