Current section
Files
Jump to
Current section
Files
lib/aerospike/protocol/info.ex
defmodule Aerospike.Protocol.Info do
@moduledoc false
alias Aerospike.Protocol.Message
@doc """
Encodes an info request from a list of command strings.
Commands are joined with newlines and a trailing newline is appended.
The result is wrapped in a Message with type 1 (info).
## Examples
iex> Aerospike.Protocol.Info.encode_request(["namespaces"])
<<2, 1, 0, 0, 0, 0, 0, 11, "namespaces\\n">>
iex> Aerospike.Protocol.Info.encode_request(["node", "build"])
<<2, 1, 0, 0, 0, 0, 0, 11, "node\\nbuild\\n">>
iex> Aerospike.Protocol.Info.encode_request([])
<<2, 1, 0, 0, 0, 0, 0, 0>>
"""
@spec encode_request([String.t()]) :: binary()
def encode_request([]), do: Message.encode_info("")
def encode_request(commands) when is_list(commands) do
payload = Enum.join(commands, "\n") <> "\n"
Message.encode_info(payload)
end
@doc """
Decodes an info response body into a map of key-value pairs.
The response format is newline-separated entries where each entry is either:
- `key\\tvalue` (tab-separated key and value)
- `key` (key only, value is empty string)
## Examples
iex> Aerospike.Protocol.Info.decode_response("namespaces\\ttest;memory\\n")
{:ok, %{"namespaces" => "test;memory"}}
iex> Aerospike.Protocol.Info.decode_response("node\\tBB9050011AC4202\\nbuild\\t7.0.0.0\\n")
{:ok, %{"node" => "BB9050011AC4202", "build" => "7.0.0.0"}}
iex> Aerospike.Protocol.Info.decode_response("status\\n")
{:ok, %{"status" => ""}}
iex> Aerospike.Protocol.Info.decode_response("")
{:ok, %{}}
"""
@spec decode_response(binary()) :: {:ok, map()}
def decode_response(body) when is_binary(body) do
result =
body
|> String.trim_trailing("\n")
|> case do
"" -> %{}
trimmed -> parse_entries(trimmed)
end
{:ok, result}
end
defp parse_entries(data) do
data
|> String.split("\n")
|> Enum.reduce(%{}, fn entry, acc ->
case String.split(entry, "\t", parts: 2) do
[key, value] -> Map.put(acc, key, value)
[key] -> Map.put(acc, key, "")
end
end)
end
@doc """
Decodes a complete info response message (header + body).
First decodes the message envelope, validates it's an info message (type 1),
then parses the body.
## Examples
iex> msg = <<2, 1, 0, 0, 0, 0, 0, 16, "namespaces\\ttest\\n">>
iex> Aerospike.Protocol.Info.decode_message(msg)
{:ok, %{"namespaces" => "test"}}
"""
@spec decode_message(binary()) ::
{:ok, map()} | {:error, :incomplete_header | :incomplete_body | :invalid_message_type}
def decode_message(data) do
with {:ok, {_version, type, body}} <- Message.decode(data) do
if type == Message.type_info() do
decode_response(body)
else
{:error, :invalid_message_type}
end
end
end
end