Current section
Files
Jump to
Current section
Files
src/grpcbox_reflection_service.erl
-module(grpcbox_reflection_service).
-export([server_reflection_info/2]).
-include("grpcbox.hrl").
-define(UNIMPLEMENTED_RESPONSE,
{error_response,
#{error_code => 12,
error_message => "unimplemented method since extensions removed in proto3"}}).
server_reflection_info(Ref, Stream) ->
receive
{Ref, Message} ->
handle_message(Message, Stream),
server_reflection_info(Ref, Stream)
end.
handle_message(#{message_request := {list_services, _}}=OriginalRequest, Stream) ->
Services = list_services(),
grpcbox_stream:send(#{original_request => OriginalRequest,
message_response => {list_services_response,
#{service => Services}}}, Stream);
handle_message(#{message_request := {file_by_filename, Filename}}=OriginalRequest, Stream) ->
Response = file_by_filename(Filename),
grpcbox_stream:send(#{original_request => OriginalRequest,
message_response => Response}, Stream);
handle_message(#{message_request := {file_containing_symbol, Symbol}}=OriginalRequest, Stream) ->
Response = file_containing_symbol(Symbol),
grpcbox_stream:send(#{original_request => OriginalRequest,
message_response => Response}, Stream);
%% proto3 dropped extensions so we'll just return an empty result
handle_message(#{message_request := {all_extension_numbers_of_type, _}}=OriginalRequest, Stream) ->
grpcbox_stream:send(#{original_request => OriginalRequest,
message_response => ?UNIMPLEMENTED_RESPONSE},
Stream);
handle_message(#{message_request := {file_containing_extension, _}}=OriginalRequest, Stream) ->
grpcbox_stream:send(#{original_request => OriginalRequest,
message_response => ?UNIMPLEMENTED_RESPONSE}, Stream).
%%
list_services() ->
ServiceSups = supervisor:which_children(grpcbox_services_simple_sup),
lists:usort(lists:flatmap(fun services/1, ServiceSups)).
services({_, Pid, _, _}) ->
{registered_name, Name} = erlang:process_info(Pid, registered_name),
[#{name => Service} || Service <- ets:select(Name, [{#method{key={'$1', '_'},
_='_'}, [], ['$1']}])].
file_by_filename(_Filename) ->
{error_response, #{error_code => 12,
error_message => "not implemented yet"}}.
%% {file_descriptor_response, #{file_descriptor_proto => [FileDescriptor]}
file_containing_symbol(Symbol) ->
ServiceSups = supervisor:which_children(grpcbox_services_simple_sup),
ServicePbModules = lists:usort(lists:flatmap(fun proto_modules/1, ServiceSups)),
find(ServicePbModules, Symbol).
proto_modules({_, Pid, _, _}) ->
{registered_name, Name} = erlang:process_info(Pid, registered_name),
[Module || Module <- ets:select(Name, [{#method{proto='$1',
_='_'}, [], ['$1']}])].
find([], _) ->
{error_response, #{error_code => 5,
error_message => "symbol not found"}};
find([M | T], Symbol) ->
case lists:any(fun(F) -> find_symbol(M, F, Symbol) end, [service_name_to_fqbin,
fetch_enum_def]) of
true ->
{file_descriptor_response,
#{file_descriptor_proto => [M:descriptor()]}};
false ->
find(T, Symbol)
end.
find_symbol(M, F, Symbol) ->
try M:F(binary_to_existing_atom(Symbol, utf8)) of
_ ->
true
catch
_:_ ->
false
end.