.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Continuity::Mapper 3" .TH Continuity::Mapper 3 "2011-09-17" "perl v5.14.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Continuity::Mapper \- Map a request onto a session .SH "DESCRIPTION" .IX Header "DESCRIPTION" This is the session dictionary and mapper. Given an \s-1HTTP\s0 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. .SH "METHODS" .IX Header "METHODS" .ie n .SS "$mapper = Continuity::Mapper\->new( callback => sub { ... } )" .el .SS "\f(CW$mapper\fP = Continuity::Mapper\->new( callback => sub { ... } )" .IX Subsection "$mapper = Continuity::Mapper->new( callback => sub { ... } )" Create a new session mapper. .PP Contuinity does the following by default: .PP .Vb 4 \& $server = Continuity\->new( \& adapter => Continuity::Adapter::HttpDaemon\->new, \& mapper => Continuity::Mapper\->new( callback => \e::main ) \& ); .Ve .PP Continuity::Mapper fills in the following defaults: .PP .Vb 5 \& cookie_session => \*(Aqsid\*(Aq, \& ip_session => 0, \& path_session => 0, \& query_session => 0, \& assign_session_id => sub { join \*(Aq\*(Aq, map int rand 10, 1..20 }, .Ve .PP Only \f(CW\*(C`cookie_session\*(C'\fR or \f(CW\*(C`query_session\*(C'\fR should be set, but not both. \&\f(CW\*(C`assign_session_id\*(C'\fR specifies a call-back that generates a new session id value for when \f(CW\*(C`cookie_session\*(C'\fR is enabled and no cookie of the given name (\f(CW\*(C`sid\*(C'\fR in this example) is passed. \f(CW\*(C`assign_session_id\*(C'\fR likewise gets called when \f(CW\*(C`query_session\*(C'\fR is set but no \s-1GET/POST\s0 parameter of the specified name (\f(CW\*(C`sid\*(C'\fR in this example) is passed. .PP If you use \f(CW\*(C`query_session\*(C'\fR 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 \s-1ID\s0 can be gotten at with \f(CW\*(C`$request\->session_id\*(C'\fR. .PP For each incoming \s-1HTTP\s0 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 \*(L"execution context\*(R" 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. .PP In the simple case, each \*(L"user\*(R" gets their own execution context. By default, users are distinguished by their \s-1IP\s0 address, which is a very bad way to try to make this distinction. Corporate users behind NATs and \s-1AOL\s0 users (also behind a \s-1NAT\s0) will all appear to be the same few users. .PP \&\f(CW\*(C`path_session\*(C'\fR may be set true to use the pathname of the request, such as \&\f(CW\*(C`foo\*(C'\fR in \f(CW\*(C`http://bar.com/foo?baz=quux\*(C'\fR, 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. .PP 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 \s-1CPAN\s0, or whatnot) will have the work of picking session IDs. .PP To get more sophisticated or specialized session \s-1ID\s0 computing logic, subclass this object, re-implement \f(CW\*(C`get_session_id_from_hit()\*(C'\fR to suit your needs, and then pass in an instance of your subclass to as the value for \f(CW\*(C`mapper\*(C'\fR in the call to \f(CW\*(C`Continuity\->new)\*(C'\fR. Here's an example of that sort of constructor call: .PP .Vb 3 \& $server = Continuity\->new( \& mapper => Continuity::Mapper::StrongRandomSessionCookies\->new( callback => \e::main ) \& ); .Ve .ie n .SS "$mapper\->get_session_id_from_hit($request)" .el .SS "\f(CW$mapper\fP\->get_session_id_from_hit($request)" .IX Subsection "$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. .PP \&\f(CW$request\fR is generally an HTTP::Request, though technically may only have a subset of the functionality. .ie n .SS "$mapper\->map($request)" .el .SS "\f(CW$mapper\fP\->map($request)" .IX Subsection "$mapper->map($request)" Send the given request to the correct session, creating it if necessary. .PP This implementation uses the \f(CW\*(C`get_session_id_from_hit()\*(C'\fR method of this same class to get an identifying string from information in the request object. This is used as an index into \f(CW\*(C`$self\->{sessions}\->{$session_id}\*(C'\fR, which holds a queue of pending requests for the session to process. .PP So actually \f(CW\*(C`map()\*(C'\fR just drops the request into the correct session queue. .ie n .SS "$mapper\->reap($age)" .el .SS "\f(CW$mapper\fP\->reap($age)" .IX Subsection "$mapper->reap($age)" Reap all sessions older than \f(CW$age\fR. .PP 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. .ie n .SS "$request_queue = $mapper\->new_request_queue($session_id)" .el .SS "\f(CW$request_queue\fP = \f(CW$mapper\fP\->new_request_queue($session_id)" .IX Subsection "$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. .ie n .SS "$mapper\->enqueue($request, $request_queue|$session_id)" .el .SS "\f(CW$mapper\fP\->enqueue($request, \f(CW$request_queue\fP|$session_id)" .IX Subsection "$mapper->enqueue($request, $request_queue|$session_id)" Add the given request to the given request queue. .PP 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 \s-1HTTP\s0 headers for you. .PP Currently \f(CW\*(C`die\*(C'\fRs if the session_id doesn't map to a correct request queue, but pass an invalid reference and it'll probably die anyway. .ie n .SS "$mapper\->sessions" .el .SS "\f(CW$mapper\fP\->sessions" .IX Subsection "$mapper->sessions" Returns a list of session IDs of active sessions, useful as arguments to Continuity::Mapper. .ie n .SS "$mapper\->inspect($session_id, sub { ... } )" .el .SS "\f(CW$mapper\fP\->inspect($session_id, sub { ... } )" .IX Subsection "$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. .PP 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. .PP Returns false if the session_id doesn't exist. .PP .Vb 6 \& 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; }, ); .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" Continuity, Coro .SH "AUTHOR" .IX Header "AUTHOR" .Vb 1 \& Brock Wilcox \- http://thelackthereof.org/ .Ve .SH "COPYRIGHT" .IX Header "COPYRIGHT" .Vb 3 \& Copyright (c) 2004\-2011 Brock Wilcox . All \& rights reserved. This program is free software; you can redistribute it \& and/or modify it under the same terms as Perl itself. .Ve