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, eos} -> ok; {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 resulthandle_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)).%% Find the name of the services for a service supervisorservices({_, Pid, _, _}) -> {registered_name, Name} = erlang:process_info(Pid, registered_name), [#{name => Service} || Service <- ets:select(Name, [{#method{key={'$1', '_'}, _='_'}, [], ['$1']}])].file_by_filename(Filename) -> FilenameList = binary_to_list(Filename), {file_descriptor_response, #{file_descriptor_proto => [grpcbox_health_pb:descriptor(FilenameList)]}}.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).%% looks up all protobuf modules generated by gpb related to a service supervisorproto_modules({_, Pid, _, _}) -> {registered_name, Name} = erlang:process_info(Pid, registered_name), [Module || Module <- ets:select(Name, [{#method{proto='$1', _='_'}, [], ['$1']}])].%% check all the fqbin lookup functions for the provided symbolfind([], _) -> {error_response, #{error_code => 5, error_message => "symbol not found"}};find([M | T], Symbol) -> case find_all(fun(F) -> find_symbol(M, F, Symbol) end, [get_proto_by_msg_name_as_fqbin, get_proto_by_service_name_as_fqbin, get_proto_by_enum_name_as_fqbin, get_protos_by_pkg_name_as_fqbin]) of [P | _] -> {file_descriptor_response, #{file_descriptor_proto => [M:descriptor(P)]}}; [] -> find(T, Symbol) end.find_symbol(M, F, Symbol) -> try M:F(Symbol) of Proto -> Proto catch _:_ -> false end.find_all(F, L) -> find_all(F, L, []).find_all(_, [], Acc) -> Acc;find_all(F, [H | T], Acc) -> case F(H) of false -> find_all(F, T, Acc); Proto -> find_all(F, T, [Proto | Acc]) end.