Yuval Kogman wrote:
> sub session {
[...]
>               return $self->NEXT::session->{$sub} ||= {};


Zbigniew Lukasiak wrote:
> On 9/27/07, Rainer Clasen <[EMAIL PROTECTED]> wrote:
> > So I'm searching for something functional similar to:
> > http://paneris.net/cgi-bin/cvsweb.cgi/SubSession/SubSessions.html?rev=1.3
> >
> 
> Interesting.  I usually use GET parameters for that - but I can
> imagine where it would become not enough.

Thanks to both of you. Your responses helped a lot to sort my Ideas and
hack up my initial "poor man" / proof of concept solution:

- subsession ids are generated with c->generate_session_id from the
  Session Plugin.
- subsession data is stored as $c->session->{SUBSESSION}{$ssid}
- ssid is picked from $c->param
- uri_for automagically sets ssid
- all internal links are constructed with uri_for()
- change of subsession data doesn't yet cause a new ssid to be assigned.
  This comes later. Up to then it has to be done manually with
  subsession_next.
- You cannot change subsession data after you've shown the subsession id
  to the client (i.e. you've used uri_for).

So far this seems to work fine, but it needs a bit more testing (and
documentation).


Rainer

-- 
KeyID=759975BD fingerprint=887A 4BE3 6AB7 EE3C 4AE0  B0E1 0556 E25A 7599 75BD
package Catalyst::Plugin::Subsession;
use warnings;
use strict;
use Storable qw( dclone );
use Catalyst::Exception ();

our $VERSION = '0.01';

# inspired by:
# http://paneris.net/cgi-bin/cvsweb.cgi/SubSession/SubSessions.html?rev=1.3

# NOTE: has to be loaded before Catalyst::Plugin::Session to run finalize
# and prepare_action in proper order.

sub setup {
	my $c = shift;

	$c->log->debug( "setting up Subsessions" );
	$c->config->{subsession}{expire} ||= 30 * 60;
	$c->config->{subsession}{param} ||= "ssid";

	$c->NEXT::setup( @_ );
}

sub subsession {
	my( $c ) = @_;

	return $c->{subsession};
}

sub ssid {
	my( $c ) = @_;
	return $c->subsession->{SSID};
}

# TODO: automagically keep track of changes to current subsession
sub subsession_next {
	my( $c ) = @_;

	Catalyst::Exception->throw( 
		"subsession already given to user, cannot modify" )
		if $c->{subsession_shown};

	$c->subsession->{SSID} = $c->_subsession_newid;
}

sub _subsession_valid {
	my( $c, $ssid ) = @_;

	return defined $ssid 
		&& $ssid =~ /^[a-z\d]+$/
		&& exists $c->session->{SUBSESSION}
		&& exists $c->session->{SUBSESSION}{$ssid}
		&& exists $c->session->{SUBSESSION}{$ssid}{SSID};
}

sub _subsession_load {
	my( $c, $ssid ) = @_;

	if( $c->_subsession_valid( $ssid ) ){
		$c->log->debug( "found Subsession $ssid" );
		$c->session->{SUBSESSION}{$ssid}{SEEN} = time;
		return dclone( $c->session->{SUBSESSION}{$ssid} )
	}
	return;
}

sub _subsession_newid {
	my( $c ) = @_;

	return $c->generate_session_id; # from Catalyst::Plugin::Session
}

sub _subsession_new {
	my( $c ) = @_;

	my $ssid = $c->_subsession_newid;
	$c->log->debug( "new Subsession $ssid" );
	return { 
		SEEN	=> time,
		SSID	=> $ssid,
	};
	# Hmm, should we redirect for new session to tell the client about
	# the new ID?
}

sub _subsession_expire {
	my( $c ) = @_;

	my $now = time;
	my $oldest = $now - $c->config->{subsession}{expire};
	foreach my $ssid ( keys %{$c->session->{SUBSESSION}} ){
		next unless ref $c->session->{SUBSESSION}{$ssid};

		if( $c->session->{SUBSESSION}{$ssid}{SEEN} < $oldest ){
			$c->log->debug( "expire Subsession $ssid" );
			delete $c->session->{SUBSESSION}{$ssid};
		}
	}
}

sub _subsession_save {
	my( $c ) = shift;

	my $ssid = $c->ssid;
	$c->log->debug( "saving Subsession $ssid" );
	$c->session->{SUBSESSION}{$ssid} =
		$c->subsession;
}

sub prepare_action {
	my $c = shift;

	$c->NEXT::prepare_action( @_ );

	my $cfg = $c->config->{subsession};
	my $ssid = $c->req->param($cfg->{param});
	# TODO: hack to shut up my abused HTML::Widget:
	delete $c->req->parameters->{$cfg->{param}};
	delete $c->req->query_parameters->{$cfg->{param}};
	$c->{subsession} = $c->_subsession_load( $ssid ) 
		|| $c->_subsession_new;
	$c->_subsession_expire;

	$c;
}
	
sub finalize {
	my $c = shift;

	my $cfg = $c->config->{subsession};
	my $ssid = $c->req->param($cfg->{param});

	if( ! defined $ssid || $ssid ne $c->ssid ){
		$c->_subsession_save;
	}

	$c->NEXT::finalize( @_ );
}

sub uri_for {
	my( $c, $path, @args ) = @_;

	++ $c->{subsession_shown};
	my $params = ( scalar @args && ref $args[$#args] eq 'HASH' 
		? pop @args : {} );

	$params->{ssid} = $c->ssid;

	$c->NEXT::uri_for( $path, @args, $params );
}

1;
_______________________________________________
List: Catalyst@lists.rawmode.org
Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst
Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/
Dev site: http://dev.catalyst.perl.org/

Reply via email to