mirror of
https://github.com/processone/ejabberd
synced 2025-10-03 09:49:18 +02:00
Support Matrix room aliases
This commit is contained in:
parent
e7035f3235
commit
80423d7e69
1 changed files with 85 additions and 21 deletions
|
@ -77,7 +77,8 @@
|
||||||
client_state}).
|
client_state}).
|
||||||
|
|
||||||
-record(multi_user,
|
-record(multi_user,
|
||||||
{join_ts :: integer()}).
|
{join_ts :: integer(),
|
||||||
|
room_jid :: jid()}).
|
||||||
|
|
||||||
-record(multi,
|
-record(multi,
|
||||||
{users :: #{{binary(), binary()} => #{binary() => #multi_user{}}}}).
|
{users :: #{{binary(), binary()} => #{binary() => #multi_user{}}}}).
|
||||||
|
@ -105,6 +106,9 @@
|
||||||
-define(MAX_DEPTH, 16#7FFFFFFFFFFFFFFF).
|
-define(MAX_DEPTH, 16#7FFFFFFFFFFFFFFF).
|
||||||
-define(MAX_TXN_RETRIES, 5).
|
-define(MAX_TXN_RETRIES, 5).
|
||||||
|
|
||||||
|
-define(MATRIX_ROOM_ALIAS_CACHE, matrix_room_alias_cache).
|
||||||
|
-define(MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT, 60000).
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
@ -140,6 +144,7 @@ create_db() ->
|
||||||
[{ram_copies, [node()]},
|
[{ram_copies, [node()]},
|
||||||
{type, set},
|
{type, set},
|
||||||
{attributes, record_info(fields, matrix_direct)}]),
|
{attributes, record_info(fields, matrix_direct)}]),
|
||||||
|
ets_cache:new(?MATRIX_ROOM_ALIAS_CACHE),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
get_room_pid(Host, RoomID) ->
|
get_room_pid(Host, RoomID) ->
|
||||||
|
@ -170,11 +175,13 @@ join_direct(Host, MatrixServer, RoomID, Sender, UserID) ->
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
route(#presence{from = From, to = #jid{luser = <<$!, _/binary>>} = To,
|
route(#presence{from = From, to = #jid{luser = <<C, _/binary>>} = To,
|
||||||
type = Type} = Packet) ->
|
type = Type} = Packet)
|
||||||
case room_id_from_xmpp(To#jid.luser) of
|
when C == $!;
|
||||||
|
C == $# ->
|
||||||
|
Host = ejabberd_config:get_myname(),
|
||||||
|
case room_id_from_xmpp(Host, To#jid.luser) of
|
||||||
{ok, RoomID} ->
|
{ok, RoomID} ->
|
||||||
Host = ejabberd_config:get_myname(),
|
|
||||||
case From#jid.lserver of
|
case From#jid.lserver of
|
||||||
Host ->
|
Host ->
|
||||||
case Type of
|
case Type of
|
||||||
|
@ -200,14 +207,20 @@ route(#presence{from = From, to = #jid{luser = <<$!, _/binary>>} = To,
|
||||||
ok
|
ok
|
||||||
end;
|
end;
|
||||||
error ->
|
error ->
|
||||||
|
Lang = xmpp:get_lang(Packet),
|
||||||
|
Txt = <<"bad or non-existing room id">>,
|
||||||
|
Err = xmpp:err_not_acceptable(Txt, Lang),
|
||||||
|
ejabberd_router:route_error(Packet, Err),
|
||||||
ok
|
ok
|
||||||
end;
|
end;
|
||||||
route(#message{from = From, to = #jid{luser = <<$!, _/binary>>} = To,
|
route(#message{from = From, to = #jid{luser = <<C, _/binary>>} = To,
|
||||||
type = groupchat,
|
type = groupchat,
|
||||||
body = Body}) ->
|
body = Body})
|
||||||
case room_id_from_xmpp(To#jid.luser) of
|
when C == $!;
|
||||||
|
C == $# ->
|
||||||
|
Host = ejabberd_config:get_myname(),
|
||||||
|
case room_id_from_xmpp(Host, To#jid.luser) of
|
||||||
{ok, RoomID} ->
|
{ok, RoomID} ->
|
||||||
Host = ejabberd_config:get_myname(),
|
|
||||||
case From#jid.lserver of
|
case From#jid.lserver of
|
||||||
Host ->
|
Host ->
|
||||||
case user_id_from_jid(From, Host) of
|
case user_id_from_jid(From, Host) of
|
||||||
|
@ -685,6 +698,7 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) ->
|
||||||
#{{LUser, LServer} := Rs} -> Rs;
|
#{{LUser, LServer} := Rs} -> Rs;
|
||||||
_ -> #{}
|
_ -> #{}
|
||||||
end,
|
end,
|
||||||
|
RoomJID = jid:remove_resource(xmpp:get_to(Packet)),
|
||||||
Data2 =
|
Data2 =
|
||||||
Data#data{
|
Data#data{
|
||||||
kind =
|
kind =
|
||||||
|
@ -692,7 +706,8 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) ->
|
||||||
users =
|
users =
|
||||||
Users#{{LUser, LServer} =>
|
Users#{{LUser, LServer} =>
|
||||||
Resources#{LResource =>
|
Resources#{LResource =>
|
||||||
#multi_user{join_ts = JoinTS}}}}},
|
#multi_user{join_ts = JoinTS,
|
||||||
|
room_jid = RoomJID}}}}},
|
||||||
{keep_state, Data2, [{next_event, cast, {add_event, JSON}}]};
|
{keep_state, Data2, [{next_event, cast, {add_event, JSON}}]};
|
||||||
error ->
|
error ->
|
||||||
?INFO_MSG("bad join user id: ~p", [UserJID]),
|
?INFO_MSG("bad join user id: ~p", [UserJID]),
|
||||||
|
@ -758,6 +773,7 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) ->
|
||||||
{timeout, 60000}],
|
{timeout, 60000}],
|
||||||
[{sync, true},
|
[{sync, true},
|
||||||
{body_format, binary}]),
|
{body_format, binary}]),
|
||||||
|
RoomJID = jid:remove_resource(xmpp:get_to(Packet)),
|
||||||
?DEBUG("send_join ~p~n", [SendJoinRes]),
|
?DEBUG("send_join ~p~n", [SendJoinRes]),
|
||||||
process_send_join_res(
|
process_send_join_res(
|
||||||
MatrixServer, SendJoinRes, RoomVersion,
|
MatrixServer, SendJoinRes, RoomVersion,
|
||||||
|
@ -765,7 +781,8 @@ handle_event(cast, {join, UserJID, Packet}, _State, Data) ->
|
||||||
kind =
|
kind =
|
||||||
#multi{users =
|
#multi{users =
|
||||||
#{{LUser, LServer} =>
|
#{{LUser, LServer} =>
|
||||||
#{LResource => #multi_user{join_ts = JoinTS}}}},
|
#{LResource => #multi_user{join_ts = JoinTS,
|
||||||
|
room_jid = RoomJID}}}},
|
||||||
room_version = RoomVersion})
|
room_version = RoomVersion})
|
||||||
end;
|
end;
|
||||||
_JSON ->
|
_JSON ->
|
||||||
|
@ -2642,12 +2659,13 @@ notify_event_xmpp(
|
||||||
case Sender of
|
case Sender of
|
||||||
<<$@, SenderUser/binary>> ->
|
<<$@, SenderUser/binary>> ->
|
||||||
?DEBUG("notify xmpp ~p", [Users]),
|
?DEBUG("notify xmpp ~p", [Users]),
|
||||||
From = jid:replace_resource(Data#data.room_jid, SenderUser),
|
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun({LUser, LServer}, Resources, ok) ->
|
fun({LUser, LServer}, Resources, ok) ->
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(LResource, #multi_user{join_ts = JoinTS}, ok)
|
fun(LResource, #multi_user{join_ts = JoinTS,
|
||||||
|
room_jid = RoomJID}, ok)
|
||||||
when JoinTS =< OriginTS ->
|
when JoinTS =< OriginTS ->
|
||||||
|
From = jid:replace_resource(RoomJID, SenderUser),
|
||||||
UserJID = jid:make(LUser, LServer, LResource),
|
UserJID = jid:make(LUser, LServer, LResource),
|
||||||
Msg = #message{from = From,
|
Msg = #message{from = From,
|
||||||
to = UserJID,
|
to = UserJID,
|
||||||
|
@ -2673,16 +2691,17 @@ notify_event_xmpp(
|
||||||
case user_id_to_jid(Sender, Data) of
|
case user_id_to_jid(Sender, Data) of
|
||||||
#jid{} = SenderJID ->
|
#jid{} = SenderJID ->
|
||||||
<<$@, SenderUser/binary>> = Sender,
|
<<$@, SenderUser/binary>> = Sender,
|
||||||
From = jid:replace_resource(Data#data.room_jid, SenderUser),
|
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun({LUser, LServer}, Resources, ok) ->
|
fun({LUser, LServer}, Resources, ok) ->
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(LResource, #multi_user{join_ts = JoinTS}, ok)
|
fun(LResource, #multi_user{join_ts = JoinTS,
|
||||||
|
room_jid = RoomJID}, ok)
|
||||||
when JoinTS =< OriginTS ->
|
when JoinTS =< OriginTS ->
|
||||||
|
From = jid:replace_resource(RoomJID, SenderUser),
|
||||||
case jid:tolower(SenderJID) of
|
case jid:tolower(SenderJID) of
|
||||||
{LUser, LServer, _} ->
|
{LUser, LServer, _} ->
|
||||||
send_initial_presences(
|
send_initial_presences(
|
||||||
SenderJID, Event, Data);
|
SenderJID, RoomJID, Event, Data);
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
|
@ -2709,12 +2728,13 @@ notify_event_xmpp(
|
||||||
Membership == <<"ban">> ->
|
Membership == <<"ban">> ->
|
||||||
case StateKey of
|
case StateKey of
|
||||||
<<$@, RUser/binary>> ->
|
<<$@, RUser/binary>> ->
|
||||||
From = jid:replace_resource(Data#data.room_jid, RUser),
|
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun({LUser, LServer}, Resources, ok) ->
|
fun({LUser, LServer}, Resources, ok) ->
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun(LResource, #multi_user{join_ts = JoinTS}, ok)
|
fun(LResource, #multi_user{join_ts = JoinTS,
|
||||||
|
room_jid = RoomJID}, ok)
|
||||||
when JoinTS =< OriginTS ->
|
when JoinTS =< OriginTS ->
|
||||||
|
From = jid:replace_resource(RoomJID, RUser),
|
||||||
UserJID = jid:make(LUser, LServer, LResource),
|
UserJID = jid:make(LUser, LServer, LResource),
|
||||||
Pres = #presence{from = From,
|
Pres = #presence{from = From,
|
||||||
to = UserJID,
|
to = UserJID,
|
||||||
|
@ -2755,7 +2775,7 @@ notify_event_xmpp(
|
||||||
notify_event_xmpp(_Event, Data) ->
|
notify_event_xmpp(_Event, Data) ->
|
||||||
Data.
|
Data.
|
||||||
|
|
||||||
send_initial_presences(JID, Event, Data) ->
|
send_initial_presences(JID, RoomJID, Event, Data) ->
|
||||||
?DEBUG("send_initial_presences ~p", [{JID, Event}]),
|
?DEBUG("send_initial_presences ~p", [{JID, Event}]),
|
||||||
maps:fold(
|
maps:fold(
|
||||||
fun({?ROOM_MEMBER, _}, EID, ok) ->
|
fun({?ROOM_MEMBER, _}, EID, ok) ->
|
||||||
|
@ -2764,7 +2784,7 @@ send_initial_presences(JID, Event, Data) ->
|
||||||
sender = <<$@, SenderUser/binary>>,
|
sender = <<$@, SenderUser/binary>>,
|
||||||
json = #{<<"content">> :=
|
json = #{<<"content">> :=
|
||||||
#{<<"membership">> := <<"join">>}}}} ->
|
#{<<"membership">> := <<"join">>}}}} ->
|
||||||
From = jid:replace_resource(Data#data.room_jid, SenderUser),
|
From = jid:replace_resource(RoomJID, SenderUser),
|
||||||
Pres = #presence{from = From,
|
Pres = #presence{from = From,
|
||||||
to = JID,
|
to = JID,
|
||||||
type = available
|
type = available
|
||||||
|
@ -3148,7 +3168,7 @@ room_id_to_xmpp(RoomID) ->
|
||||||
error
|
error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
room_id_from_xmpp(RID) ->
|
room_id_from_xmpp(Host, RID) ->
|
||||||
case RID of
|
case RID of
|
||||||
<<$!, Parts/binary>> ->
|
<<$!, Parts/binary>> ->
|
||||||
case binary:split(Parts, <<"%">>) of
|
case binary:split(Parts, <<"%">>) of
|
||||||
|
@ -3159,10 +3179,54 @@ room_id_from_xmpp(RID) ->
|
||||||
{ok, <<$!, RoomID/binary, $:, S/binary>>};
|
{ok, <<$!, RoomID/binary, $:, S/binary>>};
|
||||||
_ -> error
|
_ -> error
|
||||||
end;
|
end;
|
||||||
|
<<$#, Parts/binary>> ->
|
||||||
|
case binary:split(Parts, <<"%">>) of
|
||||||
|
[R, S] ->
|
||||||
|
Alias = <<$#, R/binary, $:, S/binary>>,
|
||||||
|
case resolve_alias(Host, S, Alias) of
|
||||||
|
{ok, <<$!, _/binary>> = RoomID} ->
|
||||||
|
{ok, RoomID};
|
||||||
|
error ->
|
||||||
|
error
|
||||||
|
end;
|
||||||
|
_ -> error
|
||||||
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
error
|
error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
resolve_alias(Host, Origin, Alias) ->
|
||||||
|
ets_cache:lookup(
|
||||||
|
?MATRIX_ROOM_ALIAS_CACHE, Alias,
|
||||||
|
fun() ->
|
||||||
|
Res =
|
||||||
|
mod_matrix_gw:send_request(
|
||||||
|
Host, get, Origin,
|
||||||
|
[<<"_matrix">>, <<"federation">>,
|
||||||
|
<<"v1">>, <<"query">>, <<"directory">>],
|
||||||
|
[{<<"room_alias">>, Alias}],
|
||||||
|
none,
|
||||||
|
[{timeout, 5000}],
|
||||||
|
[{sync, true},
|
||||||
|
{body_format, binary}]),
|
||||||
|
case Res of
|
||||||
|
{ok, {{_, 200, _}, _Headers, Body}} ->
|
||||||
|
try
|
||||||
|
case misc:json_decode(Body) of
|
||||||
|
#{<<"room_id">> := RoomID} ->
|
||||||
|
{ok, RoomID}
|
||||||
|
end
|
||||||
|
catch
|
||||||
|
Class:Reason:ST ->
|
||||||
|
?DEBUG("failed resolve_alias: ~p", [{Class, Reason, ST}]),
|
||||||
|
{cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT}
|
||||||
|
end;
|
||||||
|
{ok, {{_, _Status, _Reason}, _Headers, _Body}} ->
|
||||||
|
{cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT};
|
||||||
|
{error, _Reason} ->
|
||||||
|
{cache_with_timeout, error, ?MATRIX_ROOM_ALIAS_CACHE_ERROR_TIMEOUT}
|
||||||
|
end
|
||||||
|
end).
|
||||||
|
|
||||||
|
|
||||||
escape(S) ->
|
escape(S) ->
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue