Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 0 additions & 177 deletions apps/limiter/src/lim_accounting.erl

This file was deleted.

129 changes: 100 additions & 29 deletions apps/limiter/src/lim_config_machine.erl
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@
scope => limit_scope(),
description => description(),
op_behaviour => op_behaviour(),
currency_conversion => currency_conversion()
currency_conversion => currency_conversion(),
finalization_behaviour => finalization_behaviour()
}.

-type op_behaviour() :: #{operation_type() := addition | subtraction}.
-type operation_type() :: invoice_payment_refund.
-type currency_conversion() :: boolean().
-type finalization_behaviour() :: normal | {invertable, session_presence}.

-type lim_id() :: limproto_limiter_thrift:'LimitID'().
-type lim_version() :: dmsl_domain_thrift:'DataRevision'().
Expand Down Expand Up @@ -146,7 +148,8 @@ currency_conversion(_) ->
{ok, [lim_liminator:limit_response()]} | {error, config_error() | {processor(), get_limit_error()}}.
get_values(LimitChanges, LimitContext) ->
do(fun() ->
Changes = unwrap(collect_changes(hold, LimitChanges, LimitContext)),
GroupedChanges = unwrap(collect_grouped_changes(hold, LimitChanges, LimitContext)),
Changes = lists:flatten(maps:values(GroupedChanges)),
Names = lists:map(fun lim_liminator:get_name/1, Changes),
unwrap(lim_liminator:get_values(Names, LimitContext))
end).
Expand All @@ -155,49 +158,106 @@ get_values(LimitChanges, LimitContext) ->
{ok, [lim_liminator:limit_response()]} | {error, config_error() | {processor(), get_limit_error()}}.
get_batch(OperationID, LimitChanges, LimitContext) ->
do(fun() ->
unwrap(
OperationID,
lim_liminator:get(OperationID, unwrap(collect_changes(hold, LimitChanges, LimitContext)), LimitContext)
)
GroupedChanges = unwrap(collect_grouped_changes(hold, LimitChanges, LimitContext)),
F = fun(Group, Changes) ->
OperationIDForGroup = operation_id_for_group(OperationID, Group),
unwrap(OperationID, lim_liminator:get(OperationIDForGroup, Changes, LimitContext))
end,
lists:flatten(maps:values(maps:map(F, GroupedChanges)))
end).

-spec hold_batch(operation_id(), lim_changes(), lim_context()) ->
{ok, [lim_liminator:limit_response()]} | {error, config_error() | {processor(), hold_error()}}.
{ok, [lim_liminator:limit_response()]}
| {error, config_error() | {processor(), hold_error()} | {operation_id(), lim_liminator:invalid_request_error()}}.
hold_batch(OperationID, LimitChanges, LimitContext) ->
do(fun() ->
unwrap(
OperationID,
lim_liminator:hold(OperationID, unwrap(collect_changes(hold, LimitChanges, LimitContext)), LimitContext)
)
GroupedChanges = unwrap(collect_grouped_changes(hold, LimitChanges, LimitContext)),
F = fun(Group, Changes) ->
OperationIDForGroup = operation_id_for_group(OperationID, Group),
unwrap(OperationID, lim_liminator:hold(OperationIDForGroup, Changes, LimitContext))
end,
lists:flatten(maps:values(maps:map(F, GroupedChanges)))
end).

-spec commit_batch(operation_id(), lim_changes(), lim_context()) ->
ok | {error, config_error() | {processor(), commit_error()}}.
ok
| {error, config_error() | {processor(), commit_error()} | {operation_id(), lim_liminator:invalid_request_error()}}.
commit_batch(OperationID, LimitChanges, LimitContext) ->
do(fun() ->
unwrap(
OperationID,
lim_liminator:commit(OperationID, unwrap(collect_changes(commit, LimitChanges, LimitContext)), LimitContext)
)
GroupedChanges = unwrap(collect_grouped_changes(commit, LimitChanges, LimitContext)),
F = fun(Group, Changes) ->
unwrap(
OperationID,
finalize(
OperationID, Group, Changes, LimitContext, fun lim_liminator:commit/3, fun lim_liminator:rollback/3
)
)
end,
_ = maps:map(F, GroupedChanges),
ok
end).

-spec rollback_batch(operation_id(), lim_changes(), lim_context()) ->
ok | {error, config_error() | {processor(), rollback_error()}}.
ok
| {error,
config_error() | {processor(), rollback_error()} | {operation_id(), lim_liminator:invalid_request_error()}}.
rollback_batch(OperationID, LimitChanges, LimitContext) ->
do(fun() ->
unwrap(
OperationID,
lim_liminator:rollback(OperationID, unwrap(collect_changes(hold, LimitChanges, LimitContext)), LimitContext)
)
GroupedChanges = unwrap(collect_grouped_changes(hold, LimitChanges, LimitContext)),
F = fun(Group, Changes) ->
unwrap(
OperationID,
finalize(
OperationID, Group, Changes, LimitContext, fun lim_liminator:rollback/3, fun lim_liminator:commit/3
)
)
end,
_ = maps:map(F, GroupedChanges),
ok
end).

