1 |
|
%%%---------------------------------------------------------------------- |
2 |
|
%%% File : ejabberd_app.erl |
3 |
|
%%% Author : Alexey Shchepin <alexey@process-one.net> |
4 |
|
%%% Purpose : ejabberd's application callback module |
5 |
|
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net> |
6 |
|
%%% |
7 |
|
%%% |
8 |
|
%%% ejabberd, Copyright (C) 2002-2011 ProcessOne |
9 |
|
%%% |
10 |
|
%%% This program is free software; you can redistribute it and/or |
11 |
|
%%% modify it under the terms of the GNU General Public License as |
12 |
|
%%% published by the Free Software Foundation; either version 2 of the |
13 |
|
%%% License, or (at your option) any later version. |
14 |
|
%%% |
15 |
|
%%% This program is distributed in the hope that it will be useful, |
16 |
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 |
|
%%% General Public License for more details. |
19 |
|
%%% |
20 |
|
%%% You should have received a copy of the GNU General Public License |
21 |
|
%%% along with this program; if not, write to the Free Software |
22 |
|
%%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 |
|
%%% |
24 |
|
%%%---------------------------------------------------------------------- |
25 |
|
|
26 |
|
-module(ejabberd_app). |
27 |
|
-author('alexey@process-one.net'). |
28 |
|
|
29 |
|
-behaviour(application). |
30 |
|
|
31 |
|
-export([start/2, prep_stop/1, stop/1]). |
32 |
|
|
33 |
|
-ignore_xref([prep_stop/1]). |
34 |
|
|
35 |
|
-include("mongoose.hrl"). |
36 |
|
|
37 |
|
|
38 |
|
%%% |
39 |
|
%%% Application API |
40 |
|
%%% |
41 |
|
|
42 |
|
start(normal, _Args) -> |
43 |
80 |
mongoose_fips:notify(), |
44 |
80 |
write_pid_file(), |
45 |
80 |
update_status_file(starting), |
46 |
80 |
db_init(), |
47 |
80 |
application:start(cache_tab), |
48 |
|
|
49 |
80 |
mongoose_graphql:init(), |
50 |
80 |
translate:start(), |
51 |
80 |
ejabberd_node_id:start(), |
52 |
80 |
ejabberd_ctl:init(), |
53 |
80 |
ejabberd_commands:init(), |
54 |
80 |
mongoose_commands:init(), |
55 |
80 |
mongoose_service:start(), |
56 |
80 |
mongoose_config:start(), |
57 |
80 |
mongoose_router:start(), |
58 |
80 |
mongoose_logs:set_global_loglevel(mongoose_config:get_opt(loglevel)), |
59 |
80 |
mongoose_deprecations:start(), |
60 |
80 |
{ok, _} = Sup = ejabberd_sup:start_link(), |
61 |
80 |
mongoose_domain_api:init(), |
62 |
80 |
mongoose_wpool:ensure_started(), |
63 |
80 |
mongoose_wpool:start_configured_pools(), |
64 |
|
%% ejabberd_sm is started separately because it may use one of the outgoing_pools |
65 |
|
%% but some outgoing_pools should be started only with ejabberd_sup already running |
66 |
80 |
ejabberd_sm:start(), |
67 |
80 |
ejabberd_auth:start(), |
68 |
80 |
mongoose_cluster_id:start(), |
69 |
80 |
start_services(), |
70 |
80 |
mongoose_modules:start(), |
71 |
80 |
service_mongoose_system_metrics:verify_if_configured(), |
72 |
80 |
mongoose_metrics:init(), |
73 |
80 |
ejabberd_listener:start_listeners(), |
74 |
80 |
ejabberd_admin:start(), |
75 |
80 |
update_status_file(started), |
76 |
80 |
?LOG_NOTICE(#{what => mongooseim_node_started, version => ?MONGOOSE_VERSION, node => node()}), |
77 |
80 |
Sup; |
78 |
|
start(_, _) -> |
79 |
:-( |
{error, badarg}. |
80 |
|
|
81 |
|
%% @doc Prepare the application for termination. |
82 |
|
%% This function is called when an application is about to be stopped, |
83 |
|
%% before shutting down the processes of the application. |
84 |
|
prep_stop(State) -> |
85 |
80 |
mongoose_deprecations:stop(), |
86 |
80 |
ejabberd_listener:stop_listeners(), |
87 |
80 |
mongoose_modules:stop(), |
88 |
80 |
stop_services(), |
89 |
80 |
broadcast_c2s_shutdown(), |
90 |
80 |
mongoose_wpool:stop(), |
91 |
80 |
mongoose_metrics:remove_all_metrics(), |
92 |
80 |
mongoose_config:stop(), |
93 |
80 |
State. |
94 |
|
|
95 |
|
%% All the processes were killed when this function is called |
96 |
|
stop(_State) -> |
97 |
80 |
?LOG_NOTICE(#{what => mongooseim_node_stopped, version => ?MONGOOSE_VERSION, node => node()}), |
98 |
80 |
delete_pid_file(), |
99 |
80 |
update_status_file(stopped), |
100 |
|
%%ejabberd_debug:stop(), |
101 |
80 |
ok. |
102 |
|
|
103 |
|
|
104 |
|
%%% |
105 |
|
%%% Internal functions |
106 |
|
%%% |
107 |
|
db_init() -> |
108 |
80 |
case mnesia:system_info(extra_db_nodes) of |
109 |
|
[] -> |
110 |
52 |
application:stop(mnesia), |
111 |
52 |
mnesia:create_schema([node()]), |
112 |
52 |
application:start(mnesia, permanent); |
113 |
|
_ -> |
114 |
28 |
ok |
115 |
|
end, |
116 |
80 |
mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity). |
117 |
|
|
118 |
|
-spec start_services() -> ok. |
119 |
|
start_services() -> |
120 |
80 |
lists:foreach( |
121 |
160 |
fun({Service, Opts}) -> mongoose_service:ensure_loaded(Service, Opts) end, |
122 |
|
mongoose_config:get_opt(services, []) |
123 |
|
). |
124 |
|
|
125 |
|
-spec stop_services() -> ok. |
126 |
|
stop_services() -> |
127 |
80 |
lists:foreach( |
128 |
159 |
fun({Service, _Options}) -> mongoose_service:stop_service(Service) end, |
129 |
|
mongoose_service:loaded_services_with_opts() |
130 |
|
). |
131 |
|
|
132 |
|
-spec broadcast_c2s_shutdown() -> 'ok'. |
133 |
|
broadcast_c2s_shutdown() -> |
134 |
80 |
Children = supervisor:which_children(ejabberd_c2s_sup), |
135 |
80 |
lists:foreach( |
136 |
|
fun({_, C2SPid, _, _}) -> |
137 |
1 |
C2SPid ! system_shutdown |
138 |
|
end, Children), |
139 |
80 |
mongoose_lib:wait_until( |
140 |
|
fun() -> |
141 |
81 |
Res = supervisor:count_children(ejabberd_c2s_sup), |
142 |
81 |
proplists:get_value(active, Res) |
143 |
|
end, 0). |
144 |
|
|
145 |
|
%%% |
146 |
|
%%% PID file |
147 |
|
%%% |
148 |
|
|
149 |
|
-spec write_pid_file() -> 'ok' | {'error', atom()}. |
150 |
|
write_pid_file() -> |
151 |
80 |
case ejabberd:get_pid_file() of |
152 |
|
false -> |
153 |
:-( |
ok; |
154 |
|
PidFilename -> |
155 |
80 |
write_pid_file(os:getpid(), PidFilename) |
156 |
|
end. |
157 |
|
|
158 |
|
-spec write_pid_file(Pid :: string(), |
159 |
|
PidFilename :: nonempty_string() |
160 |
|
) -> 'ok' | {'error', atom()}. |
161 |
|
write_pid_file(Pid, PidFilename) -> |
162 |
80 |
case file:open(PidFilename, [write]) of |
163 |
|
{ok, Fd} -> |
164 |
80 |
io:format(Fd, "~s~n", [Pid]), |
165 |
80 |
file:close(Fd); |
166 |
|
{error, Reason} -> |
167 |
:-( |
?LOG_ERROR(#{what => cannot_write_to_pid_file, |
168 |
:-( |
pid_file => PidFilename, reason => Reason}), |
169 |
:-( |
throw({cannot_write_pid_file, PidFilename, Reason}) |
170 |
|
end. |
171 |
|
|
172 |
|
update_status_file(Status) -> |
173 |
240 |
case ejabberd:get_status_file() of |
174 |
|
false -> |
175 |
:-( |
ok; |
176 |
|
StatusFilename -> |
177 |
240 |
file:write_file(StatusFilename, atom_to_list(Status)) |
178 |
|
end. |
179 |
|
|
180 |
|
-spec delete_pid_file() -> 'ok' | {'error', atom()}. |
181 |
|
delete_pid_file() -> |
182 |
80 |
case ejabberd:get_pid_file() of |
183 |
|
false -> |
184 |
:-( |
ok; |
185 |
|
PidFilename -> |
186 |
80 |
file:delete(PidFilename) |
187 |
|
end. |