defmodule Kadabra.Frame.Settings do @moduledoc false defstruct [:settings, ack: false] alias Kadabra.Connection alias Kadabra.Frame.Flags @type t :: %__MODULE__{ ack: boolean, settings: Connection.Settings.t() | nil } @spec ack :: t def ack do %__MODULE__{ack: true, settings: nil} end def new(%{payload: "", flags: flags}) do %__MODULE__{settings: nil, ack: Flags.ack?(flags)} end def new(%{payload: p, flags: flags}) do s_list = parse_settings(p) case put_settings(%Connection.Settings{}, s_list) do {:ok, settings} -> %__MODULE__{settings: settings, ack: Flags.ack?(flags)} {:error, code, _settings} -> {:error, code} end end @spec ack?(0 | 1) :: boolean def ack?(1), do: true def ack?(0), do: false @spec parse_settings(bitstring) :: [{char, non_neg_integer}, ...] | [] def parse_settings(<<>>), do: [] def parse_settings(bin) do <> = bin [{identifier, value}] ++ parse_settings(rest) end def put_settings(settings, []), do: {:ok, settings} def put_settings(settings, [{ident, value} | rest]) do case Connection.Settings.put(settings, ident, value) do {:ok, settings} -> put_settings(settings, rest) {:error, code, settings} -> {:error, code, settings} end end end defimpl Kadabra.Encodable, for: Kadabra.Frame.Settings do alias Kadabra.{Encodable, Frame} @settings 0x4 def to_bin(frame) do ack = if frame.ack, do: 0x1, else: 0x0 case frame.settings do nil -> Frame.binary_frame(@settings, ack, 0x0, <<>>) settings -> p = settings |> Encodable.to_bin() Frame.binary_frame(@settings, ack, 0x0, p) end end end