fluxer/fluxer_gateway/src/gateway/gateway_rpc_call.erl
2026-01-01 21:05:54 +00:00

216 lines
8.5 KiB
Erlang

%% Copyright (C) 2026 Fluxer Contributors
%%
%% This file is part of Fluxer.
%%
%% Fluxer is free software: you can redistribute it and/or modify
%% it under the terms of the GNU Affero General Public License as published by
%% the Free Software Foundation, either version 3 of the License, or
%% (at your option) any later version.
%%
%% Fluxer 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 Affero General Public License for more details.
%%
%% You should have received a copy of the GNU Affero General Public License
%% along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
-module(gateway_rpc_call).
-export([execute_method/2]).
execute_method(<<"call.get">>, #{<<"channel_id">> := ChannelIdBin}) ->
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
case gen_server:call(call_manager, {lookup, ChannelId}, 5000) of
{ok, Pid} ->
case gen_server:call(Pid, {get_state}, 5000) of
{ok, CallData} ->
CallData;
_ ->
throw({error, <<"Failed to get call state">>})
end;
{error, not_found} ->
null;
not_found ->
null
end;
execute_method(<<"call.create">>, Params) ->
#{
<<"channel_id">> := ChannelIdBin,
<<"message_id">> := MessageIdBin,
<<"region">> := Region,
<<"ringing">> := RingingBins,
<<"recipients">> := RecipientsBins
} = Params,
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
MessageId = validation:snowflake_or_throw(<<"message_id">>, MessageIdBin),
Ringing = validation:snowflake_list_or_throw(<<"ringing">>, RingingBins),
Recipients = validation:snowflake_list_or_throw(<<"recipients">>, RecipientsBins),
CallData = #{
channel_id => ChannelId,
message_id => MessageId,
region => Region,
ringing => Ringing,
recipients => Recipients
},
case gen_server:call(call_manager, {create, ChannelId, CallData}, 10000) of
{ok, Pid} ->
case gen_server:call(Pid, {get_state}, 5000) of
{ok, CallState} ->
CallState;
_ ->
throw({error, <<"Failed to get call state after creation">>})
end;
{error, already_exists} ->
throw({error, <<"Call already exists">>});
{error, Reason} ->
throw({error, iolist_to_binary(io_lib:format("Failed to create call: ~p", [Reason]))})
end;
execute_method(<<"call.update_region">>, #{
<<"channel_id">> := ChannelIdBin, <<"region">> := Region
}) ->
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
case gen_server:call(call_manager, {lookup, ChannelId}, 5000) of
{ok, Pid} ->
case gen_server:call(Pid, {update_region, Region}, 5000) of
ok ->
true;
_ ->
throw({error, <<"Failed to update region">>})
end;
not_found ->
throw({error, <<"Call not found">>})
end;
execute_method(<<"call.ring">>, Params) ->
#{<<"channel_id">> := ChannelIdBin, <<"recipients">> := RecipientsBin} = Params,
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
Recipients = validation:snowflake_list_or_throw(<<"recipients">>, RecipientsBin),
case gen_server:call(call_manager, {lookup, ChannelId}, 5000) of
{ok, Pid} ->
case gen_server:call(Pid, {ring_recipients, Recipients}, 5000) of
ok ->
true;
_ ->
throw({error, <<"Failed to ring recipients">>})
end;
not_found ->
throw({error, <<"Call not found">>})
end;
execute_method(<<"call.stop_ringing">>, Params) ->
#{<<"channel_id">> := ChannelIdBin, <<"recipients">> := RecipientsBin} = Params,
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
Recipients = validation:snowflake_list_or_throw(<<"recipients">>, RecipientsBin),
case gen_server:call(call_manager, {lookup, ChannelId}, 5000) of
{ok, Pid} ->
case gen_server:call(Pid, {stop_ringing, Recipients}, 5000) of
ok ->
true;
_ ->
throw({error, <<"Failed to stop ringing">>})
end;
not_found ->
throw({error, <<"Call not found">>})
end;
execute_method(<<"call.join">>, Params) ->
#{
<<"channel_id">> := ChannelIdBin,
<<"user_id">> := UserIdBin,
<<"session_id">> := SessionIdBin,
<<"voice_state">> := VoiceState
} = Params,
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
UserId = validation:snowflake_or_throw(<<"user_id">>, UserIdBin),
SessionId = SessionIdBin,
case gen_server:call(session_manager, {lookup, SessionId}, 5000) of
{ok, SessionPid} ->
case gen_server:call(call_manager, {lookup, ChannelId}, 5000) of
{ok, CallPid} ->
case
gen_server:call(
CallPid, {join, UserId, VoiceState, SessionId, SessionPid}, 5000
)
of
ok ->
true;
_ ->
throw({error, <<"Failed to join call">>})
end;
not_found ->
throw({error, <<"Call not found">>})
end;
not_found ->
throw({error, <<"Session not found">>})
end;
execute_method(<<"call.leave">>, #{<<"channel_id">> := ChannelIdBin, <<"session_id">> := SessionId}) ->
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
case gen_server:call(call_manager, {lookup, ChannelId}, 5000) of
{ok, Pid} ->
case gen_server:call(Pid, {leave, SessionId}, 5000) of
ok ->
true;
_ ->
throw({error, <<"Failed to leave call">>})
end;
not_found ->
throw({error, <<"Call not found">>})
end;
execute_method(<<"call.delete">>, #{<<"channel_id">> := ChannelIdBin}) ->
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
case gen_server:call(call_manager, {terminate_call, ChannelId}, 5000) of
ok ->
true;
{error, not_found} ->
throw({error, <<"Call not found">>});
_ ->
throw({error, <<"Failed to delete call">>})
end;
execute_method(<<"call.confirm_connection">>, Params) ->
#{<<"channel_id">> := ChannelIdBin, <<"connection_id">> := ConnectionId} = Params,
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
logger:debug(
"[gateway_rpc_call] call.confirm_connection channel_id=~p connection_id=~p",
[ChannelId, ConnectionId]
),
case gen_server:call(call_manager, {lookup, ChannelId}, 5000) of
{ok, Pid} ->
gen_server:call(Pid, {confirm_connection, ConnectionId}, 5000);
{error, not_found} ->
logger:debug(
"[gateway_rpc_call] call.confirm_connection call not found for channel_id=~p", [
ChannelId
]
),
#{success => true, call_not_found => true};
not_found ->
logger:debug(
"[gateway_rpc_call] call.confirm_connection call manager returned not_found for channel_id=~p",
[ChannelId]
),
#{success => true, call_not_found => true}
end;
execute_method(<<"call.disconnect_user_if_in_channel">>, Params) ->
#{<<"channel_id">> := ChannelIdBin, <<"user_id">> := UserIdBin} = Params,
ChannelId = validation:snowflake_or_throw(<<"channel_id">>, ChannelIdBin),
UserId = validation:snowflake_or_throw(<<"user_id">>, UserIdBin),
ConnectionId = maps:get(<<"connection_id">>, Params, undefined),
case gen_server:call(call_manager, {lookup, ChannelId}, 5000) of
{ok, Pid} ->
gen_server:call(
Pid, {disconnect_user_if_in_channel, UserId, ChannelId, ConnectionId}, 5000
);
{error, not_found} ->
#{success => true, call_not_found => true};
not_found ->
#{success => true, call_not_found => true}
end.