Author: Jesse Gumm (@jessegumm)

# Session Handler

Getting Started | API | Elements | Actions | Validators | Handlers | Configuration Options | About

## Table of Contents

- 1 Session Handler

## 1 Session Handler

The session handler controls how session information and variables are set, stored, and retrieved. The default configuration uses the process registry to share session state between nodes, and uses a cookie to identify the user with the associated session.

### Behavior Functions

##### `init(Config, State)`

Initialize the handler

- Return Value - `{ok, NewState}`

##### `finish(Config, State)`

Clean up the handler

- Return Value - `{ok, NewState}`

##### `get_value(Key, DefaultValue, Config, State)`

Retrieves the value of session variable associated with `Key`

- `Key` - The key to retrieve
- `DefaultValue` - If there is no value set for `Key`, then return this value
- Return Value - `{ok, Value, NewState}`

##### `set_value(Key, Value, Config, State)`

Store the value of `Value` as a session variable with the `Key` as the identifier. If a value already exists, it's overwritten and the original value is returned.

- `Key` - The key to store, any erlang term
- `Value` - The value to store as Key
- Return Value - `{ok, OldValue, NewState}`

##### `clear_all(Config, State)`

Wipe out this session and all associated session variables

- Return Value - `{ok, Newstate}`

##### `session_id(Config, State)`

Return the unique session identifier.

- Return Value - `{ok, SessionId, NewState}`

### Example

Here is the complete text of the default session handler

    -module (simple_session_handler).
    -include_lib ("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 -> Other
        end,
        {ok, State}.

    finish(_Config, State) ->
        % Drop the session cookie...
        Timeout = wf:config_default(session_timeout, 20),
        ok = wf:cookie(get_cookie_name(), wf:pickle(State), "/", Timeout),
        {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({now(), erlang:make_ref()})),
        #state { unique=Unique }.

### See Also

- Handler Overview
- API: Session

Date: 2012-10-18 03:24:11 CDT

Author: Jesse Gumm (@jessegumm)

Org version 7.8.02 with Emacs version 23

Validate XHTML 1.0

## Comments

Note:To specify code blocks, just use the generic code block syntax:

    <pre><code>your code here</code></pre>

comments powered by Disqus