Files
fluxer/fluxer_gateway/src/gateway/gateway_rpc_guild_voice_util.erl
T

155 lines
6.4 KiB
Erlang

%% SPDX-License-Identifier: AGPL-3.0-or-later
-module(gateway_rpc_guild_voice_util).
-typing([eqwalizer]).
-export([
handle_move_member_result/4,
normalize_voice_rpc_error/1,
parse_voice_update/1,
process_voice_update/1
]).
-export_type([voice_update_payload/0]).
-define(GUILD_CALL_TIMEOUT, 4000).
-spec handle_move_member_result(term(), integer(), integer() | null, pid()) -> map().
handle_move_member_result(
#{
success := true,
needs_token := true,
session_data := SessionData,
connections_to_move := _
},
GuildId,
ChannelId,
Pid
) when is_integer(ChannelId), is_list(SessionData) ->
VoiceSessionData = voice_session_data(SessionData),
send_voice_server_updates_for_move(GuildId, ChannelId, VoiceSessionData, Pid),
#{<<"success">> => true};
handle_move_member_result(#{success := true, user_id := DisconnectedUserId}, _, null, Pid) when
is_integer(DisconnectedUserId)
->
cleanup_virtual_access_on_disconnect(DisconnectedUserId, Pid),
#{<<"success">> => true};
handle_move_member_result(#{success := true}, _, _, _) ->
#{<<"success">> => true};
handle_move_member_result({error, _Category, ErrorAtom}, _, _, _) ->
#{<<"success">> => false, <<"error">> => normalize_voice_rpc_error(ErrorAtom)};
handle_move_member_result(#{error := Error}, _, _, _) ->
#{<<"success">> => false, <<"error">> => normalize_voice_rpc_error(Error)};
handle_move_member_result(_, _, _, _) ->
#{<<"success">> => false, <<"error">> => <<"move_member_error">>}.
-spec send_voice_server_updates_for_move(integer(), integer(), [map()], pid()) -> ok.
send_voice_server_updates_for_move(GuildId, ChannelId, VoiceSessionData, Pid) ->
spawn(fun() ->
guild_voice:send_voice_server_updates_for_move(
GuildId, ChannelId, VoiceSessionData, Pid
)
end),
ok.
-spec cleanup_virtual_access_on_disconnect(integer(), pid()) -> ok.
cleanup_virtual_access_on_disconnect(DisconnectedUserId, Pid) ->
spawn(fun() -> guild_voice:cleanup_virtual_access_on_disconnect(DisconnectedUserId, Pid) end),
ok.
-spec voice_session_data([term()]) -> [map()].
voice_session_data(SessionData) ->
[Entry || Entry <- SessionData, is_map(Entry)].
-type voice_update_payload() :: #{binary() => term()}.
-spec parse_voice_update(voice_update_payload()) ->
{integer(), integer(), boolean(), boolean(), term()}.
parse_voice_update(
#{
<<"guild_id">> := GuildIdBin,
<<"user_id">> := UserIdBin,
<<"mute">> := Mute,
<<"deaf">> := Deaf
} = Update
) when is_boolean(Mute), is_boolean(Deaf) ->
GuildId = validation:snowflake_or_throw(<<"guild_id">>, GuildIdBin),
UserId = validation:snowflake_or_throw(<<"user_id">>, UserIdBin),
{GuildId, UserId, Mute, Deaf, maps:get(<<"connection_id">>, Update, null)}.
-spec process_voice_update(term()) -> map().
process_voice_update({GuildId, UserId, Mute, Deaf, ConnectionId}) when
is_integer(GuildId), is_integer(UserId), is_boolean(Mute), is_boolean(Deaf)
->
case gateway_rpc_guild_infra:ensure_guild_pid(GuildId) of
{ok, GuildPid} ->
process_voice_update_for_guild(GuildId, UserId, Mute, Deaf, ConnectionId, GuildPid);
_ ->
voice_update_result(GuildId, UserId, false, <<"guild_not_found">>)
end;
process_voice_update(_) ->
#{<<"success">> => false, <<"error">> => <<"voice_update_error">>}.
-spec process_voice_update_for_guild(
integer(), integer(), boolean(), boolean(), term(), pid()
) -> map().
process_voice_update_for_guild(GuildId, UserId, Mute, Deaf, ConnectionId, GuildPid) ->
VoicePid = gateway_rpc_guild_infra:resolve_voice_pid(GuildId, GuildPid),
Request = #{
user_id => UserId,
mute => Mute,
deaf => Deaf,
connection_id => ConnectionId
},
Result = gateway_rpc_guild_infra:safe_gen_server_call(
VoicePid,
{update_member_voice, Request},
?GUILD_CALL_TIMEOUT
),
normalize_voice_update_result(GuildId, UserId, Result).
-spec normalize_voice_update_result(integer(), integer(), term()) -> map().
normalize_voice_update_result(GuildId, UserId, {ok, #{success := true}}) ->
voice_update_result(GuildId, UserId, true, undefined);
normalize_voice_update_result(GuildId, UserId, {ok, #{error := Error}}) ->
voice_update_result(GuildId, UserId, false, Error);
normalize_voice_update_result(GuildId, UserId, _Result) ->
voice_update_result(GuildId, UserId, false, <<"voice_update_error">>).
-spec voice_update_result(integer(), integer(), boolean(), term()) -> map().
voice_update_result(GuildId, UserId, true, _Error) ->
#{
<<"guild_id">> => integer_to_binary(GuildId),
<<"user_id">> => integer_to_binary(UserId),
<<"success">> => true
};
voice_update_result(GuildId, UserId, false, Error) ->
#{
<<"guild_id">> => integer_to_binary(GuildId),
<<"user_id">> => integer_to_binary(UserId),
<<"success">> => false,
<<"error">> => Error
}.
-spec normalize_voice_rpc_error(term()) -> binary().
normalize_voice_rpc_error(voice_user_not_in_voice) -> <<"user_not_in_voice">>;
normalize_voice_rpc_error(voice_channel_not_found) -> <<"channel_not_found">>;
normalize_voice_rpc_error(voice_channel_not_voice) -> <<"channel_not_voice">>;
normalize_voice_rpc_error(voice_moderator_missing_connect) -> <<"moderator_missing_connect">>;
normalize_voice_rpc_error(voice_permission_denied) -> <<"target_missing_connect">>;
normalize_voice_rpc_error(voice_connection_not_found) -> <<"connection_not_found">>;
normalize_voice_rpc_error(voice_missing_connection_id) -> <<"connection_not_found">>;
normalize_voice_rpc_error(Error) when is_binary(Error) -> normalize_binary(Error);
normalize_voice_rpc_error(Error) when is_atom(Error) -> atom_to_binary(Error, utf8);
normalize_voice_rpc_error(_) -> <<"move_member_error">>.
-spec normalize_binary(binary()) -> binary().
normalize_binary(<<"voice_user_not_in_voice">>) -> <<"user_not_in_voice">>;
normalize_binary(<<"voice_channel_not_found">>) -> <<"channel_not_found">>;
normalize_binary(<<"voice_channel_not_voice">>) -> <<"channel_not_voice">>;
normalize_binary(<<"voice_moderator_missing_connect">>) -> <<"moderator_missing_connect">>;
normalize_binary(<<"voice_permission_denied">>) -> <<"target_missing_connect">>;
normalize_binary(<<"voice_connection_not_found">>) -> <<"connection_not_found">>;
normalize_binary(<<"voice_missing_connection_id">>) -> <<"connection_not_found">>;
normalize_binary(Error) -> Error.