From c79e6e24f40a8da09fdcd0ccc7eb4f8c9a18dff2 Mon Sep 17 00:00:00 2001 From: Andrey Fadeev Date: Thu, 14 Jun 2018 21:38:59 +0300 Subject: [PATCH] Second untested approach to session machines --- apps/ff_withdraw/src/ff_destination.erl | 3 +- apps/fistful/src/ff_adpt.erl | 15 ++ apps/fistful/src/ff_adpt_client.erl | 143 ++++++++++++++++++ ...achine.erl => ff_adpt_session_machine.erl} | 19 +-- apps/fistful/src/ff_adpt_withdrawal.erl | 22 +++ apps/fistful/src/ff_currency.erl | 1 + apps/fistful/src/ff_transfer.erl | 1 + apps/fistful/src/ff_wthadpt.erl | 31 ---- apps/fistful/src/ff_wthadpt_client.erl | 67 -------- 9 files changed, 194 insertions(+), 108 deletions(-) create mode 100644 apps/fistful/src/ff_adpt.erl create mode 100644 apps/fistful/src/ff_adpt_client.erl rename apps/fistful/src/{ff_wth_session_machine.erl => ff_adpt_session_machine.erl} (89%) create mode 100644 apps/fistful/src/ff_adpt_withdrawal.erl delete mode 100644 apps/fistful/src/ff_wthadpt.erl delete mode 100644 apps/fistful/src/ff_wthadpt_client.erl diff --git a/apps/ff_withdraw/src/ff_destination.erl b/apps/ff_withdraw/src/ff_destination.erl index 39ae17a..29294e6 100644 --- a/apps/ff_withdraw/src/ff_destination.erl +++ b/apps/ff_withdraw/src/ff_destination.erl @@ -26,7 +26,8 @@ -type destination() :: #{ wallet := wallet(), resource := resource(), - status := status() + status := status(), + masked_pan := binary() }. -export_type([destination/0]). diff --git a/apps/fistful/src/ff_adpt.erl b/apps/fistful/src/ff_adpt.erl new file mode 100644 index 0000000..bc5734b --- /dev/null +++ b/apps/fistful/src/ff_adpt.erl @@ -0,0 +1,15 @@ +%%% Withdrawal adapter generic +-module(ff_adpt). + +%% +%% Types +%% + +-type adapter() :: atom(). +-type adapter_state() :: any(). + +-type withdrawal() :: ff_adpt_withdrawal:withdrawal(). + +-export_type([adapter/0]). +-export_type([withdrawal/0]). +-export_type([adapter_state/0]). diff --git a/apps/fistful/src/ff_adpt_client.erl b/apps/fistful/src/ff_adpt_client.erl new file mode 100644 index 0000000..f24de3c --- /dev/null +++ b/apps/fistful/src/ff_adpt_client.erl @@ -0,0 +1,143 @@ +%%% Client for adapter for withdrawal provider +-module(ff_adpt_client). + +-include_lib("dmsl/include/dmsl_domain_thrift.hrl"). +-include_lib("dmsl/include/dmsl_withdrawals_provider_adapter_thrift.hrl"). + +%% API +-export([process_withdrawal/5]). + +%% +%% Internal types +%% + +-type id() :: machinery:id(). +-type identity_id() :: id(). + +-type withdrawal() :: ff_adpt_withdrawal:withdrawal(). +-type destination() :: ff_adpt_withdrawal:destination(). +-type cash() :: ff_adpt_withdrawal:cash(). + +-type adapter() :: ff_wthadpt:adapter(). +-type intent() :: {finish, status()} | {sleep, timer()}. +-type status() :: {success, trx_info()} | {failure, ff_adpt:failure()}. +-type timer() :: dmsl_base_thrift:'Timer'(). +-type trx_info() :: dmsl_domain_thrift:'TransactionInfo'(). +-type adapter_state() :: ff_adpt:adapter_state(). +-type process_result() :: {ok, intent(), adapter_state()} | {ok, intent()}. + +-type domain_withdrawal() :: dmsl_withdrawals_provider_adapter_thrift:'Withdrawal'(). +-type domain_cash() :: dmsl_withdrawals_provider_adapter_thrift:'Cash'(). +-type domain_currency() :: dmsl_domain_thrift:'Currency'(). +-type domain_destination() :: dmsl_withdrawals_provider_adapter_thrift:'Destination'(). +-type domain_identity() :: dmsl_withdrawals_provider_adapter_thrift:'Identity'(). + +-type backend() :: machinery:backend(_). + +%% +%% API +%% + +-spec process_withdrawal(Adapter, Withdrawal, ASt, AOpt, Be) -> process_result() when + Adapter :: adapter(), + Withdrawal :: withdrawal(), + ASt :: adapter_state(), + AOpt :: map(), + Be :: backend(). +process_withdrawal(Adapter, Withdrawal, ASt, AOpt, Be) -> + DomainWithdrawal = build_and_encode_withdrawal(Withdrawal, Be), + {ok, Result} = call(Adapter, 'ProcessWithdrawal', [DomainWithdrawal, ASt, AOpt]), + decode_result(Result). + +%% +%% Internals +%% + +call(Adapter, Function, Args) -> + Request = {{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'}, Function, Args}, + ff_woody_client:call(Adapter, Request). + +%% Encoders + +-spec build_and_encode_withdrawal(Withdrawal, Be) -> domain_withdrawal() when + Withdrawal :: withdrawal(), + Be :: backend(). +build_and_encode_withdrawal(Withdrawal, Be) -> + #{ + id := WId, + cash := Cash, + destination := Dest, + sender := Sender, + receiver := Receiver + } = Withdrawal, + #wthadpt_Withdrawal{ + id = WId, + body = encode_body(Cash), + destination = encode_destination(Dest), + sender = fetch_and_encode_identity(Sender, Be), + receiver = fetch_and_encode_identity(Receiver, Be) + }. + +-spec encode_body(cash()) -> domain_cash(). +encode_body({Amount, CurrencyId}) -> + Currency = ff_currency:get(CurrencyId), + DomainCurrency = encode_currency(Currency), + #wthadpt_Cash{amount = Amount, currency = DomainCurrency}. + +-spec encode_currency(ff_currency:currency()) -> domain_currency(). +encode_currency(#{ + name := Name, + symcode := Symcode, + numcode := Numcode, + exponent := Exponent +}) -> + #domain_Currency{ + name = Name, + symbolic_code = Symcode, + numeric_code = Numcode, + exponent = Exponent + }. + +-spec encode_destination(destination()) -> domain_destination(). +encode_destination(Destination) -> + #{resource := Resource} = Destination, + #{ + token := Token, + payment_system := PaymentSystem, + bin := Bin, + masked_pan := MaskedPan + } = Resource, + {bank_card, #domain_BankCard{ + token = Token, + payment_system = PaymentSystem, + bin = Bin, + masked_pan = MaskedPan + }}. + +-spec fetch_and_encode_identity + (identity_id(), backend()) -> domain_identity(); + (undefined, backend()) -> undefined. +fetch_and_encode_identity(undefined, _Be) -> + undefined; +fetch_and_encode_identity(IdentityId, _Be) -> + % {ok, Identity} = ff_identity:get(IdentityId, Be), + % TODO: Add documents and contract fields + #wthdm_Identity{ + id = IdentityId + }. + +-spec decode_result(dmsl_withdrawals_provider_adapter_thrift:'ProcessResult'()) -> process_result(). +decode_result(#wthadpt_ProcessResult{intent = Intent, next_state = undefined}) -> + {ok, decode_intent(Intent)}; +decode_result(#wthadpt_ProcessResult{intent = Intent, next_state = NextState}) -> + {ok, decode_intent(Intent), NextState}. + +%% Decoders + +-spec decode_intent(dmsl_withdrawals_provider_adapter_thrift:'Intent'()) -> intent(). +decode_intent({finish, #wthadpt_FinishIntent{status = {success, #wthadpt_Success{trx_info = TrxInfo}}}}) -> + {finish, {success, TrxInfo}}; +decode_intent({finish, #wthadpt_FinishIntent{status = {failure, Failure}}}) -> + {finish, {failure, Failure}}; +decode_intent({sleep, #wthadpt_SleepIntent{timer = Timer}}) -> + {sleep, Timer}. diff --git a/apps/fistful/src/ff_wth_session_machine.erl b/apps/fistful/src/ff_adpt_session_machine.erl similarity index 89% rename from apps/fistful/src/ff_wth_session_machine.erl rename to apps/fistful/src/ff_adpt_session_machine.erl index c096196..d209d92 100644 --- a/apps/fistful/src/ff_wth_session_machine.erl +++ b/apps/fistful/src/ff_adpt_session_machine.erl @@ -1,7 +1,7 @@ %%% %%% Withdrawal session machine %%% --module(ff_wth_session_machine). +-module(ff_adpt_session_machine). -behaviour(machinery). %% API @@ -20,11 +20,11 @@ -type session() :: #{ id => id(), status => session_status(), - withdrawal => ff_wthadpt:withdrawal(), + withdrawal => withdrawal(), adapter => adapter() }. --type session_result() :: {success, trx_info()} | {failed, ff_wthadpt:failure()}. +-type session_result() :: {success, trx_info()} | {failed, ff_adpt:failure()}. -type session_status() :: new | active @@ -32,10 +32,10 @@ -type ev() :: {created, session()} | started - | {next_state, ff_wthadpt:adapter_state()} + | {next_state, ff_adpt:adapter_state()} | {finished, session_result()}. --type adapter() :: {ff_wthadpt:adapter(), map()}. +-type adapter() :: {ff_adpt:adapter(), map()}. %% %% Internal types @@ -47,6 +47,7 @@ -type auxst() :: #{}. +-type withdrawal() :: ff_adpt_withdrawal:withdrawal(). -type machine() :: machinery:machine(ev(), auxst()). -type result() :: machinery:result(ev(), auxst()). -type handler_opts() :: machinery:handler_opts(). @@ -56,7 +57,7 @@ -type st() :: #{ session => session(), - adapter_state => ff_wthadpt:adapter_state() + adapter_state => ff_adpt:adapter_state() }. %% Pipeline @@ -71,7 +72,7 @@ Ns :: namespace(), Id :: id(), Adapter :: adapter(), - Withdrawal :: ff_wthadpt:withdrawal(), + Withdrawal :: withdrawal(), Be :: backend(), Error :: {error, exists}. create(Ns, Id, Adapter, Withdrawal, Be) -> @@ -121,7 +122,7 @@ process_session(#{session := #{status := active} = Session} = St) -> withdrawal := Withdrawal } = Session, ASt = maps:get(adapter_state, St, []), - case ff_wthadpt_client:process_withdrawal(Adapter, Withdrawal, ASt, AdapterOpts) of + case ff_adpt_client:process_withdrawal(Adapter, Withdrawal, ASt, AdapterOpts) of {ok, Intent, NextState} -> process_intent(Intent, NextState); {ok, Intent} -> @@ -145,7 +146,7 @@ process_intent({sleep, Timer}) -> %% --spec create_session(id(), adapter(), ff_wthadpt:withdrawal()) -> session(). +-spec create_session(id(), adapter(), ff_adpt:withdrawal()) -> session(). create_session(Id, Adapter, Withdrawal) -> #{ id => Id, diff --git a/apps/fistful/src/ff_adpt_withdrawal.erl b/apps/fistful/src/ff_adpt_withdrawal.erl new file mode 100644 index 0000000..7c4933f --- /dev/null +++ b/apps/fistful/src/ff_adpt_withdrawal.erl @@ -0,0 +1,22 @@ +-module(ff_adpt_withdrawal). + +%% +%% Types +%% + +-type destination() :: ff_destination:destination(). +-type identity() :: ff_identity:identity(). +-type cash() :: ff_transfer:body(). + +-type withdrawal() :: #{ + id => binary(), + destination => destination(), + cash => cash(), + sender => identity() | undefined, + receiver => identity() | undefined +}. + +-export_type([destination/0]). +-export_type([identity/0]). +-export_type([cash/0]). +-export_type([withdrawal/0]). diff --git a/apps/fistful/src/ff_currency.erl b/apps/fistful/src/ff_currency.erl index 3370c11..490a4ee 100644 --- a/apps/fistful/src/ff_currency.erl +++ b/apps/fistful/src/ff_currency.erl @@ -19,6 +19,7 @@ }. -export_type([id/0]). +-export_type([currency/0]). -export([get/1]). diff --git a/apps/fistful/src/ff_transfer.erl b/apps/fistful/src/ff_transfer.erl index ab6682d..bcd29b3 100644 --- a/apps/fistful/src/ff_transfer.erl +++ b/apps/fistful/src/ff_transfer.erl @@ -32,6 +32,7 @@ }. -export_type([transfer/0]). +-export_type([posting/0]). -export_type([status/0]). -export([trxid/1]). diff --git a/apps/fistful/src/ff_wthadpt.erl b/apps/fistful/src/ff_wthadpt.erl deleted file mode 100644 index fc6e424..0000000 --- a/apps/fistful/src/ff_wthadpt.erl +++ /dev/null @@ -1,31 +0,0 @@ -%%% Withdrawal generic --module(ff_wthadpt). - -%% -%% Types -%% - --type adapter() :: atom(). --type wth_id() :: binary(). --type destination() :: dmsl_withdrawals_provider_adapter_thrift:'Destination'(). --type identity() :: dmsl_withdrawals_provider_adapter_thrift:'Identity'(). --type cash() :: dmsl_withdrawals_provider_adapter_thrift:'Cash'(). --type failure() :: dmsl_domain_thrift:'Failure'(). --type adapter_state() :: any(). - --type withdrawal() :: #{ - id => wth_id(), - body => cash(), - destination => destination(), - sender => identity() | indefined, - receiver => identity() | indefined -}. - --export_type([adapter/0]). --export_type([wth_id/0]). --export_type([destination/0]). --export_type([identity/0]). --export_type([cash/0]). --export_type([failure/0]). --export_type([withdrawal/0]). --export_type([adapter_state/0]). diff --git a/apps/fistful/src/ff_wthadpt_client.erl b/apps/fistful/src/ff_wthadpt_client.erl deleted file mode 100644 index 74b7955..0000000 --- a/apps/fistful/src/ff_wthadpt_client.erl +++ /dev/null @@ -1,67 +0,0 @@ -%%% Client for adapter for withdrawal provider --module(ff_wthadpt_client). - --include_lib("dmsl/include/dmsl_withdrawals_provider_adapter_thrift.hrl"). - -%% API --export([process_withdrawal/4]). - -%% -%% Internal types -%% - --type withdrawal() :: ff_wthadpt:withdrawal(). --type adapter() :: ff_wthadpt:adapter(). --type intent() :: {finish, status()} | {sleep, timer()}. --type status() :: {success, trx_info()} | {failure, ff_wthadpt:failure()}. --type timer() :: dmsl_base_thrift:'Timer'(). --type trx_info() :: dmsl_domain_thrift:'TransactionInfo'(). --type adapter_state() :: ff_wthadpt:adapter_state(). --type process_result() :: {ok, intent(), adapter_state()} | {ok, intent()}. - -%% -%% API -%% - --spec process_withdrawal(adapter(), withdrawal(), adapter_state(), map()) -> process_result(). -process_withdrawal(Adapter, Withdrawal, State, Options) -> - {ok, Result} = call(Adapter, 'ProcessWithdrawal', [encode_withdrawal(Withdrawal), State, Options]), - decode_result(Result). - -%% -%% Internals -%% - -call(Adapter, Function, Args) -> - Request = {{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'}, Function, Args}, - ff_woody_client:call(Adapter, Request). - --spec encode_withdrawal(withdrawal()) -> dmsl_withdrawals_provider_adapter_thrift:'Withdrawal'(). -encode_withdrawal(#{ - id := Id, - body := Body, - destination := Destination, - sender := Sender, - receiver := Receiver -}) -> - #wthadpt_Withdrawal{ - id = Id, - body = Body, - destination = Destination, - sender = Sender, - receiver = Receiver - }. - --spec decode_result(dmsl_withdrawals_provider_adapter_thrift:'ProcessResult'()) -> process_result(). -decode_result(#wthadpt_ProcessResult{intent = Intent, next_state = undefined}) -> - {ok, decode_intent(Intent)}; -decode_result(#wthadpt_ProcessResult{intent = Intent, next_state = NextState}) -> - {ok, decode_intent(Intent), NextState}. - --spec decode_intent(dmsl_withdrawals_provider_adapter_thrift:'Intent'()) -> intent(). -decode_intent({finish, #wthadpt_FinishIntent{status = {success, #wthadpt_Success{trx_info = TrxInfo}}}}) -> - {finish, {success, TrxInfo}}; -decode_intent({finish, #wthadpt_FinishIntent{status = {failure, Failure}}}) -> - {finish, {failure, Failure}}; -decode_intent({sleep, #wthadpt_SleepIntent{timer = Timer}}) -> - {sleep, Timer}.