åã®éšåãžã®ãªã³ã¯ã¯ãèšäºã®æåŸã«ãããŸãã
ããã¯ã OTPã·ãªãŒãºã®æŠèŠã® 3çªç®ã®èšäºã§ãã æåã®ããŒãããå§ããããšããå§ãããŸããããã¯ãgen_serverã«ã€ããŠèª¬æããéè¡ã·ã¹ãã ã®åºç€ãç¯ããŸãïŒãŸã è¡ã£ãŠããªãå ŽåïŒã äžæ¹ãæèœãªåŠçã§ããã°ãæ¢è£œã®ã¢ãžã¥ãŒã«eb_atm.erlããã³eb_server.erlãèŠãããšãã§ããŸãã
ã·ããªãª ïŒäžå€®ãµãŒããŒãœãããŠã§ã¢ãšããŒã«ã«ATMã®åºçŸã«ãããErlyBankã¯æè¡ããŒã¹ã楜芳çã«èªèãå§ããŸããã ãããã競åä»ç€Ÿã«å¯Ÿããä¿è·æ段ãšããŠãäžå®éã®çŸéãåŒãåºããããšãã«éç¥ãéä¿¡ããã·ã¹ãã ãå®è£ ããããšèããŠããŸãã ãœãããŠã§ã¢ãåèµ·åããã«ãçŸéåŒãåºãé¡ã®ãããå€ãå€æŽãããšãéç¥ãããªã¬ãŒãããŸãã çµå¶é£ã¯ãã¿ã¹ã¯ã«åŸã£ãŠçŸåšã®ããŒãžã§ã³ãã¢ããã°ã¬ãŒãããããã«ç§ãã¡ãéãããšã«ããŸããã
çµæ ïŒ gen_eventã䜿çšããŠã€ãã³ãããŒã¹ã®éç¥ã·ã¹ãã ãäœæããŸãã ããã«ãããå°æ¥çã«ä»ã®éç¥ãäœæããããã®åºæ¬çãªåºç€ãæäŸããããšåæã«ãçŸåšã®ãµãŒããŒãœãããŠã§ã¢ãžã®çµ±åã容æã«ãªããŸãã
gen_eventãšã¯äœã§ããïŒ
gen_eventã¯ãErlang / OTPã®åäœã¢ãžã¥ãŒã«ãšããŠæ©èœããŸãïŒ åäœ;åã®èè ã®ç¿»èš³ãšã¯ç°ãªãçšèªã䜿çšããŸãããµã€ã¯ã«ã®åæã«ãçšèªã¯ãã€ã³ã¿ãŒãã§ã€ã¹ããšããŠç¿»èš³ãããŸããããã©ã³ã¹ã¬ãŒã¿ ïŒã€ãã³ãåŠçæ©èœãå®è£ ããŸãã ããã¯ãå€ãã®ãã³ãã©ãŒãå®è¡ãããŠããã€ãã³ããããŒãžã£ãŒããã»ã¹ãå®è¡ããããšã§å®çŸãããŸãã ã€ãã³ããããŒãžã£ãŒã¯ä»ã®ããã»ã¹ããã€ãã³ããåä¿¡ããåãã³ãã©ãŒã¯é çªã«ã€ãã³ãéç¥ãåä¿¡ãããããã§äœã§ãã§ããŸãã
ãã³ãã©ãŒã®äºæ³ãããã³ãŒã«ããã¯ã¯æ¬¡ã®ãšããã§ãã
- init / 1-ãã³ãã©ãŒãåæåããŸãã
- handle_event / 2-ãªã¹ããŒããªãã¹ã³ããã€ãã³ããããŒãžã£ãŒã«éä¿¡ãããã€ãã³ããåŠçããŸãã
- handle_call / 2-ã€ãã³ããããŒãžã£ãŒãžã®åŒã³åºããšããŠéä¿¡ãããã€ãã³ããåŠçããŸãã ãã®ã³ã³ããã¹ãã§ã®åŒã³åºãã¯ãgen_serverã®åäœã§ã®åŒã³åºããšåãã§ããå¿çãéä¿¡ããããŸã§å®è¡ã¯äžæãããŸãã
- handle_info / 2-ãã³ãã©ãŒã«éä¿¡ããããã€ãã³ãïŒã€ãã³ãïŒãŸãã¯åŒã³åºãïŒåŒã³åºãïŒã§ã¯ãªãã¡ãã»ãŒãžãåŠçããŸãã
- terminate / 2-ãã³ãã©ãŒãçµäºãããšãã«åŒã³åºãããããã»ã¹ãå¿ èŠãªãªãœãŒã¹ã解æŸã§ããããã«ããŸãã
- code_change / 3-æäœäžã«ã¢ãžã¥ãŒã«ãã³ãŒãå€æŽãçŽæ¥åãããšåŒã³åºãããŸãã ãã®ã¢ãŒãã¯ãã®èšäºã§ã¯èª¬æããŸãããããã®ã·ãªãŒãºã®ä»åŸã®èšäºã®ããŒããŒã«ãªããŸãã
ãã®ã·ãªãŒãºã®ååã§èª¬æãã2ã€ã®åäœã¢ãžã¥ãŒã«ãšæ¯èŒããŠãçŸåšã®ã¢ãžã¥ãŒã«ã«ã¯æ¯èŒçå°æ°ã®ãã£ãŒãããã¯ã¡ãœããããããŸãã ãã ããgen_eventã¯åãé »åºŠã§äœ¿çšã§ããä»ã®OTPã¢ãžã¥ãŒã«ãšåãæ©èœãåããŠããŸãã
ã€ãã³ããããŒãžã£ãŒãäœæãã
æåã«è¡ãå¿ èŠãããã®ã¯ãã€ãã³ããããŒãžã£ãŒãäœæããããšã§ãã ããã¯æ¯èŒçç°¡åãªã¿ã¹ã¯ã§ããgen_eventãµãŒããŒãèµ·åããã ãã§ãããããã€ãã®APIã¡ãœãããè¿œå ããããšã§ãæ°ãããã³ãã©ãŒã®è¿œå ãéç¥ã®éä¿¡ãªã©ãç°¡åã«ãªããŸãã
ç§ã®ã€ãã³ããããŒãžã£ãŒãã¬ãŒã ã¯ãŒã¯ãèŠãŠãã ããã ããã«ãåºç€ãšããŠäœ¿çšããŠããã©ã°ã¡ã³ããæäŸããŸãã
ã芧ã®ãšããããã®ãã¡ã€ã«ã¯çãããã®ã§ã¯ãããŸããã éå§æ¹æ³ã¯ãä»ã®OTPåäœã¢ãžã¥ãŒã«ãšåãã§ãã ã€ãã³ããããŒãžã£ãŒã«ãã³ãã©ãŒãè¿œå ããã¡ã€ã³APIãå«ããŸããã
%%--------------------------------------------------------------------
%% Function: add_handler(Module) -> ok | {'EXIT',Reason} | term()
%% Description: Adds an event handler
%%--------------------------------------------------------------------
add_handler(Module) ->
gen_event:add_handler(?SERVER, Module, []).
ãã®ã¡ãœããã¯ãåã«çŸåšã®ã¢ãžã¥ãŒã«ã«ããã€ãã³ããã³ãã©ãŒãã€ãã³ããããŒãžã£ãŒã«è¿œå ããŸãã ãŸããã€ãã³ããããŒãžã£ãŒãä»ããŠéç¥ãéä¿¡ããããã«å¿ èŠãªã䜿ããããã¡ãœãããè¿œå ããŸããã
%%--------------------------------------------------------------------
%% Function: notify(Event) -> ok | {error, Reason}
%% Description: Sends the Event through the event manager.
%%--------------------------------------------------------------------
notify(Event) ->
gen_event:notify(?SERVER, Event).
ãŸããç解ãããããã®ã§ãªããã°ãªããŸããã ãã®ã¡ãœããã¯ãã€ãã³ããã€ãã³ããããŒãžã£ã«éä¿¡ããã ãã§ãã gen_eventïŒnotify / 2ã¯éåæèŠæ±ã§ãããããããã«æ»ããçºçããŸãã
ã€ãã³ããããŒãžã£ãŒããµãŒããŒã«æ¥ç¶ãã
ãµãŒããŒãèµ·åããåã«ãã€ãã³ããããŒãžã£ãŒãæ¢ã«å®è¡ãããŠããããšã確èªãããã®ã§ããµãŒããŒã¢ãžã¥ãŒã«ããæ瀺çã«èµ·åããããã«åŒ·å¶ããŸãã åŸã§ãå¥ã®èšäºã§ã ã¹ãŒããŒãã€ã¶ãŒããªãŒã«ããã匷å¶ããäºå®ã§ãã æ°ãããµãŒããŒåæåã³ãŒãã¯æ¬¡ã®ãšããã§ãã
init([]) ->
eb_event_manager:start_link(),
{ok, dict:new()}.
ã€ãã³ããããŒãžã£ãŒã¯ãµãŒããŒããã»ã¹ã®å šæéãéããŠèµ·åãããããšãåæãšããŠãããããç¹å®ã®æç¹ã§ã¡ãã»ãŒãžãéä¿¡ããããšãã§ããŸãã ã¯ã©ã€ã¢ã³ãã§ããErlyBank ã¯ãäžå®ã®é¡ã®åŒãåºãããã€çºçããããç¥ããããšèããŠããŸãïŒ èè ã¯å ¥éãã€ãŸãå ¥éãšèšããŸãããããã¯æããã«ééãã§ãã ããã¯ç§ãããããµãŒããŒã«æ¥ç¶ããæ¹æ³ã§ãïŒ
handle_call({withdraw, Name, Amount}, _From, State) ->
case dict:find(Name, State) of
{ok, {_PIN, Value}} when Value < Amount ->
{reply, {error, not_enough_funds}, State};
{ok, {PIN, Value}} ->
NewBalance = Value - Amount,
NewState = dict:store(Name, {PIN, NewBalance}, State),
% Send notification
eb_event_manager:notify({withdraw, Name, Amount, NewBalance}),
{reply, {ok, NewBalance}, NewState};
error ->
{reply, {error, account_does_not_exist}, State}
end;
ããã§ãã€ãã³ããããŒãžã£ã䜿çšããåŒãåºãäžã«ãã€ãã³ããçæãããŸãã éç¥ã¡ãœããã¯éåæã§ãããã€ãã³ããããŒãžã£ãŒãšãã³ãã©ãŒã¯å¥ã ã®ããã»ã¹ã§å®è¡ãããããšã«æ³šæããŠãã ããã ããã¯ãéç¥ã䞊è¡ããŠå®è¡ããããã©ã³ã¶ã¯ã·ã§ã³ã®é床ãäœäžããªãããšãæå³ããŸãã ãã¡ãããããã»ããµãéè² è·ã«ãªããšãåããã»ã¹ã®å®è¡ã«æéãããããŸãããçè«çã«ã¯åæã«çºçããã¯ãã§ãã
ãŸããããã§åŒãåºãéé¡ãç¹å®ã®éé¡ãè¶ ãããã©ããããã§ãã¯ããŠããŸããã ErlyBankã¯ããããå€ãšããŠäœ¿çšããéãæå®ããŸããã§ããããµãŒããŒããã»ã¹ã§ããŒãã³ãŒãã£ã³ã°ããã®ã¯ããªãã°ãããŠããŸãã äžè¬ã«ããã¹ãŠã®ããžãã¯ããã³ãã©ãŒã«æ®ããŠãéç¥ãåŒã³åºãããšããå§ãããŸãã ãããŠãããã¯ãŸãã«ç§ãã¡ã次ã«ããããšã§ãïŒ
eb_server.erlã®ãã¹ãŠã®ã³ã³ãã³ãã¯ããã§èŠãããšãã§ããŸã ã
ãã³ãã©ãŒãã¬ãŒã
ç§ã¯ãã€ããã¹ãŠã®OTPã¢ãžã¥ãŒã«ã®åºæ¬çãªãã¬ãŒã ã¯ãŒã¯ãæã£ãŠããŸãã ã€ãã³ããã³ãã©ãŒã«ã€ããŠã¯ãã¡ããã芧ãã ãã ã
ãã®ã¢ãžã¥ãŒã«ãéç«ãããŠãã1ã€ã®ããšïŒããã«ã¯start_linkãŸãã¯startã¡ãœããããããŸããã ããã¯ãã€ãã³ããã³ãã©ãŒãæ¥ç¶ããããã«eb_event_managerïŒadd_handlerïŒModuleïŒã¡ãœããã䜿çšããŠããããã§ããå®éããã®ã¡ãœããã¯ããã»ã¹ãéå§ããŠçæããŸãã
init([]) ->
{ok, 500}.
gen_eventãã³ãã©ãŒã®åæåã¡ãœããã¯ãä»ã®ãã¹ãŠã®Erlang / OTPåäœã¢ãžã¥ãŒã«ã®ã¡ãœãããšäŒŒãŠããŸããã {okãState}ãè¿ããŸããStateã¯ããã»ã¹ã®ããŒã¿ã®ç¶æ ã§ãã ãã®å Žåã500ãè¿ããŸããããã¯ãã¢ã«ãŠã³ãããã®åŒãåºãã®éç¥ã®èŠåãããå€ã瀺ãããã«äœ¿çšããŸãã
çŸéåŒãåºãéç¥åŠç
ãã®ã€ãã³ããã³ãã©ãŒã®å¯äžã®ç®çã¯ãåºééç¥ãåãå ¥ããåºéé¡ãç¹å®ã®ãããå€ãè¶ ããå Žåã«äœããè¡ãããšã§ãã ã€ãã³ãã¯ãéåæã¡ãã»ãŒãžgen_eventïŒnotify / 2ã䜿çšããŠãã£ã¹ããããããŸãã ãã³ãã©ãŒãžã®éåæéç¥ã¯ã handle_eventã¡ãœããã«ãã£ãŠåŠçãããŸãã
handle_event({withdraw, Name, Amount, NewBalance}, State) when Amount >= State ->
io:format("WITHDRAWAL NOTIFICATION: ~p withdrew ~p leaving ~p left.~n", [Name, Amount, NewBalance]),
{ok, State};
handle_event(_Event, State) ->
{ok, State}.
ã¡ãã»ãŒãžã®åŠçã¯ç°¡åã§ãã ãããå€ã®æ€åã®éãè¶ ããå Žåã«ã®ã¿ã€ãã³ããåä¿¡ããããã«ãæ€åã¡ãã»ãŒãžãšä¿è·ã確èªããããã®ãã³ãã¬ãŒããè¿œå ããŸããã
åŒãåºãéé¡ããããå€ãè¶ ãããšã端æ«ã«åºåããŸãã
å®æããeb_withdrawal_handler.erlã¢ãžã¥ãŒã«ã¯ã ããã§ååŸã§ããŸã ã
æäœäžã®ãããå€ã®å€æŽ
ErlyBankã¯ãä»äºäžã«çŸéã®åŒãåºããéç¥ããããã®ãããå€ãå€æŽã§ããããã«ããããšãè¿°ã¹ãŸããã ãããè¡ãã«ã¯ãå®éã®ãã³ãã©ãŒã«APIã¡ãœãããè¿œå ããŸãã ããã«ãããŸãïŒ
%%--------------------------------------------------------------------
%% Function: change_threshold(Amount) -> {ok, Old, NewThreshold}
%% | {error, Reason}
%% Description: Changes the withdrawal amount threshold during runtime
%%--------------------------------------------------------------------
change_threshold(Amount) ->
gen_event:call(eb_event_manager, ?MODULE, {change_threshold, Amount}).
ããã«ãããæ°ããget_eventã¡ãœããã§ããcallã¡ãœãããå°å ¥ãããŸãã ãã®ã¡ãœããã¯ãç¹å®ã®ãã³ãã©ãŒã«èŠæ±ãéä¿¡ããå¿çãäºæãããããåæçã§ãã 圌ã®åŒæ°ã¯callïŒEventManagerãHandlerãMessageïŒã§ãã ãããã£ãŠããã®å Žåãæåã®ãã©ã¡ãŒã¿ãŒãšããŠãçŸåšã®ããã»ã¹ã«ç»é²ãããŠããã€ãã³ããããŒãžã£ãŒã¢ãžã¥ãŒã«ã瀺ããŸãã ãã³ãã©ãŒã¢ãžã¥ãŒã«ã®ååã2çªç®ã®ãã©ã¡ãŒã¿ãŒãšããŠæå®ãããããå€ãå€æŽããã¡ãã»ãŒãžãéä¿¡ããŸãã
ãã®ãªã¯ãšã¹ãã¯ã handle_call / 2ãã£ãŒãããã¯ã¡ãœããã§åŠçããŸãã
handle_call({change_threshold, Amount}, State) ->
io:format("NOTICE: Changing withdrawal threshold from ~p to ~p~n", [State, Amount]),
{ok, {ok, State, Amount}, Amount};
handle_call(_Request, State) ->
Reply = ok,
{ok, Reply, State}.
ãŸãããããå€ãå€æŽãããŠãããšããã¡ãã»ãŒãžã端æ«ã«è¡šç€ºãã次ã«ã¡ãã»ãŒãž{okãOldThresholdãNewThreshold}ã§è¿ä¿¡ããæ°ãããããå€ãããŒã¿ã®ç¶æ ãšããŠèšå®ããŸãã 次ã®åºééç¥ãåãåããšããã³ãã©ãŒã¯æ°ããèŠåå€ã䜿çšããŸãïŒ :)
å®å šãªeb_withdrawal_handlerã¢ãžã¥ãŒã«ã¯ã ããã§è¡šç€ºã§ããŸã ã
ãããã«
gen_eventã«é¢ãããã®èšäºã§ã¯ãã€ãã³ããããŒãžã£ãŒã®äœæãã€ãã³ãã®ãã£ã¹ããããã€ãã³ããã³ãã©ãŒã®å®è£ ããããã®ã€ãã³ãã®åä¿¡ãããã³ãã³ãã©ãŒã®åŒã³åºãã«ã€ããŠèª¬æããŸããã ç§ãé瀺ããªãã£ãå¯äžã®ããšã¯ãgen_eventã®äžéšã§ããããã«ãããã€ãã³ããã³ãã©ãŒã¯åæããããå¥ã®ãã³ãã©ãŒã«çœ®ãæãããã§ããŸãã ãã®çç±ã¯ãç§ã¯å®éã®ç°å¢ã§ãã®ã¡ã«ããºã ã䜿çšããçµéšãè±å¯ã§ã¯ãªãããã§ãã ãããŸã§ã®ãšãããç§ã¯ãããã®æ©äŒãžã®å¿çšãèŠã€ããŠããŸããã ãã ãããããã«ã€ããŠç¥ãããå Žåã¯ã ããã¥ã¡ã³ããåç §ããŠãã ããã
ããã§ãErlang / OTPå°å ¥ãµã€ã¯ã«ã®3çªç®ã®éšåãçµäºããŸãã 第4æ¡ã¯æ°æ¥äžã«å ¬éãããäºå®ã§ã ç£ç£è ã«ã€ããŠè©±ããŸãã
UPD
kutu habrayuzerã®æ³šæã®ãããã§ãé倧ãªçç¥ãçºèŠãããŸãããããã¯ãåæã§äœæããããã®åŸç¿»èš³ã«ç§»è¡ããŸããã 泚ïŒãã®èšäºã§ã¯ããã³ãã©ãŒã«å¯ŸããŠeb_event_managerïŒadd_handlerïŒModuleïŒãåŒã³åºãå¿ èŠãããå Žæã瀺ããŠããŸããã åŒã³åºãã¯å®è¡ãããªãããããã³ãã©ãŒã¯äœæ¥ã«å«ãŸããŸããã ãã®æ®µéã§ãã³ãã©ãŒãæ¥ç¶ããè«ççãªå Žæã¯ãeb_serverl.erlã®initïŒArgsïŒã§ãã ããã¯ãå¿ èŠãªå€æŽãè¡ã£ãåŸã®ãã®ã¡ãœããã®å€èŠ³ã§ãã
init([]) ->
eb_event_manager:start_link(),
eb_event_manager:add_handler(eb_withdrawal_handler),
{ok, dict:new()}.
å°æ¥ã®èšäºã§ã¯ãå ã®ããã¹ãã®äœæè ã¯ããã¹ãŠã®èµ·åã¹ã¯ãªããã1ãæããèµ·åããããšãçŽæããŸãããããã¯æ¬¡ã®èšäºã§ã®ã¿çºçããŸãã ç§ãã¡ãšäžç·ã«ããŠãã ããïŒ
ããã«ãeb_withdrawal_handlerãã³ãã©ãŒã®å®å šçãžã®ãªã³ã¯ã翻蚳ã«è¿œå ãããŸãããã誀ã£ãŠæã£ãŠè¡ãã®ãå¿ããŠããŸããã
ã·ãªãŒãºã®èšäº
4. ã³ã³ãããŒã©ãŒã䜿çšããŠErlyBankããããŒãç¶æ ã«ä¿ã€
3. gen_eventã®æŠèŠïŒè«æ±æžå€æŽã®éç¥ïŒçŸåšã®èšäºïŒ
翻蚳ã®èè ã¯é¢ä¿è ã§ãïŒ
2. gen_fsmã®æŠèŠïŒErlyBank ATM
1. gen_serverã®æŠèŠïŒErlyBank
0. Open Telecom Platform / Open Telecommunication PlatformïŒOTP / OTPïŒã®æŠèŠ
-1ã èæ¯