1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
defmodule Ejabberd.Config do
@moduledoc """
Base module for configuration file.
Imports macros for the config DSL and contains functions
for working/starting the configuration parsed.
"""
alias Ejabberd.Config.EjabberdModule
alias Ejabberd.Config.Attr
alias Ejabberd.Config.EjabberdLogger
defmacro __using__(_opts) do
quote do
import Ejabberd.Config, only: :macros
import Ejabberd.Logger
@before_compile Ejabberd.Config
end
end
# Validate the modules parsed and log validation errors at compile time.
# Could be also possible to interrupt the compilation&execution by throwing
# an exception if necessary.
def __before_compile__(_env) do
get_modules_parsed_in_order()
|> EjabberdModule.validate
|> EjabberdLogger.log_errors
end
@doc """
Given the path of the config file, it evaluates it.
"""
def init(file_path, force \\ false) do
init_already_executed = Ejabberd.Config.Store.get(:module_name) != []
case force do
true ->
Ejabberd.Config.Store.stop
Ejabberd.Config.Store.start_link
do_init(file_path)
false ->
if not init_already_executed, do: do_init(file_path)
end
end
@doc """
Returns a list with all the opts, formatted for ejabberd.
"""
def get_ejabberd_opts do
get_general_opts()
|> Map.put(:modules, get_modules_parsed_in_order())
|> Map.put(:listeners, get_listeners_parsed_in_order())
|> Ejabberd.Config.OptsFormatter.format_opts_for_ejabberd
end
@doc """
Register the hooks defined inside the elixir config file.
"""
def start_hooks do
get_hooks_parsed_in_order()
|> Enum.each(&Ejabberd.Config.EjabberdHook.start/1)
end
###
### MACROS
###
defmacro listen(module, do: block) do
attrs = Attr.extract_attrs_from_block_with_defaults(block)
quote do
Ejabberd.Config.Store.put(:listeners, %EjabberdModule{
module: unquote(module),
attrs: unquote(attrs)
})
end
end
defmacro module(module, do: block) do
attrs = Attr.extract_attrs_from_block_with_defaults(block)
quote do
Ejabberd.Config.Store.put(:modules, %EjabberdModule{
module: unquote(module),
attrs: unquote(attrs)
})
end
end
defmacro hook(hook_name, opts, fun) do
quote do
Ejabberd.Config.Store.put(:hooks, %Ejabberd.Config.EjabberdHook{
hook: unquote(hook_name),
opts: unquote(opts),
fun: unquote(fun)
})
end
end
# Private API
defp do_init(file_path) do
# File evaluation
Code.eval_file(file_path) |> extract_and_store_module_name()
# Getting start/0 config
Ejabberd.Config.Store.get(:module_name)
|> case do
nil -> IO.puts "[ ERR ] Configuration module not found."
[module] -> call_start_func_and_store_data(module)
end
# Fetching git modules and install them
get_modules_parsed_in_order()
|> EjabberdModule.fetch_git_repos
end
# Returns the modules from the store
defp get_modules_parsed_in_order,
do: Ejabberd.Config.Store.get(:modules) |> Enum.reverse
# Returns the listeners from the store
defp get_listeners_parsed_in_order,
do: Ejabberd.Config.Store.get(:listeners) |> Enum.reverse
defp get_hooks_parsed_in_order,
do: Ejabberd.Config.Store.get(:hooks) |> Enum.reverse
# Returns the general config options
defp get_general_opts,
do: Ejabberd.Config.Store.get(:general) |> List.first
# Gets the general ejabberd options calling
# the start/0 function and stores them.
defp call_start_func_and_store_data(module) do
opts = apply(module, :start, [])
Ejabberd.Config.Store.put(:general, opts)
end
# Stores the configuration module name
defp extract_and_store_module_name({{:module, mod, _bytes, _}, _}) do
Ejabberd.Config.Store.put(:module_name, mod)
end
end
|