Source

hello / erlang / hf_session.erl

Full commit
%% -*- coding: utf-8 -*-
-module(hf_session).
-author('kuenishi@gmail.com').
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2 ]).

-export([ stop/0, getspec/2, start_link/2 ]).

-include("hf.hrl").
-ifdef(UNITTEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

getspec(ClientRef, Socket)->
    Spec = {ClientRef, {?MODULE, start_link, [Socket, ClientRef]}, 
	    temporary, 2000, worker, [ ?MODULE ] },
    supervisor:check_childspecs([Spec]),
    Spec.

start_link(Socket, ClientRef)->
    gen_server:start_link({local,ClientRef}, ?MODULE, [Socket, ClientRef], []).
%    gen_server:start_link({local,ClientRef}, ?MODULE, [Socket, ClientRef], [{debug, [trace,log,statistics]}]).
%    gen_server:start_link({local,ClientRef}, ?MODULE, [Socket, ClientRef], [{debug, [statistics]}]).

-spec stop() -> {stop, atom(), ok, any()}.
stop()->
    gen_server:call(?MODULE, stop).

init([Socket, ClientRef])->
    io:format("~p: starting ~p,~p~n", [?MODULE, Socket, ClientRef]),
    {ok, #session{socket=Socket, self=ClientRef}}.

handle_call(_, _From, State) ->    {noreply, State}.

handle_cast(go,State)->
    ok=inet:setopts(State#session.socket, [{active,once}]),
%    {ok, Ref}=prim_inet:async_recv(State#session.socket, 0, -1), % bad call. doesn't work.
    {noreply, State#session{ready=true}};

handle_cast(_,State)->    {noreply, State}.

handle_info({tcp, Socket, Data}, State)->
    case hf_handle_request:decode_packet({tcp, Socket, Data}, State) of % recv's all http header
	{Proplist, Body} when is_list(Proplist)->
	    Method = proplists:get_value( method, Proplist ),
	    {abs_path, Resource} = proplists:get_value(resource, Proplist),
	    case hf_handle_request:process(Method, Resource, Proplist, Body, Socket) of
		ok-> 
 		    ok=inet:setopts(Socket, [{active,once}]),		    
		    {noreply, State#session{req_header=undefined, remain=0, req_body=[]}};
		close->
		    {stop, normal, State#session{req_header=undefined, remain=-1, req_body=[]}}
	    end;
	{error, Reason}->
	    {stop, Reason, error}
    end;

handle_info({tcp_closed, Socket}, Status)->
    ok=gen_tcp:close(Socket),
    ?elt("tcp connection closed by peer.~n", []),
    {stop,normal,Status};

handle_info(Msg,State)->
    erlang:display(Msg),
    {noreply, State}.

terminate(Reason,State)-> 
    ?eli("~p (~p) terminating.~n", [?MODULE, self()]),
    gen_tcp:close(State#session.socket),
    {shutdown, Reason}.
    
code_change(_,_,State)->
    {ok, State}.

-ifdef(EUNIT).
my_test()->
    ok=supervisor:check_childspecs( [getspec(erlang:make_ref(), hoge)] ),
    % TODO: make more tests about handling sessions.
    %  or this module has a lot of side effects, so
    %  maybe it's better to use ct.
    ok.
-endif.