diff options
author | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2017-03-28 19:34:04 +0300 |
---|---|---|
committer | Evgeniy Khramtsov <ekhramtsov@process-one.net> | 2017-03-28 19:34:04 +0300 |
commit | cba6e1b3abbb76addfafedabcdecae9a447549b2 (patch) | |
tree | 8f2b8b78da7f2179170370ef77f769eeeae4b9a4 /src/ejabberd_router_redis.erl | |
parent | Mix needs include path to p1_utils (diff) |
Add Redis as router RAM backend
Diffstat (limited to 'src/ejabberd_router_redis.erl')
-rw-r--r-- | src/ejabberd_router_redis.erl | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/src/ejabberd_router_redis.erl b/src/ejabberd_router_redis.erl new file mode 100644 index 00000000..be8d166b --- /dev/null +++ b/src/ejabberd_router_redis.erl @@ -0,0 +1,154 @@ +%%%------------------------------------------------------------------- +%%% @author Evgeny Khramtsov <ekhramtsov@process-one.net> +%%% Created : 28 Mar 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net> +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2017 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%------------------------------------------------------------------- +-module(ejabberd_router_redis). +-behaviour(ejabberd_router). + +%% API +-export([init/0, register_route/5, unregister_route/3, find_routes/1, + host_of_route/1, is_my_route/1, is_my_host/1, get_all_routes/0, + find_routes/0]). + +-include("ejabberd.hrl"). +-include("logger.hrl"). +-include("ejabberd_router.hrl"). + +-define(ROUTES_KEY, "ejabberd:routes"). + +%%%=================================================================== +%%% API +%%%=================================================================== +init() -> + clean_table(). + +register_route(Domain, ServerHost, LocalHint, _, Pid) -> + DomKey = domain_key(Domain), + PidKey = term_to_binary(Pid), + T = term_to_binary({ServerHost, LocalHint}), + case ejabberd_redis:qp([["HSET", DomKey, PidKey, T], + ["SADD", ?ROUTES_KEY, Domain]]) of + [{ok, _}, {ok, _}] -> + ok; + Err -> + ?ERROR_MSG("failed to register route in redis: ~p", [Err]), + Err + end. + +unregister_route(Domain, _, Pid) -> + DomKey = domain_key(Domain), + PidKey = term_to_binary(Pid), + try + {ok, _} = ejabberd_redis:q(["HDEL", DomKey, PidKey]), + {ok, Num} = ejabberd_redis:q(["HLEN", DomKey]), + case binary_to_integer(Num) of + 0 -> + {ok, _} = ejabberd_redis:q(["SREM", ?ROUTES_KEY, Domain]), + ok; + _ -> + ok + end + catch _:{badmatch, Err} -> + ?ERROR_MSG("failed to unregister route in redis: ~p", [Err]), + Err + end. + +find_routes(Domain) -> + DomKey = domain_key(Domain), + case ejabberd_redis:q(["HGETALL", DomKey]) of + {ok, Vals} -> + decode_routes(Domain, Vals); + Err -> + ?ERROR_MSG("failed to find routes in redis: ~p", [Err]), + [] + end. + +host_of_route(Domain) -> + DomKey = domain_key(Domain), + case ejabberd_redis:q(["HGETALL", DomKey]) of + {ok, [_, Data|_]} -> + {ServerHost, _} = binary_to_term(Data), + {ok, ServerHost}; + {ok, []} -> + error; + Err -> + ?ERROR_MSG("failed to get host of route in redis: ~p", [Err]), + error + end. + +is_my_route(Domain) -> + case ejabberd_redis:q(["SISMEMBER", ?ROUTES_KEY, Domain]) of + {ok, <<"1">>} -> true; + {ok, _} -> false; + Err -> + ?ERROR_MSG("failed to check route in redis: ~p", [Err]), + false + end. + +is_my_host(Domain) -> + {ok, Domain} == host_of_route(Domain). + +get_all_routes() -> + case ejabberd_redis:q(["SMEMBERS", ?ROUTES_KEY]) of + {ok, Routes} -> + Routes; + Err -> + ?ERROR_MSG("failed to fetch routes from redis: ~p", [Err]), + [] + end. + +find_routes() -> + lists:flatmap( + fun(Domain) -> + DomKey = domain_key(Domain), + case ejabberd_redis:q(["HGETALL", DomKey]) of + {ok, Vals} -> + decode_routes(Domain, Vals); + Err -> + ?ERROR_MSG("failed to fetch routes from redis: ~p", + [Err]), + [] + end + end, get_all_routes()). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== +clean_table() -> + lists:foreach( + fun(#route{domain = Domain, pid = Pid}) when node(Pid) == node() -> + unregister_route(Domain, undefined, Pid); + (_) -> + ok + end, find_routes()). + +domain_key(Domain) -> + <<"ejabberd:route:", Domain/binary>>. + +decode_routes(Domain, [Pid, Data|Vals]) -> + {ServerHost, LocalHint} = binary_to_term(Data), + [#route{domain = Domain, + pid = binary_to_term(Pid), + server_host = ServerHost, + local_hint = LocalHint}| + decode_routes(Domain, Vals)]; +decode_routes(_, []) -> + []. |