collect_changes(_Stage, [], _LimitContext) ->
{ok, []};
collect_changes(Stage, [LimitChange = #limiter_LimitChange{id = ID, version = Version} | Other], LimitContext) ->
finalize(OperationID, Group, Changes, LimitContext, NormalFun, InvertedFun) ->
OperationIDForGroup = operation_id_for_group(OperationID, Group),
case resolve_group_finalization_behaviour(Group, LimitContext) of
normal -> NormalFun(OperationIDForGroup, Changes, LimitContext);
inverted -> InvertedFun(OperationIDForGroup, Changes, LimitContext)
end.

resolve_group_finalization_behaviour({_, normal}, _) ->
normal;
resolve_group_finalization_behaviour({ContextType, {invertable, session_presence}}, LimitContext) ->
case lim_context:get_value(ContextType, session, LimitContext) of
{ok, undefined} ->
normal;
{ok, _Some} ->
inverted;
{error, {unsupported, _}} ->
%% If context doesn't support session value then we treat it as
%% normal finalization.
normal;
{error, notfound} ->
normal
end.

operation_id_for_group(OperationID, {_, normal}) ->
OperationID;
operation_id_for_group(OperationID, {_, {invertable, session_presence}}) ->
<<OperationID/binary, "/inverted/session-presence">>.

collect_grouped_changes(Stage, LimitChanges, LimitContext) ->
collect_grouped_changes(Stage, LimitChanges, LimitContext, #{}).

collect_grouped_changes(_, [], _, Acc) ->
{ok, Acc};
collect_grouped_changes(Stage, [LimitChange | Other], LimitContext, Acc0) ->
do(fun() ->
#limiter_LimitChange{id = ID, version = Version} = LimitChange,
{Handler, Config} = unwrap(get_handler(ID, Version, LimitContext)),
Change = unwrap(Handler, Handler:make_change(Stage, LimitChange, Config, LimitContext)),
[Change | unwrap(collect_changes(Stage, Other, LimitContext))]
#{context_type := ContextType, finalization_behaviour := FinalizationBehaviour} = Config,
Group = {ContextType, FinalizationBehaviour},
Acc1 = maps:update_with(Group, fun(Changes) -> [Change | Changes] end, [Change], Acc0),
unwrap(collect_grouped_changes(Stage, Other, LimitContext, Acc1))
end).

get_handler(ID, Version, LimitContext) ->
Expand Down Expand Up @@ -503,7 +563,8 @@ unmarshal_limit_config(#domain_LimitConfigObject{
scopes = Scopes,
description = Description,
op_behaviour = OpBehaviour,
currency_conversion = CurrencyConversion
currency_conversion = CurrencyConversion,
finalization_behaviour = FinalizationBehaviour
}
}) ->
genlib_map:compact(#{
Expand All @@ -517,9 +578,17 @@ unmarshal_limit_config(#domain_LimitConfigObject{
scope => maybe_apply(Scopes, fun unmarshal_scope/1),
description => Description,
op_behaviour => maybe_apply(OpBehaviour, fun unmarshal_op_behaviour/1),
currency_conversion => CurrencyConversion =/= undefined
currency_conversion => CurrencyConversion =/= undefined,
finalization_behaviour => unmarshal_finalization_behaviour(FinalizationBehaviour)
}).

unmarshal_finalization_behaviour(undefined) ->
normal;
unmarshal_finalization_behaviour({normal, #limiter_config_Normal{}}) ->
normal;
unmarshal_finalization_behaviour({invertable, {session_presence, #limiter_config_Inversed{}}}) ->
{invertable, session_presence}.

unmarshal_time_range_type({calendar, CalendarType}) ->
{calendar, unmarshal_calendar_time_range_type(CalendarType)};
unmarshal_time_range_type({interval, #limiter_config_TimeRangeTypeInterval{amount = Amount}}) ->
Expand Down Expand Up @@ -619,7 +688,8 @@ unmarshal_config_object_test() ->
type => {turnover, number},
scope => ordsets:from_list([party, shop, {destination_field, [<<"path">>, <<"to">>, <<"field">>]}]),
description => <<"description">>,
currency_conversion => true
currency_conversion => true,
finalization_behaviour => {invertable, session_presence}
},
Object = #domain_LimitConfigObject{
ref = #domain_LimitConfigRef{id = <<"id">>},
Expand All @@ -639,7 +709,8 @@ unmarshal_config_object_test() ->
}}
]),
description = <<"description">>,
currency_conversion = #limiter_config_CurrencyConversion{}
currency_conversion = #limiter_config_CurrencyConversion{},
finalization_behaviour = {invertable, {session_presence, #limiter_config_Inversed{}}}
}
},
?assertEqual(Config, unmarshal_limit_config(Object)).
Expand Down
Loading
Loading