access = {none,none,none,none,none} :: {atom(), atom(), atom(), atom(), atom()},
jid = #jid{} :: jid(),
config = #config{} :: config(),
- users = #{} :: map(),
- subscribers = #{} :: map(),
- subscriber_nicks = #{} :: map(),
+ users = #{} :: users(),
+ subscribers = #{} :: subscribers(),
+ subscriber_nicks = #{} :: subscriber_nicks(),
last_voice_request_time = treap:empty() :: treap:treap(),
- robots = #{} :: map(),
- nicks = #{} :: map(),
- affiliations = #{} :: map(),
+ robots = #{} :: robots(),
+ nicks = #{} :: nicks(),
+ affiliations = #{} :: affiliations(),
history = #lqueue{} :: lqueue(),
subject = [] :: [text()],
subject_author = <<"">> :: binary(),
room_shaper = none :: ejabberd_shaper:shaper(),
room_queue :: p1_queue:queue() | undefined
}).
+
+-type users() :: #{ljid() => #user{}}.
+-type robots() :: #{jid() => {binary(), stanza()}}.
+-type nicks() :: #{binary() => [ljid()]}.
+-type affiliations() :: #{ljid() => affiliation() | {affiliation(), binary()}}.
+-type subscribers() :: #{ljid() => #subscriber{}}.
+-type subscriber_nicks() :: #{binary() => [ljid()]}.
-define(SALT_LENGTH, 16).
--record(state, {host_modules = #{} :: map()}).
+-record(state, {host_modules = #{} :: host_modules()}).
+-type host_modules() :: #{binary => [module()]}.
-type password() :: binary() | #scram{}.
-type digest_fun() :: fun((binary()) -> binary()).
-export_type([password/0]).
%%%----------------------------------------------------------------------
%%% Cache stuff
%%%----------------------------------------------------------------------
--spec init_cache(map()) -> ok.
+-spec init_cache(host_modules()) -> ok.
init_cache(HostModules) ->
CacheOpts = cache_opts(),
{True, False} = use_cache(HostModules),
LifeTime = ejabberd_option:auth_cache_life_time(),
[{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}].
--spec use_cache(map()) -> {True :: [module()], False :: [module()]}.
+-spec use_cache(host_modules()) -> {True :: [module()], False :: [module()]}.
use_cache(HostModules) ->
{Enabled, Disabled} =
maps:fold(
{exception, term(), term(), term()}.
-type error_return() :: {error, econf:error_reason(), term()} |
{error, error_reason()}.
+-type host_config() :: #{{atom(), binary() | global} => term()}.
-callback opt_type(atom()) -> econf:validator().
-callback options() -> [atom() | {atom(), term()}].
end,
Err.
--spec set_host_config([{atom(), term()}]) -> {ok, map()} | error_return().
+-spec set_host_config([{atom(), term()}]) -> {ok, host_config()} | error_return().
set_host_config(Opts) ->
Map1 = lists:foldl(
fun({Opt, Val}, M) when Opt /= host_config,
_ -> {ok, Map3}
end.
--spec apply_defaults(ets:tid(), [binary()], map()) -> ok.
+-spec apply_defaults(ets:tid(), [binary()], host_config()) -> ok.
apply_defaults(Tab, Hosts, Map) ->
Defaults1 = defaults(),
apply_defaults(Tab, global, Map, Defaults1),
apply_defaults(Tab, Host, Map, Defaults2)
end, Hosts).
--spec apply_defaults(ets:tid(), global | binary(), map(),
+-spec apply_defaults(ets:tid(), global | binary(),
+ host_config(),
[atom() | {atom(), term()}]) -> ok.
apply_defaults(Tab, Host, Map, Defaults) ->
lists:foreach(
-record(state, {connection :: pid() | undefined,
num :: pos_integer(),
- subscriptions = #{} :: map(),
+ subscriptions = #{} :: subscriptions(),
pending_q :: p1_queue:queue()}).
+-type subscriptions() :: #{binary() => [pid()]}.
-type error_reason() :: binary() | timeout | disconnected | overloaded.
-type redis_error() :: {error, error_reason()}.
-type redis_reply() :: undefined | binary() | [binary()].
name :: pid() | atom()}).
-type state() :: #state{}.
-type proc_stat() :: #proc_stat{}.
+-type app_pids() :: #{pid() => atom()}.
%%%===================================================================
%%% API
end,
lists:foreach(fun erlang:garbage_collect/1, Procs).
--spec get_app_pids() -> map().
+-spec get_app_pids() -> app_pids().
get_app_pids() ->
try application:info() of
Info ->
#{}
end.
--spec overloaded_procs(map(), [pid()])
+-spec overloaded_procs(app_pids(), [pid()])
-> {non_neg_integer(), non_neg_integer(), dict:dict(), [proc_stat()]}.
overloaded_procs(AppPids, AllProcs) ->
lists:foldl(
end
end, {0, 0, dict:new(), []}, AllProcs).
--spec proc_stat(pid(), map()) -> proc_stat() | undefined.
+-spec proc_stat(pid(), app_pids()) -> proc_stat() | undefined.
proc_stat(Pid, AppPids) ->
case process_info(Pid, [message_queue_len,
memory,
-include("xmpp.hrl").
-include_lib("kernel/include/file.hrl").
+-type distance_cache() :: #{{string(), string()} => non_neg_integer()}.
+
%%%===================================================================
%%% API
%%%===================================================================
{MS, S, erlang:unique_integer([positive, monotonic]) rem 1000000}.
%% Levenshtein distance
--spec ld(string(), string(), map()) -> {non_neg_integer(), map()}.
+-spec ld(string(), string(), distance_cache()) -> {non_neg_integer(), distance_cache()}.
ld([] = S, T, Cache) ->
{length(T), maps:put({S, T}, length(T), Cache)};
ld(S, [] = T, Cache) ->
-include("logger.hrl").
-include("pubsub.hrl").
+-type avatar_id_meta() :: #{avatar_meta => {binary(), avatar_meta()}}.
-opaque convert_rule() :: {default | eimp:img_type(), eimp:img_type()}.
-export_type([convert_rule/0]).
end
end.
--spec set_vcard_avatar(jid(), vcard_photo() | undefined, map()) -> ok.
+-spec set_vcard_avatar(jid(), vcard_photo() | undefined, avatar_id_meta()) -> ok.
set_vcard_avatar(JID, VCardPhoto, Meta) ->
case get_vcard(JID) of
{ok, #vcard_temp{photo = VCardPhoto}} ->
-define(CSI_QUEUE_MAX, 100).
-type csi_type() :: presence | chatstate | {pep, binary()}.
--type csi_queue() :: {non_neg_integer(), map()}.
+-type csi_queue() :: {non_neg_integer(), #{csi_key() => csi_element()}}.
-type csi_timestamp() :: {non_neg_integer(), erlang:timestamp()}.
-type csi_key() :: {ljid(), csi_type()}.
-type csi_element() :: {csi_timestamp(), stanza()}.
service_url :: binary() | undefined,
thumbnail :: boolean(),
custom_headers :: [{binary(), binary()}],
- slots = #{} :: map(),
+ slots = #{} :: slots(),
external_secret :: binary()}).
-record(media_info,
-type state() :: #state{}.
-type slot() :: [binary(), ...].
+-type slots() :: #{slot() => {pos_integer(), reference()}}.
-type media_info() :: #media_info{}.
%%--------------------------------------------------------------------
access_hard_quota :: atom(),
max_days :: pos_integer() | infinity,
docroot :: binary(),
- disk_usage = #{} :: map(),
+ disk_usage = #{} :: disk_usage(),
timers :: [timer:tref()]}).
+-type disk_usage() :: #{{binary(), binary()} => non_neg_integer()}.
-type state() :: #state{}.
%%--------------------------------------------------------------------
will :: undefined | publish(),
will_delay = 0 :: seconds(),
stop_reason :: undefined | error_reason(),
- acks = #{} :: map(),
- subscriptions = #{} :: map(),
- topic_aliases = #{} :: map(),
+ acks = #{} :: acks(),
+ subscriptions = #{} :: subscriptions(),
+ topic_aliases = #{} :: topic_aliases(),
id = 0 :: non_neg_integer(),
in_flight :: undefined | publish() | pubrel(),
codec :: mqtt_codec:state(),
queue :: undefined | p1_queue:queue(),
tls :: boolean()}).
+-type acks() :: #{non_neg_integer() => pubrec()}.
+-type subscriptions() :: #{binary() => {sub_opts(), non_neg_integer()}}.
+-type topic_aliases() :: #{non_neg_integer() => binary()}.
+
-type error_reason() :: {auth, reason_code()} |
{code, reason_code()} |
{peer_disconnected, reason_code(), binary()} |
server_keep_alive => KeepAlive}.
-spec subscribe([{binary(), sub_opts()}], jid:ljid(), non_neg_integer()) ->
- {[reason_code()], map(), properties()}.
+ {[reason_code()], subscriptions(), properties()}.
subscribe(TopicFilters, USR, SubID) ->
subscribe(TopicFilters, USR, SubID, [], #{}, ok).
-spec subscribe([{binary(), sub_opts()}], jid:ljid(), non_neg_integer(),
- [reason_code()], map(), ok | {error, error_reason()}) ->
- {[reason_code()], map(), properties()}.
+ [reason_code()], subscriptions(), ok | {error, error_reason()}) ->
+ {[reason_code()], subscriptions(), properties()}.
subscribe([{TopicFilter, SubOpts}|TopicFilters], USR, SubID, Codes, Subs, Err) ->
case mod_mqtt:subscribe(USR, TopicFilter, SubOpts, SubID) of
ok ->
end,
{lists:reverse(Codes), Subs, Props}.
--spec unsubscribe([binary()], jid:ljid(), map()) ->
- {[reason_code()], map(), properties()}.
+-spec unsubscribe([binary()], jid:ljid(), subscriptions()) ->
+ {[reason_code()], subscriptions(), properties()}.
unsubscribe(TopicFilters, USR, Subs) ->
unsubscribe(TopicFilters, USR, [], Subs, ok).
-spec unsubscribe([binary()], jid:ljid(),
- [reason_code()], map(),
+ [reason_code()], subscriptions(),
ok | {error, error_reason()}) ->
- {[reason_code()], map(), properties()}.
+ {[reason_code()], subscriptions(), properties()}.
unsubscribe([TopicFilter|TopicFilters], USR, Codes, Subs, Err) ->
case mod_mqtt:unsubscribe(USR, TopicFilter) of
ok ->
end,
{lists:reverse(Codes), Subs, Props}.
--spec select_retained(jid:ljid(), map(), map()) -> [{publish(), seconds()}].
+-spec select_retained(jid:ljid(), subscriptions(), subscriptions()) -> [{publish(), seconds()}].
select_retained(USR, NewSubs, OldSubs) ->
lists:flatten(
maps:fold(
%%%===================================================================
%%% Misc
%%%===================================================================
--spec resubscribe(jid:ljid(), map()) -> ok | {error, error_reason()}.
+-spec resubscribe(jid:ljid(), subscriptions()) -> ok | {error, error_reason()}.
resubscribe(USR, Subs) ->
case maps:fold(
fun(TopicFilter, {SubOpts, ID}, ok) ->
-callback set_affiliation(binary(), binary(), binary(), jid(), affiliation(),
binary()) -> ok | {error, any()}.
-callback set_affiliations(binary(), binary(), binary(),
- map()) -> ok | {error, any()}.
+ affiliations()) -> ok | {error, any()}.
-callback get_affiliation(binary(), binary(), binary(),
binary(), binary()) -> {ok, affiliation()} | {error, any()}.
--callback get_affiliations(binary(), binary(), binary()) -> {ok, map()} | {error, any()}.
+-callback get_affiliations(binary(), binary(), binary()) -> {ok, affiliations()} | {error, any()}.
-callback search_affiliation(binary(), binary(), binary(), affiliation()) ->
{ok, [{ljid(), {affiliation(), binary()}}]} | {error, any()}.
role = none}],
status_codes = [332,110]}]},
maps:fold(
- fun(LJID, Info, _) ->
- Nick = Info#user.nick,
+ fun(_, #user{nick = Nick, jid = JID}, _) ->
case Reason of
shutdown ->
send_wrapped(jid:replace_resource(StateData#state.jid, Nick),
- Info#user.jid, Packet,
+ JID, Packet,
?NS_MUCSUB_NODES_PARTICIPANTS,
StateData);
_ -> ok
end,
- tab_remove_online_user(LJID, StateData)
+ tab_remove_online_user(JID, StateData)
end, [], get_users_and_subscribers(StateData)),
add_to_log(room_existence, stopped, StateData),
case (StateData#state.config)#config.persistent of
_ -> {next_state, normal_state, StateData1}
end.
--spec get_users_and_subscribers(state()) -> map().
+-spec get_users_and_subscribers(state()) -> users().
get_users_and_subscribers(StateData) ->
OnlineSubscribers = maps:fold(
fun(LJID, _, Acc) ->
end,
StateData#state{affiliations = Affiliations}.
--spec set_affiliations(map(), state()) -> state().
+-spec set_affiliations(affiliations(), state()) -> state().
set_affiliations(Affiliations,
#state{config = #config{persistent = false}} = StateData) ->
set_affiliations_fallback(Affiliations, StateData);
set_affiliations_fallback(Affiliations, StateData)
end.
--spec set_affiliations_fallback(map(), state()) -> state().
+-spec set_affiliations_fallback(affiliations(), state()) -> state().
set_affiliations_fallback(Affiliations, StateData) ->
StateData#state{affiliations = Affiliations}.
end
end.
--spec get_affiliations(state()) -> map().
+-spec get_affiliations(state()) -> affiliations().
get_affiliations(#state{config = #config{persistent = false}} = StateData) ->
get_affiliations_callback(StateData);
get_affiliations(StateData) ->
Affiliations
end.
--spec get_affiliations_callback(state()) -> map().
+-spec get_affiliations_callback(state()) -> affiliations().
get_affiliations_callback(StateData) ->
StateData#state.affiliations.
_ -> []
end
end,
- lists:foreach(fun (J) ->
- #user{nick = Nick} = maps:get(J, StateData#state.users),
+ lists:foreach(fun (LJ) ->
+ #user{nick = Nick, jid = J} = maps:get(LJ, StateData#state.users),
add_to_log(kickban, {Nick, Reason, Code}, StateData),
tab_remove_online_user(J, StateData),
send_kickban_presence1(UJID, J, Reason, Code,
id = Id,
sub_els = [El]}]}}]}.
--spec send_wrapped_multiple(jid(), map(), stanza(), binary(), state()) -> ok.
+-spec send_wrapped_multiple(jid(), users(), stanza(), binary(), state()) -> ok.
send_wrapped_multiple(From, Users, Packet, Node, State) ->
maps:fold(
fun(_, #user{jid = To}, _) ->
user_send/1, mod_opt_type/1, mod_options/1, depends/2]).
-record(state,
- {host = <<"">> :: binary(),
+ {host :: binary(),
send_pings :: boolean(),
ping_interval :: non_neg_integer(),
ping_ack_timeout :: undefined | non_neg_integer(),
- timeout_action ::none | kill,
- timers = maps:new() :: map()}).
+ timeout_action :: none | kill,
+ timers :: timers()}).
+
+-type timers() :: #{ljid() => reference()}.
%%====================================================================
%% API
ping_interval = PingInterval,
timeout_action = TimeoutAction,
ping_ack_timeout = PingAckTimeout,
- timers = maps:new()}.
+ timers = #{}}.
register_hooks(Host) ->
ejabberd_hooks:add(sm_register_connection_hook, Host,
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_PING),
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_PING).
--spec add_timer(jid(), non_neg_integer(), map()) -> map().
+-spec add_timer(jid(), non_neg_integer(), timers()) -> timers().
add_timer(JID, Interval, Timers) ->
LJID = jid:tolower(JID),
NewTimers = case maps:find(LJID, Timers) of
{ping, JID}),
maps:put(LJID, TRef, NewTimers).
--spec del_timer(jid(), map()) -> map().
+-spec del_timer(jid(), timers()) -> timers().
del_timer(JID, Timers) ->
LJID = jid:tolower(JID),
case maps:find(LJID, Timers) of