package IO::SessionSet;
use strict;
use Carp;
use IO::Select;
use IO::Handle;
use IO::SessionData;
use vars '$DEBUG';
$DEBUG = 0;
sub new {
my $pack = shift;
my $listen = shift;
my $self = bless {
sessions => {},
readers => IO::Select->new(),
writers => IO::Select->new(),
},$pack;
if ( defined($listen) and $listen->can('accept') ) {
$self->{listen_socket} = $listen;
$self->{readers}->add($listen);
}
return $self;
}
sub sessions { return values %{shift->{sessions}} };
sub add {
my $self = shift;
my ($handle,$writeonly) = @_;
warn "Adding a new session for $handle.\n" if $DEBUG;
return $self->{sessions}{$handle} =
$self->SessionDataClass->new($self,$handle,$writeonly);
}
sub delete {
my $self = shift;
my $thing = shift;
my $handle = $self->to_handle($thing);
my $sess = $self->to_session($thing);
warn "Deleting session $sess handle $handle.\n" if $DEBUG;
delete $self->{sessions}{$handle};
$self->{readers}->remove($handle);
$self->{writers}->remove($handle);
}
sub to_handle {
my $self = shift;
my $thing = shift;
return $thing->handle if $thing->isa('IO::SessionData');
return $thing if defined (fileno $thing);
return; }
sub to_session {
my $self = shift;
my $thing = shift;
return $thing if $thing->isa('IO::SessionData');
return $self->{sessions}{$thing} if defined (fileno $thing);
return; }
sub activate {
my $self = shift;
my ($thing,$rw,$act) = @_;
croak 'Usage $obj->activate($session,"read"|"write" [,$activate])'
unless @_ >= 2;
my $handle = $self->to_handle($thing);
my $select = lc($rw) eq 'read' ? 'readers' : 'writers';
my $prior = defined $self->{$select}->exists($handle);
if (defined $act && $act != $prior) {
$self->{$select}->add($handle) if $act;
$self->{$select}->remove($handle) unless $act;
warn $act ? 'Activating' : 'Inactivating',
" handle $handle for ",
$rw eq 'read' ? 'reading':'writing',".\n" if $DEBUG;
}
return $prior;
}
use Data::Dumper;
sub wait {
my $self = shift;
my $timeout = shift;
warn "IO::Select->select() returned error: $!"
unless my ($read,$write) =
IO::Select->select($self->{readers},$self->{writers},undef,$timeout);
foreach (@$write) {
my $session = $self->to_session($_);
warn "Writing pending data (",$session->pending+0," bytes) for $_.\n"
if $DEBUG;
my $rc = $session->write;
}
my @sessions;
foreach (@$read) {
if ($_ eq $self->{listen_socket}) {
my $newhandle = $_->accept;
warn "Accepting a new handle $newhandle.\n" if $DEBUG;
my $newsess = $self->add($newhandle) if $newhandle;
push @sessions,$newsess;
} else {
push @sessions,$self->to_session($_);
}
}
return @sessions;
}
sub SessionDataClass { return 'IO::SessionData'; }
1;