A Gentle Introduction to Plack Sessions

Table of contents

A Gentle Introduction to Plack Sessions
Storing Session Data
Coding Our Cache Strategy
Getting Plack's Session Handler to use our Cache
Accessing the Session within our Application
Wrapping Up
References
Author
Licence

A Gentle Introduction to Plack Sessions

In this article I'll show how CGI scripts, e.g. based on CGI::Application and CGI::Session, can switch to Plack-style sessions.

Storing Session Data

The first step is to decide how to store the session data, i.e. in memory, in a cookie, in a file, or in a database.

The documentation for Plack::Middleware::Session shows some ways to do this.

I won't repeat that code, but will show how to use CHI to cache the data.

Coding Our Cache Strategy

CHI is a sophisticated interface to many caching mechanisms. Here, I store session data in a hashref managed by CHI.

We create a new class to encapsulate the CHI-specific code:

         1  package Local::Application::Util::Cache;
         2
         3  use CHI;
         4
         5  use Local::Application::Util::Config;
         6
         7  use Moose;
         8
         9  use namespace::autoclean;
        10
        11  our $VERSION = '1.02';
        12
        13  # -----------------------------------------------
        14
        15  sub cache
        16  {
        17      my($self)      = @_;
        18      my($config)    = Local::Application::Util::Config -> new -> config;
        19      my($datastore) = {};
        20
        21      return CHI -> new
        22      (
        23              datastore  => $datastore,
        24              driver     => 'Memory',
        25              expires_in => $$config{session_timeout},
        26              namespace  => __PACKAGE__,
        27      );
        28
        29  } # End of cache.
        30
        31  # --------------------------------------------------
        32
        33  __PACKAGE__ -> meta -> make_immutable;
        34
        35  1;

Points to note:

Line 18

We use a config module to read a config file, to get a session timeout, which is used on line 25.

My config file contins this line:

        session_timeout = 10h

and is read in using Config::Tiny.

Line 19

The session data is held in a hashref, which is a local variable inside the cache() method.

The reason this works is that CHI keeps a reference to this hashref, which stops the variable going out of scope when the cache() method exits.

Line 21

We pass to CHI -> new() the parameters required for a memory-based data store.

Different cache strategies have different parameter requirements, so check the docs carefully.

Line 25

The format of session times, as used by CHI, is described in CHI's docs under Duration Expressions.

Getting Plack's Session Handler to use our Cache

The next step is the PSGI script to use our cache class. Call it 'local.psgi':

         1  #!/usr/bin/perl
         2
         3  use common::sense;
         4
         5  use CGI::Application::Dispatch::PSGI;
         6
         7  use Local::Application::Util::Cache;
         8
         9  use Plack::Builder;
        10  use Plack::Session::Store::Cache;
        11
        12  # ----------------
        13
        14  my($app) = CGI::Application::Dispatch -> as_psgi
        15  (
        16      prefix => 'Local::Application::Controller',
        17      table  =>
        18      [
        19      ''              => {app => 'Initialize', rm => 'display'},
        20      ':app'          => {rm => 'display'},
        21      ':app/:rm/:id?' => {},
        22      ],
        23  );
        24
        25  builder
        26  {
        27      enable 'Session',
        28              store => Plack::Session::Store::Cache -> new
        29              (cache => Local::Application::Util::Cache -> new -> cache);
        30      enable 'Static',
        31              path => qr!^/(assets|favicon|yui)/!,
        32              root => '/var/www';
        33      $app;
        34  };

Run local.psgi with:

        plackup -l 127.0.0.1:5002 local.psgi &

or, even better:

        starman -l 127.0.0.1:5002 --workers 1 local.psgi &

Points to note:

Line 7

We prepare to use our new class.

Line 10

We prepare to interface to Plack's session-handling code.

Lines 14 .. 23

Our common-or-garden, CGI::Application::Dispatch-based, Plack app.

If you don't use CGI::Application::Dispatch your code will be even simpler.

Lines 27 .. 29

We tell Plack::Session::Store::Cache to use our new class.

Accessing the Session within our Application

Plack makes the session data available via the environment, so that's what we tap into next:

        1  my($q)   = $self -> query;
        2  my($env) = $q -> env;
        3
        4  $self -> param(sid => $$env{'psgix.session.options'}{id});
        5  $self -> param(script_name => $$env{SCRIPT_NAME});
        6
        7  my($session) = $$env{'psgix.session'};
        8
        9  $$session{execution_count}++;

Points to note:

Line 1

Since our app is CGI::Application-based, we get the query object (of type CGI) via a call to the query() method.

Query objects are usually only used to hold CGI form field key-value pairs.

Line 2

But, since Plack's environment is made available via the query object, we call the env() method to retrieve a hashref of env data.

Lines 4 .. 5

Again, since our app is CGI::Application-based, we have a param() method available to use to store key-value pairs, for later retrieval elsewhere in the app.

Lines 7 .. 9

We grab the session itself, and update an arbitrary parameter within that session.

Yep - that's all there is to it.

Wrapping Up

Any session data value, here $$session{execution_count}, can be updated in this manner, and the new value is saved in the session automatically.

Of course, using the memory-based datastore as above means the value is not saved between runs of the program.

But by changing the return value of our class's cache() method to:

        1       return CHI -> new
        2       (
        3               driver     => 'File',
        4               root_dir   => '/tmp/chi',
        5               namespace  => __PACKAGE__,
        6       );

we can even stop and start local.psgi, and have the counter continue from where it was up to.

Neat, huh?

References

The Plack Home Page - http://plackperl.org/.

The Previous Article in this Series: http://savage.net.au/Perl/html/plack.for.beginners.html.

Author

Ron Savage .

Home page: http://savage.net.au/index.html.

Licence

Australian Copyright © 2010 Ron Savage. All rights reserved.

        All Programs of mine are 'OSI Certified Open Source Software';
        you can redistribute them and/or modify them under the terms of
        The Artistic License, a copy of which is available at:
        http://www.opensource.org/licenses/index.html