Packages
ejabberd
25.8.0
26.4.0
26.3.0
26.2.0
26.1.0
25.10.0
25.8.0
25.7.0
25.4.0
25.3.0
24.12.0
24.10.0
24.7.0
24.6.0
24.2.6
23.10.0
23.4.0
23.1.0
22.10.0
22.5.0
21.12.0
21.7.0
21.4.0
21.1.0
20.12.0
20.7.0
20.4.0
20.3.0
20.2.0
20.1.0
19.9.1
19.9.0
19.8.0
19.5.0
19.2.0
18.12.1
18.12.0
18.6.0
18.4.0
18.3.0
18.1.0
17.11.0
17.9.0
17.6.0
17.3.0
17.1.0
16.12.0-beta1
16.9.0
16.8.0
16.6.2
16.6.1
16.6.0
16.4.1
16.4.0
16.3.0
16.2.0
16.1.0-beta1
Robust, Ubiquitous and Massively Scalable Messaging Platform (XMPP, MQTT, SIP Server)
Current section
Files
Jump to
Current section
Files
lib/ejabberd/config/attr.ex
defmodule Ejabberd.Config.Attr do
@moduledoc """
Module used to work with the attributes parsed from
an elixir block (do...end).
Contains functions for extracting attrs from a block
and validation.
"""
@type attr :: {atom(), any()}
@attr_supported [
active:
[type: :boolean, default: true],
git:
[type: :string, default: ""],
name:
[type: :string, default: ""],
opts:
[type: :list, default: []],
dependency:
[type: :list, default: []]
]
@doc """
Takes a block with annotations and extracts the list
of attributes.
"""
@spec extract_attrs_from_block_with_defaults(any()) :: [attr]
def extract_attrs_from_block_with_defaults(block) do
block
|> extract_attrs_from_block
|> put_into_list_if_not_already
|> insert_default_attrs_if_missing
end
@doc """
Takes an attribute or a list of attrs and validate them.
Returns a {:ok, attr} or {:error, attr, cause} for each of the attributes.
"""
@spec validate([attr]) :: [{:ok, attr}] | [{:error, attr, atom()}]
def validate(attrs) when is_list(attrs), do: Enum.map(attrs, &valid_attr?/1)
def validate(attr), do: validate([attr])
@doc """
Returns the type of an attribute, given its name.
"""
@spec get_type_for_attr(atom()) :: atom()
def get_type_for_attr(attr_name) do
@attr_supported
|> Keyword.get(attr_name)
|> Keyword.get(:type)
end
@doc """
Returns the default value for an attribute, given its name.
"""
@spec get_default_for_attr(atom()) :: any()
def get_default_for_attr(attr_name) do
@attr_supported
|> Keyword.get(attr_name)
|> Keyword.get(:default)
end
# Private API
# Given an elixir block (do...end) returns a list with the annotations
# or a single annotation.
@spec extract_attrs_from_block(any()) :: [attr] | attr
defp extract_attrs_from_block({:__block__, [], attrs}), do: Enum.map(attrs, &extract_attrs_from_block/1)
defp extract_attrs_from_block({:@, _, [attrs]}), do: extract_attrs_from_block(attrs)
defp extract_attrs_from_block({attr_name, _, [value]}), do: {attr_name, value}
defp extract_attrs_from_block(nil), do: []
# In case extract_attrs_from_block returns a single attribute,
# then put it into a list. (Ensures attrs are always into a list).
@spec put_into_list_if_not_already([attr] | attr) :: [attr]
defp put_into_list_if_not_already(attrs) when is_list(attrs), do: attrs
defp put_into_list_if_not_already(attr), do: [attr]
# Given a list of attributes, it inserts the missing attribute with their
# default value.
@spec insert_default_attrs_if_missing([attr]) :: [attr]
defp insert_default_attrs_if_missing(attrs) do
Enum.reduce @attr_supported, attrs, fn({attr_name, _}, acc) ->
case Keyword.has_key?(acc, attr_name) do
true -> acc
false -> Keyword.put(acc, attr_name, get_default_for_attr(attr_name))
end
end
end
# Given an attribute, validates it and return a tuple with
# {:ok, attr} or {:error, attr, cause}
@spec valid_attr?(attr) :: {:ok, attr} | {:error, attr, atom()}
defp valid_attr?({attr_name, param} = attr) do
case Keyword.get(@attr_supported, attr_name) do
nil -> {:error, attr, :attr_not_supported}
[{:type, param_type} | _] -> case is_of_type?(param, param_type) do
true -> {:ok, attr}
false -> {:error, attr, :type_not_supported}
end
end
end
# Given an attribute value and a type, it returns a true
# if the value its of the type specified, false otherwise.
# Usefoul for checking if an attr value respects the type
# specified for the annotation.
@spec is_of_type?(any(), atom()) :: boolean()
defp is_of_type?(param, type) when type == :boolean and is_boolean(param), do: true
defp is_of_type?(param, type) when type == :string and is_bitstring(param), do: true
defp is_of_type?(param, type) when type == :list and is_list(param), do: true
defp is_of_type?(param, type) when type == :atom and is_atom(param), do: true
defp is_of_type?(_param, type) when type == :any, do: true
defp is_of_type?(_, _), do: false
end