++ed by:
DRAEGTUN

1 PAUSE user(s)
2 non-PAUSE user(s).

Brock Wilcox

NAME

Continuity::Mapper - Map a request onto a session

DESCRIPTION

This is the session dictionary and mapper. Given an HTTP request, mapper gives said request to the correct continuation. Mapper makes continuations as needed and stores them. Mapper may be subclassed to implement other strategies for associating requests with continuations. The default strategy is (in limbo but quite possibily) based on a cookie.

METHODS

$mapper = Continuity::Mapper->new( callback => sub { ... } )

Create a new session mapper.

Contuinity does the following by default:

  $server = Continuity->new( 
    adapter  => Continuity::Adapter::HttpDaemon->new,
    mapper   => Continuity::Mapper->new( callback => \::main )
  );

Continuity::Mapper fills in the following defaults:

    cookie_session => 'sid',
    ip_session => 0,
    path_session => 0,
    query_session => 0,
    assign_session_id => sub { join '', map int rand 10, 1..20 },

Only cookie_session or query_session should be set, but not both. assign_session_id specifies a call-back that generates a new session id value for when cookie_session is enabled and no cookie of the given name (sid in this example) is passed. assign_session_id likewise gets called when query_session is set but no GET/POST parameter of the specified name (sid in this example) is passed.

If you use query_session to keep the user associated with their session, every link and form in the application must be written to include the session id. The currently assigned ID can be gotten at with $request->session_id.

For each incoming HTTP hit, Continuity must use some criteria for deciding which execution context to send that hit to. For each of these that are set true, that element of the request will be used as part of the key that maps requests to execution context (remembering that Continuity hopes to give each user one unique execution context). An "execution context" is just a unique call to the whichever function is specified or passed as the callback, where several such instances of the same function will be running at the same time, each being paused to wait for more data or unpaused when data comes in.

In the simple case, each "user" gets their own execution context. By default, users are distinguished by their IP address, which is a very bad way to try to make this distinction. Corporate users behind NATs and AOL users (also behind a NAT) will all appear to be the same few users.

path_session may be set true to use the pathname of the request, such as foo in http://bar.com/foo?baz=quux, as part of the criteria for deciding which execution context to associate with that hit. This makes it possible to write applications that give one user more than one execution contexts. This is necessary to run server-push concurrently with push from the user back to the server (see the examples directory) or to have sub-applications running on the same port, each having its own state seperate from the others.

Cookies aren't issued or read by Continuity, but we plan to add support for reading them. I expect the name of the cookie to look for would be passed in, or perhaps a subroutine that validates the cookies and returns it (possibily stripped of a secure hash) back out. Other code (the main application, or another session handling module from CPAN, or whatnot) will have the work of picking session IDs.

To get more sophisticated or specialized session ID computing logic, subclass this object, re-implement get_session_id_from_hit() to suit your needs, and then pass in an instance of your subclass to as the value for mapper in the call to Continuity->new). Here's an example of that sort of constructor call:

  $server = Continuity->new( 
    mapper   => Continuity::Mapper::StrongRandomSessionCookies->new( callback => \::main )
  );

$mapper->get_session_id_from_hit($request)

Uses the defined strategies (ip, path, cookie) to create a session identifier for the given request. This is what you'll most likely want to override, if anything.

$request is generally an HTTP::Request, though technically may only have a subset of the functionality.

$mapper->map($request)

Send the given request to the correct session, creating it if necessary.

This implementation uses the get_session_id_from_hit() method of this same class to get an identifying string from information in the request object. This is used as an index into $self->{sessions}->{$session_id}, which holds a queue of pending requests for the session to process.

So actually map() just drops the request into the correct session queue.

$mapper->reap($age)

Reap all sessions older than $age.

Reaping is done through the 'immediate' execution request mechanism. A special request is sent to the session that the session executes instead of user code. The special request then called Coro::terminate to kill itself.

$request_queue = $mapper->new_request_queue($session_id)

Returns a brand new session request queue, and starts a session to pull requests out the other side.

$mapper->enqueue($request, $request_queue|$session_id)

Add the given request to the given request queue.

This is a good spot to override for some tricky behaviour... mostly for pre-processing requests before they get to the session handler. This particular implementation will optionally print the HTTP headers for you.

Currently dies if the session_id doesn't map to a correct request queue, but pass an invalid reference and it'll probably die anyway.

$mapper->sessions

Returns a list of session IDs of active sessions, useful as arguments to Continuity::Mapper.

$mapper->inspect($session_id, sub { ... } )

Run code in another coroutine's execution context. The execution context includes the call stack, including all of the data returned by Carp::confess, Padwalker, caller, and so on.

This creates an Continuity::Inspector instance and sends it over the request queue. It's just a bit of a shorthand for the same thing.

Returns false if the session_id doesn't exist.

  my $server = Continuity->new();
  my @sessions;
  while(! @sessions) {
      @sessions = Continuity->mapper->sessions or sleep 1;
  }
  $server->mapper->inspect( $sessions[0], sub { use Carp; Carp::confess; }, );

SEE ALSO

Continuity, Coro

AUTHOR

  Brock Wilcox <awwaiid@thelackthereof.org> - http://thelackthereof.org/

COPYRIGHT

  Copyright (c) 2004-2011 Brock Wilcox <awwaiid@thelackthereof.org>. All
  rights reserved.  This program is free software; you can redistribute it
  and/or modify it under the same terms as Perl itself.



Hosting generously
sponsored by Bytemark