mirror of
https://github.com/valitydev/url-shortener.git
synced 2024-11-06 01:55:19 +00:00
MSPF-320: Introduce CAPI copypaste
This commit is contained in:
parent
7fdb5913ce
commit
79c7768bdf
2
Makefile
2
Makefile
@ -62,7 +62,7 @@ start: submodules
|
||||
devrel: submodules
|
||||
$(REBAR) release
|
||||
|
||||
release: distclean
|
||||
release: submodules distclean generate
|
||||
$(REBAR) as prod release
|
||||
|
||||
clean:
|
||||
|
@ -2,9 +2,16 @@
|
||||
{description, "Url shortener service"},
|
||||
{vsn, "0"},
|
||||
{registered, []},
|
||||
{mod, {shortener, []}},
|
||||
{applications, [
|
||||
kernel,
|
||||
stdlib
|
||||
stdlib,
|
||||
lager,
|
||||
lager_logstash_formatter,
|
||||
genlib,
|
||||
jose,
|
||||
cowboy_cors,
|
||||
swag
|
||||
]},
|
||||
{env, []},
|
||||
{modules, []},
|
||||
|
@ -8,13 +8,13 @@
|
||||
|
||||
%%
|
||||
|
||||
-spec start(normal, any()) ->
|
||||
{ok, pid()} | {error, any()}.
|
||||
-spec start(normal, any()) -> {ok, pid()} | {error, any()}.
|
||||
|
||||
start(_StartType, _StartArgs) ->
|
||||
shortener_sup:start_link().
|
||||
|
||||
-spec stop(any()) ->
|
||||
ok.
|
||||
-spec stop(any()) -> ok.
|
||||
|
||||
stop(_State) ->
|
||||
ok.
|
||||
|
||||
|
47
apps/shortener/src/shortener_sup.erl
Normal file
47
apps/shortener/src/shortener_sup.erl
Normal file
@ -0,0 +1,47 @@
|
||||
-module(shortener_sup).
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
%% API
|
||||
-export([start_link/0]).
|
||||
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
%% API
|
||||
|
||||
-spec start_link() -> {ok, pid()} | {error, {already_started, pid()}}.
|
||||
|
||||
start_link() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
%% Supervisor callbacks
|
||||
|
||||
-spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
|
||||
|
||||
init([]) ->
|
||||
%% AuthorizerSpecs = get_authorizer_child_specs(),
|
||||
{LogicHandler, LogicHandlerSpecs} = get_logic_handler_info(),
|
||||
SwaggerSpec = shortener_swagger_server:child_spec(LogicHandler),
|
||||
{ok, {
|
||||
{one_for_all, 0, 1},
|
||||
LogicHandlerSpecs ++ [SwaggerSpec]
|
||||
}}.
|
||||
|
||||
%%
|
||||
|
||||
%% -spec get_authorizer_child_specs() -> [supervisor:child_spec()].
|
||||
|
||||
%% get_authorizer_child_specs() ->
|
||||
%% Authorizers = genlib_app:env(shortener, authorizers, #{}),
|
||||
%% [get_authorizer_child_spec(jwt, maps:get(jwt, Authorizers))].
|
||||
|
||||
%% -spec get_authorizer_child_spec(Name :: atom(), Options :: #{}) -> supervisor:child_spec().
|
||||
|
||||
%% get_authorizer_child_spec(jwt, Options) ->
|
||||
%% shortener_authorizer_jwt:get_child_spec(Options).
|
||||
|
||||
-spec get_logic_handler_info() -> {Handler :: atom(), [Spec :: supervisor:child_spec()] | []} .
|
||||
|
||||
get_logic_handler_info() ->
|
||||
{shortener_handler, []}.
|
155
apps/shortener/src/shortener_swagger_server.erl
Normal file
155
apps/shortener/src/shortener_swagger_server.erl
Normal file
@ -0,0 +1,155 @@
|
||||
-module(shortener_swagger_server).
|
||||
|
||||
-export([child_spec/1]).
|
||||
-export([request_hook/1]).
|
||||
-export([response_hook/4]).
|
||||
|
||||
-define(APP, shortener).
|
||||
-define(DEFAULT_ACCEPTORS_POOLSIZE, 100).
|
||||
-define(DEFAULT_IP_ADDR, "::").
|
||||
-define(DEFAULT_PORT, 8080).
|
||||
|
||||
-define(START_TIME_TAG, processing_start_time).
|
||||
|
||||
-spec child_spec(module()) -> supervisor:child_spec().
|
||||
|
||||
child_spec(LogicHandler) ->
|
||||
{Transport, TransportOpts} = get_socket_transport(),
|
||||
CowboyOpts = get_cowboy_config(LogicHandler),
|
||||
AcceptorsPool = genlib_app:env(?APP, acceptors_poolsize, ?DEFAULT_ACCEPTORS_POOLSIZE),
|
||||
ranch:child_spec(?MODULE, AcceptorsPool,
|
||||
Transport, TransportOpts, cowboy_protocol, CowboyOpts).
|
||||
|
||||
get_socket_transport() ->
|
||||
{ok, IP} = inet:parse_address(genlib_app:env(?APP, ip, ?DEFAULT_IP_ADDR)),
|
||||
Port = genlib_app:env(?APP, port, ?DEFAULT_PORT),
|
||||
{ranch_tcp, [{ip, IP}, {port, Port}]}.
|
||||
|
||||
get_cowboy_config(LogicHandler) ->
|
||||
Dispatch = cowboy_router:compile(swag_router:get_paths(LogicHandler)),
|
||||
[
|
||||
{env, [
|
||||
{dispatch, Dispatch},
|
||||
{cors_policy, shortener_cors_policy}
|
||||
]},
|
||||
{middlewares, [
|
||||
cowboy_router,
|
||||
cowboy_cors,
|
||||
cowboy_handler
|
||||
]},
|
||||
{onrequest, fun ?MODULE:request_hook/1},
|
||||
{onresponse, fun ?MODULE:response_hook/4}
|
||||
].
|
||||
|
||||
-spec request_hook(cowboy_req:req()) ->
|
||||
cowboy_req:req().
|
||||
|
||||
request_hook(Req) ->
|
||||
cowboy_req:set_meta(?START_TIME_TAG, genlib_time:ticks(), Req).
|
||||
|
||||
-spec response_hook(cowboy:http_status(), cowboy:http_headers(), iodata(), cowboy_req:req()) ->
|
||||
cowboy_req:req().
|
||||
|
||||
response_hook(Code, Headers, _, Req) ->
|
||||
try
|
||||
{Code1, Headers1, Req1} = handle_response(Code, Headers, Req),
|
||||
_ = log_access(Code1, Headers1, Req1),
|
||||
Req1
|
||||
catch
|
||||
Class:Reason ->
|
||||
Stack = genlib_format:format_stacktrace(erlang:get_stacktrace(), [newlines]),
|
||||
_ = lager:warning(
|
||||
"Response hook failed for: [~p, ~p, ~p]~nwith: ~p:~p~nstacktrace: ~ts",
|
||||
[Code, Headers, Req, Class, Reason, Stack]
|
||||
),
|
||||
Req
|
||||
end.
|
||||
|
||||
handle_response(Code, Headers, Req) when Code >= 500 ->
|
||||
send_oops_resp(Code, Headers, get_oops_body_safe(Code), Req);
|
||||
handle_response(Code, Headers, Req) ->
|
||||
{Code, Headers, Req}.
|
||||
|
||||
%% cowboy_req:reply/4 has a faulty spec in case of response body fun.
|
||||
-dialyzer({[no_contracts, no_fail_call], send_oops_resp/4}).
|
||||
|
||||
send_oops_resp(Code, Headers, undefined, Req) ->
|
||||
{Code, Headers, Req};
|
||||
send_oops_resp(Code, Headers, File, Req) ->
|
||||
FileSize = filelib:file_size(File),
|
||||
F = fun(Socket, Transport) ->
|
||||
case Transport:sendfile(Socket, File) of
|
||||
{ok, _} ->
|
||||
ok;
|
||||
{error, Error} ->
|
||||
_ = lager:warning("Failed to send oops body: ~p", [Error]),
|
||||
ok
|
||||
end
|
||||
end,
|
||||
Headers1 = lists:foldl(
|
||||
fun({K, V}, Acc) -> lists:keystore(K, 1, Acc, {K, V}) end,
|
||||
Headers,
|
||||
[
|
||||
{<<"content-type">>, <<"text/plain; charset=utf-8">>},
|
||||
{<<"content-length">>, integer_to_list(FileSize)}
|
||||
]
|
||||
),
|
||||
{ok, Req1} = cowboy_req:reply(Code, Headers1, {FileSize, F}, Req),
|
||||
{Code, Headers1, Req1}.
|
||||
|
||||
get_oops_body_safe(Code) ->
|
||||
try get_oops_body(Code)
|
||||
catch
|
||||
Error:Reason ->
|
||||
_ = lager:warning("Invalid oops body config for code: ~p. Error: ~p:~p", [Code, Error, Reason]),
|
||||
undefined
|
||||
end.
|
||||
|
||||
get_oops_body(Code) ->
|
||||
genlib_map:get(Code, genlib_app:env(?APP, oops_bodies, #{}), undefined).
|
||||
|
||||
log_access(Code, Headers, Req) ->
|
||||
{Method, _} = cowboy_req:method(Req),
|
||||
{Path, _} = cowboy_req:path(Req),
|
||||
{ReqLen, _} = cowboy_req:body_length(Req),
|
||||
{ReqId, _} = cowboy_req:header(<<"x-request-id">>, Req, undefined),
|
||||
RemAddr = get_remote_addr(Req),
|
||||
RespLen = get_response_len(Headers),
|
||||
Duration = get_request_duration(Req),
|
||||
ReqMeta = [
|
||||
{remote_addr, RemAddr},
|
||||
{request_method, Method},
|
||||
{request_path, Path},
|
||||
{request_length, ReqLen},
|
||||
{response_length, RespLen},
|
||||
{request_time, Duration},
|
||||
{'http_x-request-id', ReqId},
|
||||
{status, Code}
|
||||
],
|
||||
Meta = orddict:merge(fun(_Key, New, _Old) -> New end, ReqMeta, lager:md()),
|
||||
%% Call lager:log/5 here directly in order to pass request metadata (fused into
|
||||
%% lager metadata) without storing it in a process dict via lager:md/1.
|
||||
lager:log(shortener_access_lager_event, info, Meta, "", []).
|
||||
|
||||
get_remote_addr(Req) ->
|
||||
case swag_handler_api:determine_peer(Req) of
|
||||
{{ok, #{ip_address := IP}}, _} ->
|
||||
genlib:to_binary(inet:ntoa(IP));
|
||||
{_, _} ->
|
||||
undefined
|
||||
end.
|
||||
get_request_duration(Req) ->
|
||||
case cowboy_req:meta(?START_TIME_TAG, Req) of
|
||||
{undefined, _} ->
|
||||
undefined;
|
||||
{StartTime, _} ->
|
||||
(genlib_time:ticks() - StartTime) / 1000000
|
||||
end.
|
||||
|
||||
get_response_len(Headers) ->
|
||||
case lists:keyfind(<<"content-length">>, 1, Headers) of
|
||||
{_, Len} ->
|
||||
genlib:to_int(Len);
|
||||
false ->
|
||||
undefined
|
||||
end.
|
41
config/sys.config
Normal file
41
config/sys.config
Normal file
@ -0,0 +1,41 @@
|
||||
[
|
||||
{lager, [
|
||||
{error_logger_hwm, 600},
|
||||
{log_root, "/var/log/shortener"},
|
||||
{handlers, [
|
||||
{lager_console_backend, debug},
|
||||
{lager_file_backend, [
|
||||
{file, "console.json"},
|
||||
{level, debug},
|
||||
{formatter, lager_logstash_formatter}
|
||||
]}
|
||||
]},
|
||||
{extra_sinks, [
|
||||
{shortener_access_lager_event, [
|
||||
{handlers, [
|
||||
{lager_file_backend, [
|
||||
{file, "access_log.json"},
|
||||
{level, info},
|
||||
{formatter, lager_logstash_formatter}
|
||||
]}
|
||||
]},
|
||||
{async_threshold, 20},
|
||||
{async_threshold_window, 5}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
|
||||
{shortener, [
|
||||
{ip, "::"},
|
||||
{port, 8080},
|
||||
{authorizers, #{
|
||||
jwt => #{
|
||||
signee => capi,
|
||||
keyset => #{
|
||||
keycloak => {pem_file, "var/keys/keycloak/public.pem"},
|
||||
capi => {pem_file, "var/keys/capi/private.pem"}
|
||||
}
|
||||
}
|
||||
}}
|
||||
]}
|
||||
].
|
6
config/vm.args
Normal file
6
config/vm.args
Normal file
@ -0,0 +1,6 @@
|
||||
-sname shortener
|
||||
|
||||
-setcookie shortener_cookie
|
||||
|
||||
+K true
|
||||
+A 10
|
21
rebar.config
21
rebar.config
@ -27,7 +27,26 @@
|
||||
]}.
|
||||
|
||||
% Common project dependencies.
|
||||
{deps, []}.
|
||||
{deps, [
|
||||
{cowboy, "1.0.4"},
|
||||
{jose, "1.7.9"},
|
||||
{lager, "3.2.4"},
|
||||
{genlib,
|
||||
{git, "https://github.com/rbkmoney/genlib.git",
|
||||
{branch, "master"}
|
||||
}
|
||||
},
|
||||
{lager_logstash_formatter,
|
||||
{git, "git@github.com:rbkmoney/lager_logstash_formatter.git",
|
||||
{branch, "master"}
|
||||
}
|
||||
},
|
||||
{cowboy_cors,
|
||||
{git, "https://github.com/danielwhite/cowboy_cors.git",
|
||||
{branch, "master"}
|
||||
}
|
||||
}
|
||||
]}.
|
||||
|
||||
{xref_checks, [
|
||||
undefined_function_calls,
|
||||
|
32
rebar.lock
32
rebar.lock
@ -1,14 +1,44 @@
|
||||
{"1.1.0",
|
||||
[{<<"jesse">>,
|
||||
[{<<"base64url">>,{pkg,<<"base64url">>,<<"0.0.1">>},1},
|
||||
{<<"cowboy">>,{pkg,<<"cowboy">>,<<"1.0.4">>},0},
|
||||
{<<"cowboy_cors">>,
|
||||
{git,"https://github.com/danielwhite/cowboy_cors.git",
|
||||
{ref,"392f5804b63fff2bd0fda67671d5b2fbe0badd37"}},
|
||||
0},
|
||||
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"1.0.2">>},1},
|
||||
{<<"genlib">>,
|
||||
{git,"https://github.com/rbkmoney/genlib.git",
|
||||
{ref,"7fc1ca1a57dbe2b8b837951095e314c32afd6c9a"}},
|
||||
0},
|
||||
{<<"goldrush">>,{pkg,<<"goldrush">>,<<"0.1.9">>},1},
|
||||
{<<"jesse">>,
|
||||
{git,"git@github.com:rbkmoney/jesse.git",
|
||||
{ref,"39105922d1ce5834383d8e8aa877c60319b9834a"}},
|
||||
0},
|
||||
{<<"jose">>,{pkg,<<"jose">>,<<"1.7.9">>},0},
|
||||
{<<"jsx">>,{pkg,<<"jsx">>,<<"2.8.2">>},0},
|
||||
{<<"lager">>,{pkg,<<"lager">>,<<"3.2.4">>},0},
|
||||
{<<"lager_logstash_formatter">>,
|
||||
{git,"git@github.com:rbkmoney/lager_logstash_formatter.git",
|
||||
{ref,"83a0f21c03dacbd876c7289435f369f573c749b1"}},
|
||||
0},
|
||||
{<<"parse_trans">>,
|
||||
{git,"https://github.com/rbkmoney/parse_trans.git",
|
||||
{ref,"5ee45f5bfa6c04329bea3281977b774f04c89f11"}},
|
||||
0},
|
||||
{<<"pooler">>,{pkg,<<"pooler">>,<<"1.5.0">>},0},
|
||||
{<<"ranch">>,{pkg,<<"ranch">>,<<"1.4.0">>},1},
|
||||
{<<"rfc3339">>,{pkg,<<"rfc3339">>,<<"0.2.1">>},0}]}.
|
||||
[
|
||||
{pkg_hash,[
|
||||
{<<"base64url">>, <<"36A90125F5948E3AFD7BE97662A1504B934DD5DAC78451CA6E9ABF85A10286BE">>},
|
||||
{<<"cowboy">>, <<"A324A8DF9F2316C833A470D918AAF73AE894278B8AA6226CE7A9BF699388F878">>},
|
||||
{<<"cowlib">>, <<"9D769A1D062C9C3AC753096F868CA121E2730B9A377DE23DEC0F7E08B1DF84EE">>},
|
||||
{<<"goldrush">>, <<"F06E5D5F1277DA5C413E84D5A2924174182FB108DABB39D5EC548B27424CD106">>},
|
||||
{<<"jose">>, <<"9DC5A14AB62DB4E41677FCC97993752562FB57AD0B8BA062589682EDD3ACB91F">>},
|
||||
{<<"jsx">>, <<"7ACC7D785B5ABE8A6E9ADBDE926A24E481F29956DD8B4DF49E3E4E7BCC92A018">>},
|
||||
{<<"lager">>, <<"A6DEB74DAE7927F46BD13255268308EF03EB206EC784A94EAF7C1C0F3B811615">>},
|
||||
{<<"pooler">>, <<"0FD4BE5D2976E6A2E9A1617623031758C26F200C1FCA89E4A3C542747BEC6371">>},
|
||||
{<<"ranch">>, <<"10272F95DA79340FA7E8774BA7930B901713D272905D0012B06CA6D994F8826B">>},
|
||||
{<<"rfc3339">>, <<"0F037D3385A724BC78C732CF83384B2CC7A643F9ADDBF3FDB38A4BC6A6CD0069">>}]}
|
||||
].
|
||||
|
Loading…
Reference in New Issue
Block a user