package POEDaemon::AIO; use strict; use warnings FATAL => 'all'; no warnings 'redefine'; use Fcntl; use HTTP::Status qw(:constants); use HTTP::Date; use POE qw(Component::AIO); use POEDaemon; sub states { return $_[0], [qw( aio_stop aio_send_file_to_client aio_open_done aio_stat_done aio_read_file aio_read_done aio_close_done )]; } sub aio_stop { $poco_aio->shutdown; } sub aio_send_file_to_client { my ($kernel, $heap, $args) = @_[KERNEL, HEAP, ARG0]; return unless ref $args eq 'HASH'; my $file = $args->{file}; return unless defined $file && $args->{wheel_id}; $args->{buffer_size} = 4096 unless $args->{buffer_size}; aio_open $file, O_RDONLY, 0, $poco_aio->callback(aio_open_done => $args); } sub aio_open_done { my ($kernel, $session, $heap, $args, $fh) = @_[KERNEL, SESSION, HEAP, ARG0, ARG1]; my $file = $args->{file}; my $wheel_id = $args->{wheel_id}; my $client = $heap->{tcpserver}->{connections}->{$wheel_id}; my $wheel = $client->{wheel}; unless (defined $fh) { log_enabled && logline "aio open failed on '%s': '%s'", $file, $!; return unless $wheel; $wheel->event(FlushedEvent => 'tcpserver_client_http_response_sent'); my $response_status = HTTP_INTERNAL_SERVER_ERROR; my $response_content = ''; $kernel->call($session => tcpserver_output_http => { wheel_id => $wheel_id, status => $response_status, content => $response_content, protocol => $args->{http_protocol}, connection => $args->{http_connection}, }); return; } $args->{fh} = $fh; log_enabled && logline "aio open done on '%s'", $file; aio_stat $fh, $poco_aio->postback(aio_stat_done => $args); } sub aio_stat_done { my ($kernel, $session, $heap, $args) = @_[KERNEL, SESSION, HEAP, ARG0]; my $file = $args->{file}; my $wheel_id = $args->{wheel_id}; my $client = $heap->{tcpserver}->{connections}->{$wheel_id}; my $wheel = $client->{wheel}; my @stat = stat _; unless (@stat) { log_enabled && logline "aio stat failed on '%s': '%s'", $file, $!; return unless $wheel; $wheel->event(FlushedEvent => 'tcpserver_client_http_response_sent'); my $response_status = HTTP_INTERNAL_SERVER_ERROR; my $response_content = ''; $kernel->call($session => tcpserver_output_http => { wheel_id => $wheel_id, status => $response_status, content => $response_content, protocol => $args->{http_protocol}, connection => $args->{http_connection}, }); return; } my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = @stat; log_enabled && logline "aio stat done on '%s': size = '%s' bytes, mtime = '%s'", $file, $size, $mtime; $args->{size} = $size; $args->{mtime} = $mtime; $client->{aio_args} = $args; return unless $wheel; $wheel->event(FlushedEvent => 'tcpserver_client_aio_send_file'); $kernel->call($session => tcpserver_output_http => { wheel_id => $wheel_id, content_type => $args->{content_type}, content_length => $size, last_modified => time2str $mtime, protocol => $args->{http_protocol}, connection => $args->{http_connection}, }); } sub aio_read_file { my ($kernel, $heap, $args) = @_[KERNEL, HEAP, ARG0]; my $fh = $args->{fh}; my $buffer = ''; $args->{buffer} = \$buffer; my $length = $args->{buffer_size} || 1024; aio_read $fh, undef, $length, $buffer, 0, $poco_aio->postback(aio_read_done => $args); } sub aio_read_done { my ($kernel, $heap, $args, $bytes) = @_[KERNEL, HEAP, ARG0, ARG1]; my $file = $args->{file}; my $fh = $args->{fh}; my $buffer = $args->{buffer}; my $wheel_id = $args->{wheel_id}; unless ($bytes > 0) { log_enabled && logline "aio read done on '%s': '%s'", $file, $!; $kernel->yield(tcpserver_client_aio_send_file_done => { wheel_id => $wheel_id, }); aio_close $fh, $poco_aio->postback(aio_close_done => $args); return; } #log_enabled && logline "aio read '%s' bytes on '%s': buffer = '%s'", # $bytes, # $file, # $$buffer; $kernel->yield(tcpserver_output => { wheel_id => $args->{wheel_id}, output => $$buffer, }); $kernel->yield(aio_read_file => $args); } sub aio_close_done { my ($kernel, $session, $heap, $args) = @_[KERNEL, SESSION, HEAP, ARG0]; my $file = $args->{file}; my $fh = $args->{fh}; unless (close $fh) { log_enabled && logline "aio close failed on '%s': %s", $file, $!; return; } log_enabled && logline "aio close done on '%s'", $file; } 1;