Current section

Files

Jump to
nitrogen_core src handlers session simple_session_handler.erl
Raw

src/handlers/session/simple_session_handler.erl

% vim: sw=4 ts=4 et ft=erlang
% Nitrogen Web Framework for Erlang
% Copyright (c) 2008-2010 Rusty Klophaus
% See MIT-LICENSE for licensing information.
% This is a "simple as possible" session handler. Unfortunately,
% due to time constraints, had to leave out some great code
% contributed by Dave Peticolas that fit Nitrogen sessions
% into a gen_server. My code below is far inferior.
% Someone please make it better! - Rusty
-module (simple_session_handler).
-include("wf.hrl").
-behaviour (session_handler).
-export ([
init/2,
finish/2,
get_value/4,
set_value/4,
clear_all/2,
session_id/2
]).
-record (state, {unique, node}).
init(_Config, _State) ->
% Get the session cookie and node...
Cookie = wf:cookie(get_cookie_name()),
State = case wf:depickle(Cookie) of
undefined -> new_state();
Other=#state{} -> Other;
_ -> new_state()
end,
{ok, State}.
finish(_Config, State) ->
% Drop the session cookie...
Timeout = wf:config_default(session_timeout, 20),
Opts = [
{path, "/"},
{minutes_to_live, Timeout},
{http_only, true}
],
ok = wf:cookie(get_cookie_name(), wf:pickle(State), Opts),
{ok, []}.
get_value(Key, DefaultValue, Config, State) ->
{ok, Pid} = get_session_pid(Config, State),
Ref = make_ref(),
Pid!{get_value, Key, self(), Ref},
Value = receive
{ok, undefined, Ref} -> DefaultValue;
{ok, Other, Ref} -> Other
end,
{ok, Value, State}.
set_value(Key, Value, Config, State) ->
{ok, Pid} = get_session_pid(Config, State),
Ref = make_ref(),
Pid!{set_value, Key, Value, self(), Ref},
receive {ok, OldValue, Ref} -> ok end,
{ok, OldValue, State}.
clear_all(Config, State) ->
{ok, Pid} = get_session_pid(Config, State),
Ref = make_ref(),
Pid!{clear_all, self(), Ref},
receive {ok, Ref} -> ok end,
{ok, State}.
session_id(_Config, State) ->
{ok, SessionId} = wf:hex_encode (State#state.unique),
{ok, SessionId, State}.
%%% PRIVATE FUNCTIONS
get_cookie_name() ->
wf:config_default(cookie_name, "newcookie").
get_session_pid(_Config, State) ->
Timeout = wf:config_default(session_timeout, 20),
F = fun() -> session_loop([], Timeout) end,
SessionTag = {session, State#state.unique},
{ok, _Pid} = process_registry_handler:get_pid(SessionTag, F).
session_loop(Session, Timeout) ->
%% Timeout in 10 if the session is empty...
TimeoutMS = case Session == [] of
true -> 10 * 1000;
false -> Timeout * 60 * 1000
end,
receive
{get_value, Key, Pid, Ref} ->
Value = case lists:keysearch(Key, 1, Session) of
{value, {Key, V}} -> V;
false -> undefined
end,
Pid!{ok, Value, Ref},
session_loop(Session, Timeout);
{set_value, Key, Value, Pid, Ref} ->
OldValue = case lists:keysearch(Key, 1, Session) of
{value, {Key, V}} -> V;
false -> undefined
end,
Session1 = lists:keystore(Key, 1, Session, {Key, Value}),
Pid!{ok, OldValue, Ref},
session_loop(Session1, Timeout);
{clear_all, Pid, Ref} ->
Pid!{ok, Ref},
session_loop([], Timeout)
after TimeoutMS ->
exit(timed_out)
end.
new_state() ->
Unique = erlang:md5(term_to_binary({os:timestamp(), erlang:make_ref()})),
#state { unique=Unique }.