Revision: 110 Author: matt Date: 2006-08-22 22:22:18 +0000 (Tue, 22 Aug 2006)
Log Message: ----------- Initial AIO support Made gallery a bit faster on resizes Modified Paths: -------------- trunk/NOTICE trunk/lib/AxKit2.pm trunk/plugins/demo/gallery Added Paths: ----------- trunk/plugins/aio/ trunk/plugins/aio/uri_to_file Modified: trunk/NOTICE =================================================================== --- trunk/NOTICE 2006-08-22 22:21:28 UTC (rev 109) +++ trunk/NOTICE 2006-08-22 22:22:18 UTC (rev 110) @@ -1,2 +1,5 @@ -This product includes software developed by -The Apache Software Foundation (http://www.apache.org/). \ No newline at end of file +Apache AxKit (Version 2) +Copyright 2006 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). Modified: trunk/lib/AxKit2.pm =================================================================== --- trunk/lib/AxKit2.pm 2006-08-22 22:21:28 UTC (rev 109) +++ trunk/lib/AxKit2.pm 2006-08-22 22:22:18 UTC (rev 110) @@ -21,7 +21,10 @@ use AxKit2::Server; use AxKit2::Config; use AxKit2::Console; +use AxKit2::Constants qw(LOGINFO); +use constant AIO_AVAILABLE => eval { require IO::AIO }; + our $VERSION = '1.0'; sub run { @@ -40,6 +43,12 @@ AxKit2::Server->create($server); } + if (AIO_AVAILABLE) { + AxKit2::Client->log(LOGINFO, "Adding AIO support"); + Danga::Socket->AddOtherFds (IO::AIO::poll_fileno() => + \&IO::AIO::poll_cb); + } + # print $_, "\n" for sort keys %INC; Danga::Socket->EventLoop(); Added: trunk/plugins/aio/uri_to_file =================================================================== --- trunk/plugins/aio/uri_to_file 2006-08-22 22:21:28 UTC (rev 109) +++ trunk/plugins/aio/uri_to_file 2006-08-22 22:22:18 UTC (rev 110) @@ -0,0 +1,156 @@ +#!/usr/bin/perl -w + +# Copyright 2001-2006 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +=head1 NAME + +uri_to_file - Convert URIs to filenames, and other critical stuff + +=head1 SYNOPSIS + + Plugin uri_to_file + + # optionally: + DirectoryIndex index.html + +=head1 DESCRIPTION + +This plugin provides the filename for a given URI. It is absolutely required +that you load this plugin if you wish to serve files off the filesystem, or else +re-implement its functionality somehow. + +It also splits off the path_info off the URI, provides a redirect when a +directory without a "/" is requested, and implements C<DirectoryIndex> (see below). + +=head1 CONFIG + +=head2 DirectoryIndex STRING + +A filename to append to directory requests. If the file exists then it will be +the filename used instead of the directory itself. + +=cut + +use File::Spec::Functions qw(canonpath catfile); +use AxKit2::Utils qw(uri_decode); + +sub register { + my $self = shift; + $self->register_hook('uri_translation' => 'hook_uri_translation1'); + $self->register_hook('uri_translation' => 'hook_uri_translation2'); +} + +sub init { + my $self = shift; + $self->register_config('DirectoryIndex', sub { $self->set_dirindex(@_) }); +} + +sub set_dirindex { + my ($self, $config, $value) = @_; + my $key = $self->plugin_name . '::dirindex'; + $config->notes($key, $value); +} + +sub hook_uri_translation1 { + my ($self, $hd, $uri) = @_; + + $self->log(LOGINFO, "translate: $uri"); + + + $uri =~ s/(\?.*)//; + my $removed = $1 || ''; + + my $original_uri = $uri; + + $uri = uri_decode($uri); + + my $root = $self->config->path; + + $uri =~ s/^\Q$root// || die "$uri did not match config path $root"; + + my $path = canonpath(catfile($self->config->docroot, $uri)); + $path .= '/' if $uri =~ /\/$/; # canonpath will strip a trailing slash + + my $path_info = ''; + + # set default return value + $self->client->notes('uri_to_file_retcode', DECLINED); + + # the default will work in most cases, so we do this once here. + $hd->filename($path); + + # save these so they get locked in for the closure. + my $client = $self->client; + my $config = $self->config; + + IO::AIO::aio_stat($path, sub { + $self->log(LOGINFO, "aio_stat($path) returned ($_[0])"); + if ($_[0]) { + # error (usually file didn't exist). + print "error\n"; + while ($path =~ /\// && !-f $path) { + $path =~ s/(\/[^\/]*)$//; + $path_info = $1 . $path_info; + } + if ($path_info && -f _) { + $hd->path_info($path_info); + substr($original_uri, 0 - length($path_info)) = ''; + $hd->request_uri($original_uri); + } + else { + $path .= $path_info; + $hd->path_info(''); + } + } + elsif (-d _) { + print "dir\n"; + # URI didn't end in a slash - need to redirect + if ($original_uri !~ /\/$/) { + $self->log(LOGINFO, "redirecting to $original_uri/$removed"); + $client->headers_out->header('Location', "$original_uri/$removed"); + $client->notes('uri_to_file_retcode', REDIRECT); + return; + } + if (my $dirindex = $config->notes($self->plugin_name . '::dirindex')) { + my $filepath = catfile($path, $dirindex); + $path = $filepath if -f $filepath; + } + } + elsif (-f _) { + print "file\n"; + return; + } + else { + # neither a dir nor a file + die "Unknown entity type: $path"; + } + + print "Setting filename to $path\n"; + $hd->filename($path); + + $client->finish_continuation; + }); + + return CONTINUATION; +} + +# This allows us to return REDIRECT above +sub hook_uri_translation2 { + my $self = shift; + + print "Continuation returns!\n"; + return $self->client->notes('uri_to_file_retcode'); +} Modified: trunk/plugins/demo/gallery =================================================================== --- trunk/plugins/demo/gallery 2006-08-22 22:21:28 UTC (rev 109) +++ trunk/plugins/demo/gallery 2006-08-22 22:22:18 UTC (rev 110) @@ -57,8 +57,6 @@ use RDF::Core::Model::Serializer; use AxKit2::Utils qw(uri_decode uri_encode); -use constant EPEG_AVAILABLE => eval { require Image::Epeg }; - our $DEFAULT_SIZE = '133 640 800 1024'; sub hook_xmlresponse { @@ -136,18 +134,7 @@ my $out; - if ($type eq 'jpeg' && EPEG_AVAILABLE) { - my $epg = Image::Epeg->new($file); - $epg->resize($size, $size, Image::Epeg::MAINTAIN_ASPECT_RATIO()); - $out = $epg->get_data(); - if (!$out) { - # Epeg didn't work. Resort to Imager anyway - $self->resize_image($size, $file, $type, \$out); - } - } - else { - $self->resize_image($size, $file, $type, \$out); - } + $self->resize_image($size, $file, $type, \$out); $cache->set("$file+$size", $out); @@ -175,22 +162,36 @@ $quality = 'normal' if $quality ne 'preview'; $quality = 'normal' if $self->client->param('size') ne 'thumb'; - $self->log(LOGINFO, "Scaling to $size"); + $self->log(LOGINFO, "Scaling to $size with quality: $quality"); + my $doublesize = $size < (($w > $h ? $w : $h)/2); + + if ($quality eq 'normal' && $doublesize) { + $self->log(LOGINFO, "Doing an initial shrinkage in preview mode"); + my $thumb = $image->scale(qtype => "preview", + $w > $h ? (xpixels => $w/2) + : (ypixels => $h/2) + ); + + $image = $thumb; + } + my $thumb = $image->scale(qtype => $quality, $w > $h ? (xpixels => $size) : (ypixels => $size) ); - $self->log(LOGINFO, "sharpening $thumb"); + if ($doublesize) { + $self->log(LOGINFO, "sharpening $thumb"); + + # Sharpen a bit with a convolve filter + $thumb->filter( + type=>'conv', + coef => [-0.2, 1, -0.2] + ) if $quality eq 'normal'; + } - # Sharpen a bit with a convolve filter - $thumb->filter( - type=>'conv', - coef => [-0.2, 1, -0.2] - ) if $quality eq 'normal'; - $thumb->write(data => $out, type => $type) or die "Cannot write to scalar: ", $thumb->errstr; }