/usr/share/perl5/POE/Component/Schedule.pm is in libpoe-component-schedule-perl 0.95-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | package POE::Component::Schedule;
use 5.008;
use strict;
use warnings;
use Carp;
our $VERSION = '0.95';
use POE;
BEGIN {
defined &DEBUG or *DEBUG = sub () { 0 };
}
# Private properties of a schedule ticket
sub PCS_TIMER () { 0 } # The POE timer
sub PCS_ITERATOR () { 1 } # DateTime::Set iterator
sub PCS_SESSION () { 2 } # POE session ID
sub PCS_EVENT () { 3 } # Event name
sub PCS_ARGS () { 4 } # Event args array
# Private constant:
# The name of the counter attached to each session
# We use only one counter for all timers of one session
# All instances of P::C::S will use the same counter for a given session
sub REFCOUNT_COUNTER_NAME () { __PACKAGE__ }
# Scheduling session ID
# This session is a singleton
my $BackEndSession;
# Maps tickets IDs to tickets
my %Tickets = ();
my $LastTicketID = 'a'; # 'b' ... 'z', 'aa' ...
#
# crank up the schedule session
#
sub spawn { ## no critic (Subroutines::RequireArgUnpacking)
if ( !defined $BackEndSession ) {
my ($class, %arg) = @_;
my $alias = $arg{Alias} || ref $class || $class;
$BackEndSession = POE::Session->create(
inline_states => {
_start => sub {
print "# $alias _start\n" if DEBUG;
my ($k) = $_[KERNEL];
$k->detach_myself;
$k->alias_set( $alias );
$k->sig( 'SHUTDOWN', 'shutdown' );
},
schedule => \&_schedule,
client_event => \&_client_event,
cancel => \&_cancel,
shutdown => sub {
print "# $alias shutdown\n" if DEBUG;
my $k = $_[KERNEL];
# Remove all timers of our session
# and decrement session references
foreach my $alarm ($k->alarm_remove_all()) {
my ($name, $time, $t) = @$alarm;
$t->[PCS_TIMER] = undef;
$k->refcount_decrement($t->[PCS_SESSION], REFCOUNT_COUNTER_NAME);
}
%Tickets = ();
$k->sig_handled();
},
_stop => sub {
print "# $alias _stop\n" if DEBUG;
$BackEndSession = undef;
},
},
)->ID;
}
return $BackEndSession;
}
#
# schedule the next event
# ARG0 is the schedule ticket
#
sub _schedule {
my ( $k, $t ) = @_[ KERNEL, ARG0];
#
# deal with DateTime::Sets that are finite
#
my $n = $t->[PCS_ITERATOR]->next;
unless ($n) {
# No more events, so release the session
$k->refcount_decrement($t->[PCS_SESSION], REFCOUNT_COUNTER_NAME);
$t->[PCS_TIMER] = undef;
return;
}
$t->[PCS_TIMER] = $k->alarm_set( client_event => $n->epoch, $t );
return $t;
}
#
# handle a client event and schedule the next one
# ARG0 is the schedule ticket
#
sub _client_event { ## no critic (Subroutines::RequireArgUnpacking)
my ( $k, $t ) = @_[ KERNEL, ARG0 ];
$k->post( @{$t}[PCS_SESSION, PCS_EVENT], @{$t->[PCS_ARGS]} );
return _schedule(@_);
}
#
# cancel an alarm
#
sub _cancel {
my ( $k, $t ) = @_[ KERNEL, ARG0 ];
if (defined($t->[PCS_TIMER])) {
$k->alarm_remove($t->[PCS_TIMER]);
$k->refcount_decrement($t->[PCS_SESSION], REFCOUNT_COUNTER_NAME);
$t->[PCS_TIMER] = undef;
}
return;
}
#
# Takes a POE::Session, an event name and a DateTime::Set
# Returns a ticket object
#
sub add {
my ( $class, $session, $event, $iterator, @args ) = @_;
# Remember only the session ID
$session = $poe_kernel->alias_resolve($session) unless ref $session;
defined($session) or croak __PACKAGE__ . "->add: first arg must be an existing POE session ID or alias.";
$session = $session->ID;
# We don't want to loose the session until the event has been handled
$poe_kernel->refcount_increment($session, REFCOUNT_COUNTER_NAME) > 0
or croak __PACKAGE__ . "->add: first arg must be an existing POE session ID or alias: $!";
ref $iterator && $iterator->isa('DateTime::Set')
or croak __PACKAGE__ . "->add: third arg must be a DateTime::Set";
$class->spawn unless $BackEndSession;
my $id = $LastTicketID++;
my $ticket = $Tickets{$id} = [
undef, # Current alarm id
$iterator,
$session,
$event,
\@args,
];
$poe_kernel->post( $BackEndSession, schedule => $ticket);
# We return a kind of smart pointer, so the schedule
# can be simply destroyed by releasing its object reference
return bless \$id, ref($class) || $class;
}
sub delete {
my $id = ${$_[0]};
return unless exists $Tickets{$id};
$poe_kernel->post($BackEndSession, cancel => delete $Tickets{$id});
return;
}
# Releasing the ticket object will delete the ressource
sub DESTROY {
return $_[0]->delete;
}
{
no warnings;
*new = \&add;
}
1;
__END__
=head1 NAME
POE::Component::Schedule - Schedule POE events using DateTime::Set iterators
=head1 SYNOPSIS
use POE qw(Component::Schedule);
use DateTime::Set;
POE::Session->create(
inline_states => {
_start => sub {
$_[HEAP]{sched} = POE::Component::Schedule->add(
$_[SESSION], Tick => DateTime::Set->from_recurrence(
after => DateTime->now,
before => DateTime->now->add(seconds => 3),
recurrence => sub {
return $_[0]->truncate( to => 'second' )->add( seconds => 1 )
},
),
);
},
Tick => sub {
print 'tick ', scalar localtime, "\n";
},
remove_sched => sub {
# Three ways to remove a schedule
# The first one is only for API compatibility with POE::Component::Cron
$_[HEAP]{sched}->delete;
$_[HEAP]{sched} = undef;
delete $_[HEAP]{sched};
},
_stop => sub {
print "_stop\n";
},
},
);
POE::Kernel->run();
=head1 DESCRIPTION
This component encapsulates a session that sends events to client sessions
on a schedule as defined by a DateTime::Set iterator.
=head1 POE::Component::Schedule METHODS
=head2 spawn(Alias => I<name>)
Start up the PoCo::Schedule background session with the given alias. Returns
the back-end session handle.
No need to call this in normal use, C<add()> and C<new()> all crank
one of these up if it is needed.
=head2 add(I<$session>, I<$event_name>, I<$iterator>, I<@event_args>)
my $sched = POE::Component::Schedule->add(
$session,
$event_name,
$DateTime_Set_iterator,
@event_args
);
Add a set of events to the scheduler.
Returns a schedule handle. The event is automatically deleted when the handle
is not referenced anymore.
=head2 new(I<$session>, I<$event_name>, I<$iterator>, I<@event_args>)
C<new()> is an alias for C<add()>.
=head1 SCHEDULE HANDLE METHODS
=head2 delete()
Removes a schedule using the handle returned from C<add()> or C<new()>.
B<DEPRECATED>: Schedules are now automatically deleted when they are not
referenced anymore. So just setting the container variable to C<undef> will
delete the schedule.
=head1 SEE ALSO
L<POE>, L<DateTime::Set>, L<POE::Component::Cron>.
=head1 SUPPORT
You can look for information at:
=over 4
=item * RT: CPAN's request tracker
L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=POE-Component-Schedule>:
post bug report there.
=item * CPAN Ratings
L<http://cpanratings.perl.org/p/POE-Component-Schedule>:
if you use this distibution, please add comments on your experience for other
users.
=item * Search CPAN
L<http://search.cpan.org/dist/POE-Component-Schedule/>
=item * AnnoCPAN: Annotated CPAN documentation
L<http://annocpan.org/dist/POE-Component-Schedule>
=back
=head1 ACKNOWLEDGMENT & HISTORY
This module was a friendly fork of L<POE::Component::Cron> to extract the
generic parts and isolate the Cron specific code in order to reduce
dependencies on other CPAN modules.
See L<https://rt.cpan.org/Ticket/Display.html?id=44442>.
The orignal author of POE::Component::Cron is Chris Fedde.
POE::Component::Cron is now implemented as a class that inherits from
POE::Component::Schedule.
Most of the POE::Component::Schedule internals have since been rewritten in
0.91_01 and we have now a complete test suite.
=head1 AUTHORS
=over 4
=item Olivier MenguE<eacute>, C<<< dolmen@cpan.org >>>
=item Chris Fedde, C<<< cfedde@cpan.org >>>
=back
=head1 COPYRIGHT AND LICENSE
=over 4
=item Copyright E<copy> 2009-2010 Olivier MenguE<eacute>.
=item Copyright E<copy> 2007-2008 Chris Fedde.
=back
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.3 or,
at your option, any later version of Perl 5 you may have available.
=cut
|