[erlang-questions] "calling" a gen_fsm
Roger Lipscombe
roger@REDACTED
Wed Sep 23 10:58:57 CEST 2015
On 23 September 2015 at 05:01, Garry Hodgson <garry@REDACTED> wrote:
> On 9/22/15 3:02 PM, Roger Lipscombe wrote:
>> I'd just add one point, though: I recently built something similar,
>> and I found it simpler to separate the client into two processes: one
>> gen_fsm to handle the state machine, and a separate gen_server to
>> handle the decoding and framing.
>
> i briefly considered that, but it wasn't obvious how to divide the
> work between the two. i'd be interested in how you did, if you'd
> care to elaborate.
Hmmm. I'll have a go. This is an approximation:
% client.erl -- lots of details ellided
-module(client).
-behaviour(gen_fsm).
init([Host, Port, User, Password]) ->
{ok, C} = client_connection:start_link(self(), Host, Port),
client_connection:send(C, {connect, User, Password}),
{ok, connecting, #state{ conn = C }}.
handle_info({connected, Token}, connecting, StateData) ->
{next_state, connected, StateData#state{ token = Token }};
handle_info({friends, Txn, Friends}, connected, StateData) ->
{From, NewStateData} = pop_txn(Txn, StateData),
gen_fsm:reply(From, {ok, Friends}),
{next_state, connected, NewStateData};
% etc.
handle_sync_event(get_friends, _From, connecting, State) ->
{reply, {error, not_connected}, connecting, State};
handle_sync_event(get_friends, From, connected, State) ->
Txn = new_txn_id(),
client_connection:send(C, {get_friends, Txn, State#state.token}),
{next_state, connected, add_txn_to_state({Txn, From}, State)};
% etc.
% client_connection.erl
-module(client_connection).
-behaviour(gen_server).
start_link(Parent, Host, Port) ->
% etc.
{ok, #state{ parent = Parent, %etc }}.
send(C, Msg) ->
Bin = client_codec:encode(Msg),
gen_server:cast(C, {send, Bin}).
handle_info({tcp, Bin}, State = #state{ buffer = Buffer, parent = Parent }) ->
case client_codec:decode(Buffer, Bin) of
{need_more, NewBuffer} ->
{noreply, State#state{ buffer = NewBuffer }};
{ok, Msg, NewBuffer} ->
Parent ! Msg,
{noreply, State#state{ buffer = NewBuffer }}
end
...something like that, anyway.
More information about the erlang-questions
mailing list