Просмотр исходного кода

Replace gen_server with gen_statem in examples

j.uhlig 7 лет назад
Родитель
Сommit
301f582b97

+ 9 - 9
doc/src/guide/protocols.asciidoc

@@ -59,30 +59,30 @@ loop(Socket, Transport) ->
 	end.
 ----
 
-=== Using gen_server
+=== Using gen_statem
 
-Special processes like the ones that use the `gen_server` or `gen_fsm`
+Special processes like the ones that use the `gen_statem` or `gen_server`
 behaviours have the particularity of having their `start_link` call not
 return until the `init` function returns. This is problematic, because
 you won't be able to call `ranch:accept_ack/1` from the `init` callback
 as this would cause a deadlock to happen.
 
-Use the `gen_server:enter_loop/3` function. It allows you to start your process
+Use the `gen_statem:enter_loop/4` function. It allows you to start your process
 normally (although it must be started with `proc_lib` like all special
 processes), then perform any needed operations before falling back into
-the normal `gen_server` execution loop.
+the normal `gen_statem` execution loop.
 
-.Use a gen_server for protocol handling
+.Use a gen_statem for protocol handling
 
 [source,erlang]
 ----
 -module(my_protocol).
--behaviour(gen_server).
+-behaviour(gen_statem).
 -behaviour(ranch_protocol).
 
 -export([start_link/4]).
 -export([init/1]).
-%% Exports of other gen_server callbacks here.
+%% Exports of other gen_statem callbacks here.
 
 start_link(Ref, Socket, Transport, Opts) ->
 	{ok, proc_lib:spawn_link(?MODULE, init, [{Ref, Socket, Transport, Opts}])}.
@@ -91,9 +91,9 @@ init({Ref, Socket, Transport, _Opts = []}) ->
 	%% Perform any required state initialization here.
 	ok = ranch:accept_ack(Ref),
 	ok = Transport:setopts(Socket, [{active, once}]),
-	gen_server:enter_loop(?MODULE, [], {state, Socket, Transport}).
+	gen_statem:enter_loop(?MODULE, [], state_name, {state_data, Socket, Transport}).
 
-%% Other gen_server callbacks here.
+%% Other gen_statem callbacks here.
 ----
 
 Check the `tcp_reverse` example for a complete example.

+ 2 - 2
examples/tcp_reverse/README.md

@@ -1,11 +1,11 @@
 Ranch TCP reverse example
 =========================
 
-This example uses a `gen_server` to handle a protocol to revese input.
+This example uses a `gen_statem` to handle a protocol to revese input.
 See `reverse_protocol.erl` for the implementation. Documentation about
 this topic can be found in the guide:
 
-  http://ninenines.eu/docs/en/ranch/HEAD/guide/protocols/#using_gen_server
+  http://ninenines.eu/docs/en/ranch/HEAD/guide/protocols/#using_gen_statem
 
 To try this example, you need GNU `make` and `git` in your PATH.
 

+ 37 - 34
examples/tcp_reverse/src/reverse_protocol.erl

@@ -1,19 +1,18 @@
 %% Feel free to use, reuse and abuse the code in this file.
 
 -module(reverse_protocol).
--behaviour(gen_server).
+-behaviour(gen_statem).
 -behaviour(ranch_protocol).
 
 %% API.
 -export([start_link/4]).
 
-%% gen_server.
+%% gen_statem.
+-export([callback_mode/0]).
 -export([init/1]).
--export([handle_call/3]).
--export([handle_cast/2]).
--export([handle_info/2]).
--export([terminate/2]).
--export([code_change/3]).
+-export([connected/3]).
+-export([terminate/3]).
+-export([code_change/4]).
 
 -define(TIMEOUT, 5000).
 
@@ -24,45 +23,49 @@
 start_link(Ref, Socket, Transport, Opts) ->
 	{ok, proc_lib:spawn_link(?MODULE, init, [{Ref, Socket, Transport, Opts}])}.
 
-%% gen_server.
+%% gen_statem.
 
-%% This function is never called. We only define it so that
-%% we can use the -behaviour(gen_server) attribute.
-%init([]) -> {ok, undefined}.
+callback_mode() ->
+	state_functions.
 
 init({Ref, Socket, Transport, _Opts = []}) ->
 	ok = ranch:accept_ack(Ref),
-	ok = Transport:setopts(Socket, [{active, once}]),
-	gen_server:enter_loop(?MODULE, [],
+	ok = Transport:setopts(Socket, [{active, once}, {packet, line}]),
+	gen_statem:enter_loop(?MODULE, [], connected,
 		#state{socket=Socket, transport=Transport},
-		?TIMEOUT).
+		[?TIMEOUT]).
 
-handle_info({tcp, Socket, Data}, State=#state{
+connected(info, {tcp, Socket, Data}, _StateData=#state{
 		socket=Socket, transport=Transport})
 		when byte_size(Data) > 1 ->
 	Transport:setopts(Socket, [{active, once}]),
 	Transport:send(Socket, reverse_binary(Data)),
-	{noreply, State, ?TIMEOUT};
-handle_info({tcp_closed, _Socket}, State) ->
-	{stop, normal, State};
-handle_info({tcp_error, _, Reason}, State) ->
-	{stop, Reason, State};
-handle_info(timeout, State) ->
-	{stop, normal, State};
-handle_info(_Info, State) ->
-	{stop, normal, State}.
-
-handle_call(_Request, _From, State) ->
-	{reply, ok, State}.
-
-handle_cast(_Msg, State) ->
-	{noreply, State}.
-
-terminate(_Reason, _State) ->
+	{keep_state_and_data, ?TIMEOUT};
+connected(info, {tcp_closed, _Socket}, _StateData) ->
+	{stop, normal};
+connected(info, {tcp_error, _, Reason}, _StateData) ->
+	{stop, Reason};
+connected({call, From}, _Request, _StateData) ->
+	gen_statem:reply(From, ok),
+	keep_state_and_data;
+connected(cast, _Msg, _StateData) ->
+	keep_state_and_data;
+connected(timeout, _Msg, _StateData) ->
+	{stop, normal};
+connected(_EventType, _Msg, _StateData) ->
+	{stop, normal}.
+
+terminate(Reason, StateName, StateData=#state{
+		socket=Socket, transport=Transport})
+		when Socket=/=undefined andalso Transport=/=undefined ->
+	catch Transport:close(Socket),
+	terminate(Reason, StateName,
+		StateData#state{socket=undefined, transport=undefined});
+terminate(_Reason, _StateName, _StateData) ->
 	ok.
 
-code_change(_OldVsn, State, _Extra) ->
-	{ok, State}.
+code_change(_OldVsn, StateName, StateData, _Extra) ->
+	{ok, StateName, StateData}.
 
 %% Internal.