From: Steinar H. Gunderson Date: Sun, 3 May 2009 17:35:22 +0000 (+0200) Subject: Add a mechanism for invalidating the front-end cache, if any. Currently it spits... X-Git-Url: https://git.sesse.net/?p=pr0n;a=commitdiff_plain;h=fd1e8cc4d43ed344438cb93e203ca146fe243487;ds=sidebyside Add a mechanism for invalidating the front-end cache, if any. Currently it spits out a regex in a special header, but you could easily imagine calling PURGE, for instance. --- diff --git a/perl/Sesse/pr0n/Common.pm b/perl/Sesse/pr0n/Common.pm index 00fa9e9..57d0a6b 100644 --- a/perl/Sesse/pr0n/Common.pm +++ b/perl/Sesse/pr0n/Common.pm @@ -26,6 +26,7 @@ use LWP::Simple; use Image::ExifTool; use HTML::Entities; use URI::Escape; +use File::Basename; BEGIN { use Exporter (); @@ -879,7 +880,7 @@ sub gcd { } sub add_new_event { - my ($dbh, $id, $date, $desc, $vhost) = @_; + my ($r, $dbh, $id, $date, $desc) = @_; my @errors = (); if (!defined($id) || $id =~ /^\s*$/ || $id !~ /^([a-zA-Z0-9-]+)$/) { @@ -896,12 +897,14 @@ sub add_new_event { return @errors; } + my $vhost = $r->get_server_name; $dbh->do("INSERT INTO events (event,date,name,vhost) VALUES (?,?,?,?)", undef, $id, $date, $desc, $vhost) or return ("Kunne ikke sette inn ny hendelse" . $dbh->errstr); $dbh->do("INSERT INTO last_picture_cache (vhost,event,last_picture) VALUES (?,?,NULL)", undef, $vhost, $id) or return ("Kunne ikke sette inn ny cache-rad" . $dbh->errstr); + purge_cache($r, "/"); return (); } @@ -920,6 +923,69 @@ sub guess_charset { return $decoded; } +# Depending on your front-end cache, you might want to get creative somehow here. +# This example assumes you have a front-end cache and it can translate an X-Pr0n-Purge +# regex tacked onto a request into something useful. The elements given in +# should not be regexes, though, as e.g. Squid will not be able to handle that. +sub purge_cache { + my ($r, @elements) = @_; + return if (scalar @elements == 0); + + my @pe = (); + for my $elem (@elements) { + $r->log->info("Purging $elem"); + (my $e = $elem) =~ s/[.+*|()]/\\$&/g; + push @pe, $e; + } + + my $regex = "^"; + if (scalar @pe == 1) { + $regex .= $pe[0]; + } else { + $regex .= "(" . join('|', @pe) . ")"; + } + $regex .= "(\\?.*)?\$"; + $r->headers_out->{'X-Pr0n-Purge'} = $regex; + + $r->log->info($r->headers_out->{'X-Pr0n-Purge'}); +} + +# Find a list of all cache URLs for a given image, given what we have on disk. +sub get_all_cache_urls { + my ($r, $dbh, $id) = @_; + my $dir = POSIX::floor($id / 256); + my @ret = (); + + my $q = $dbh->prepare('SELECT event, filename FROM images WHERE id=?') + or die "Couldn't prepare: " . $dbh->errstr; + $q->execute($id) + or die "Couldn't find event and filename: " . $dbh->errstr; + my $ref = $q->fetchrow_hashref; + my $event = $ref->{'event'}; + my $filename = $ref->{'filename'}; + $q->finish; + + my $base = get_base($r) . "cache/$dir"; + for my $file (<$base/$id-*>) { + my $fname = File::Basename::basename($file); + if ($fname =~ /^$id-mipmap-.*\.jpg$/) { + # Mipmaps don't have an URL, ignore + } elsif ($fname =~ /^$id--1--1\.jpg$/) { + push @ret, "/$event/$filename"; + } elsif ($fname =~ /^$id-(\d+)-(\d+)\.jpg$/) { + push @ret, "/$event/$1x$2/$filename"; + } elsif ($fname =~ /^$id-(\d+)-(\d+)-nobox\.jpg$/) { + push @ret, "/$event/$1x$2/nobox/$filename"; + } elsif ($fname =~ /^$id-(\d+)-(\d+)-box\.png$/) { + push @ret, "/$event/$1x$2/box/$filename"; + } else { + $r->log->warning("Couldn't find a purging URL for $fname"); + } + } + + return @ret; +} + 1; diff --git a/perl/Sesse/pr0n/NewEvent.pm b/perl/Sesse/pr0n/NewEvent.pm index 6112453..2aac990 100644 --- a/perl/Sesse/pr0n/NewEvent.pm +++ b/perl/Sesse/pr0n/NewEvent.pm @@ -20,7 +20,7 @@ sub handler { my $date = $apr->param('date'); my $desc = $apr->param('desc'); - my @errors = Sesse::pr0n::Common::add_new_event($dbh, $id, $date, $desc, $r->get_server_name); + my @errors = Sesse::pr0n::Common::add_new_event($r, $dbh, $id, $date, $desc); if (scalar @errors > 0) { for my $err (@errors) { diff --git a/perl/Sesse/pr0n/Rotate.pm b/perl/Sesse/pr0n/Rotate.pm index be56225..eb8d17e 100644 --- a/perl/Sesse/pr0n/Rotate.pm +++ b/perl/Sesse/pr0n/Rotate.pm @@ -14,6 +14,11 @@ sub handler { return Apache2::Const::OK; } + # FIXME: People can rotate and delete across vhosts using this interface. + # We should add some sanity checks. + + my @to_purge = (); + Sesse::pr0n::Common::header($r, "Rotation/deletion results"); { @@ -28,6 +33,7 @@ sub handler { if ($key =~ /^rot-(\d+)-(90|180|270)$/ && $apr->param($key) eq 'on') { my ($id, $rotval) = ($1,$2); my $fname = Sesse::pr0n::Common::get_disk_location($r, $id); + push @to_purge, Sesse::pr0n::Common::get_all_cache_urls($r, $dbh, $id); (my $tmpfname = $fname) =~ s/\.jpg$/-tmp.jpg/; system("/usr/bin/jpegtran -rotate $rotval -copy all < '$fname' > '$tmpfname' && mv '$tmpfname' '$fname'") == 0 @@ -43,6 +49,7 @@ sub handler { } } elsif ($key =~ /^del-(\d+)$/ && $apr->param($key) eq 'on') { my $id = $1; + push @to_purge, Sesse::pr0n::Common::get_all_cache_urls($r, $dbh, $id); { eval { @@ -70,6 +77,10 @@ sub handler { $dbh->do('UPDATE last_picture_cache SET last_update=CURRENT_TIMESTAMP WHERE vhost=? AND event=?', undef, $r->get_server_name, $event) or dberror($r, "Cache invalidation failed"); + push @to_purge, "/$event/"; + push @to_purge, "/+all/"; + Sesse::pr0n::Common::purge_cache($r, @to_purge); + Sesse::pr0n::Common::footer($r); return Apache2::Const::OK; diff --git a/perl/Sesse/pr0n/WebDAV.pm b/perl/Sesse/pr0n/WebDAV.pm index c38e7b2..09f10e5 100644 --- a/perl/Sesse/pr0n/WebDAV.pm +++ b/perl/Sesse/pr0n/WebDAV.pm @@ -470,6 +470,7 @@ EOF undef, $newid, $r->get_server_name, $event, $user, $takenby, $filename); $dbh->do('UPDATE last_picture_cache SET last_update=CURRENT_TIMESTAMP WHERE vhost=? AND event=?', undef, $r->get_server_name, $event); + Sesse::pr0n::Common::purge_cache($r, "/$event/"); # Now save the file to disk $fname = Sesse::pr0n::Common::get_disk_location($r, $newid);