130 lines
4.3 KiB
Erlang
130 lines
4.3 KiB
Erlang
-module(routeguide_route_guide).
|
|
|
|
-include_lib("grpcbox/include/grpcbox.hrl").
|
|
|
|
-export([get_feature/2,
|
|
list_features/2,
|
|
record_route/2,
|
|
route_chat/2,
|
|
generate_error/2,
|
|
streaming_generate_error/2]).
|
|
|
|
-type route_summary() ::
|
|
#{point_count => integer(),
|
|
feature_count => integer(),
|
|
distance => integer(),
|
|
elapsed_time => integer()}.
|
|
|
|
-type point() ::
|
|
#{latitude => integer(),
|
|
longitude => integer()}.
|
|
|
|
-type rectangle() ::
|
|
#{lo => point(),
|
|
hi => point()}.
|
|
|
|
-type route_note() ::
|
|
#{location => point(),
|
|
message => string()}.
|
|
|
|
-type feature() ::
|
|
#{name => string(),
|
|
location => point()}.
|
|
|
|
-spec get_feature(Ctx :: ctx:ctx(), Message :: point()) -> {ok, feature(), ctx:ctx()}.
|
|
get_feature(Ctx, Message) ->
|
|
Feature = #{name => find_point(Message, data()),
|
|
location => Message},
|
|
{ok, Feature, Ctx}.
|
|
|
|
-spec list_features(Message::rectangle(), GrpcStream :: grpcbox_stream:t()) -> ok.
|
|
list_features(_Message, GrpcStream) ->
|
|
grpcbox_stream:add_headers([{<<"info">>, <<"this is a test-implementation">>}], GrpcStream),
|
|
grpcbox_stream:send(#{name => <<"Tour Eiffel">>,
|
|
location => #{latitude => 3,
|
|
longitude => 5}}, GrpcStream),
|
|
grpcbox_stream:send(#{name => <<"Louvre">>,
|
|
location => #{latitude => 4,
|
|
longitude => 5}}, GrpcStream),
|
|
|
|
grpcbox_stream:add_trailers([{<<"nr_of_points_sent">>, <<"2">>}], GrpcStream),
|
|
ok.
|
|
|
|
-spec record_route(reference(), GrpcStream :: grpcbox_stream:t()) -> {ok, route_summary(), grpcbox_stream:t()}.
|
|
record_route(Ref, GrpcStream) ->
|
|
record_route(Ref, #{t_start => erlang:system_time(1),
|
|
acc => []}, GrpcStream).
|
|
|
|
record_route(Ref, Data=#{t_start := T0, acc := Points}, GrpcStream) ->
|
|
receive
|
|
{Ref, eos} ->
|
|
%% receiving 'eos' tells us that we need to return a result.
|
|
{ok, #{elapsed_time => erlang:system_time(1) - T0,
|
|
point_count => length(Points),
|
|
feature_count => count_features(Points),
|
|
distance => distance(Points)}, GrpcStream};
|
|
{Ref, Point} ->
|
|
record_route(Ref, Data#{acc => [Point | Points]}, GrpcStream)
|
|
end.
|
|
|
|
-spec route_chat(reference(), GrpcStream :: grpcbox_stream:t()) -> ok.
|
|
route_chat(Ref, GrpcStream) ->
|
|
route_chat(Ref, [], GrpcStream).
|
|
|
|
route_chat(Ref, Data, GrpcStream) ->
|
|
receive
|
|
{Ref, eos} ->
|
|
ok;
|
|
{Ref, #{location := Location} = P} ->
|
|
Messages = proplists:get_all_values(Location, Data),
|
|
[grpcbox_stream:send(Message, GrpcStream) || Message <- Messages],
|
|
route_chat(Ref, [{Location, P} | Data], GrpcStream)
|
|
end.
|
|
|
|
-spec generate_error(Ctx :: ctx:ctx(), Message :: map()) -> grpcbox_stream:grpc_extended_error_response().
|
|
generate_error(_Ctx, _Message) ->
|
|
{
|
|
grpc_extended_error, #{
|
|
status => ?GRPC_STATUS_INTERNAL,
|
|
message => <<"error_message">>,
|
|
trailers => #{
|
|
<<"generate_error_trailer">> => <<"error_trailer">>
|
|
}
|
|
}
|
|
}.
|
|
|
|
-spec streaming_generate_error(Message :: map(), GrpcStream :: grpcbox_stream:t()) -> no_return().
|
|
streaming_generate_error(_Message, _GrpcStream) ->
|
|
exit(
|
|
{
|
|
grpc_extended_error, #{
|
|
status => ?GRPC_STATUS_INTERNAL,
|
|
message => <<"error_message">>,
|
|
trailers => #{
|
|
<<"generate_error_trailer">> => <<"error_trailer">>
|
|
}
|
|
}
|
|
}
|
|
).
|
|
|
|
%% Supporting functions
|
|
|
|
data() ->
|
|
case file:read_file("test/otel_interceptor_SUITE_data/route_guide_db.json") of
|
|
{ok, Json} ->
|
|
jsx:decode(Json, [return_maps, {labels, atom}]);
|
|
{error, enoent} ->
|
|
{ok, Json} = file:read_file("../../../../test/otel_interceptor_SUITE_data/route_guide_db.json"),
|
|
jsx:decode(Json, [return_maps, {labels, atom}])
|
|
end.
|
|
|
|
find_point(_Location, []) ->
|
|
"";
|
|
find_point(Location, [#{location := Location, name := Name} | _]) ->
|
|
Name;
|
|
find_point(Location, [_ | T]) ->
|
|
find_point(Location, T).
|
|
|
|
count_features(_) -> 42.
|
|
distance(_) -> 42.
|