Apache-MONITOR
view release on metacpan or search on metacpan
lib/Apache/MONITOR.pm view on Meta::CPAN
open(LOCK,">$dir/lock") || die("unable to open $dir/lock, $!");
flock(LOCK,2);
dbmopen( %uris , "$dir/uris", 0666) || die("unable to open $dir/uris, $!");
if(! exists $uris{$uri})
{
my $now = time();
my $value = join(' ', ($uri,$mon_string,$now,$state) );
$uris{$uri} = $value;
}
dbmclose(%uris);
dbmopen( %monitors , "$dir/monitors", 0666) || die("unable to open $dir/monitors, $!");
foreach my $muri (keys %monitors)
{
my $value = $monitors{$muri};
my ($u,$re) = split (/ /,$value);
if( ($u eq $uri) && ($re eq $reply_to) )
{
dbmclose(%monitors);
close(LOCK);
return ($muri,SUBSCRIBE_ALREADY);
}
}
my $id = time() . $$;
$monitor_url .= $id;
$monitors{$monitor_url} = "$uri $reply_to";
dbmclose(%monitors);
close(LOCK);
return ($monitor_url,SUBSCRIBE_OK);
}
sub get_monitor_code
{
my ($r,$monitored_uri) = @_;
return undef;
return "checker";
}
sub SUBSCRIBE
{
require LWP::UserAgent;
@Apache::MONITOR::ISA = qw(LWP::UserAgent);
my $ua = __PACKAGE__->new;
my $args = @_ ? \@_ : \@ARGV;
my ($url,$reply_to,$proxy) = @$args;
$ua->proxy(['http'], $proxy ) if(defined $proxy);
my $req = HTTP::Request->new('MONITOR' => $url );
$req->header('Reply_To' => $reply_to );
#$req->header('Accept' => 'text/plain' );
my $res = $ua->request($req);
if($res->is_success)
{
print $res->as_string();
print "Monitor created at: ",$res->header('Location') , "\n";
}
else
{
print $res->as_string();
}
}
sub UNSUBSCRIBE
{
require LWP::UserAgent;
@Apache::MONITOR::ISA = qw(LWP::UserAgent);
my $ua = __PACKAGE__->new;
my $args = @_ ? \@_ : \@ARGV;
my ($mon_url) = @$args;
my $req = HTTP::Request->new('DELETE' => $mon_url );
my $res = $ua->request($req);
if($res->is_success)
{
print $res->as_string();
#print $res->content;
print "Monitor deleted\n";
}
else
{
print $res->as_string();
}
}
sub NOTIFY
{
require LWP::UserAgent;
@Apache::MONITOR::ISA = qw(LWP::UserAgent);
my $ua = __PACKAGE__->new;
my $args = @_ ? \@_ : \@ARGV;
my ($dir) = @$args;
my %uris;
my %monitors;
open(LOCK,">$dir/lock") || die("unable to open $dir/lock, $!");
flock(LOCK,2);
dbmopen( %uris , "$dir/uris" , 0040) || die("unable to open $dir/uris, $!");
dbmopen( %monitors , "$dir/monitors" , 0040) || die("unable to open $dir/monitors, $!");
foreach my $monitored_uri ( keys %uris )
{
my $value = $uris{$monitored_uri};
my ($u,$mon_string,$lastmod,$state) = split(/ /,$value);
my $modified_time = $lastmod;
#print "--$u $mon_string $lastmod\n";
print "*--------------------------------------------------\n";
if( $mon_string =~ /^apply:(.+)$/ )
{
# apply code
my $code = $1;
require "/tmp/" . $code;
$modified_time = $code->check($u);
}
elsif( $mon_string =~ /^mtime:(.+)$/ )
{
my $filename = $1;
print "$monitored_uri: checking file mtime of $filename\n";
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
$modified_time = $mtime;
}
else
{
my $old_checksum = $state;
print "$monitored_uri: checking checksum via HTTP GET\n";
my ($checksum,$rv,$msg) = poll_to_checksum($monitored_uri);
if($rv)
{
print "$monitored_uri: ",$msg, "\n";
next;
}
print " ....old checksum $old_checksum\n";
print " ....new checksum $checksum\n";
if( $checksum != $old_checksum)
{
$modified_time = time();
$state = $checksum;
}
}
next unless ($modified_time > $lastmod);
print "...$monitored_uri has changed, getting monitors\n";
# updating record with new lastmod
$uris{$monitored_uri} = "$u $mon_string $modified_time $state";
foreach my $muri (keys %monitors)
{
my $value = $monitors{$muri};
my ($u,$re) = split(/ / , $value);
next unless ($u eq $monitored_uri);
#my $req = HTTP::Request->new('GET' => $monitored_uri);
#my $res = $ua->request($req);
#my $body;
#if($res->is_success)
#{
# $body = $res->content;
#}
#else
#{
# $body = $res->as_string();
#}
#$req->header('Reply_To' => $reply_to );
if( $re =~ /^mailto:(.*)$/ )
{
my $to = $1;
open(MAIL,"|mail $to -s \"Resource $monitored_uri has changed\"");
print MAIL "Resource state has changed at ". localtime($modified_time) ."\n";
print MAIL "View the monitored resource: $monitored_uri\n";
print MAIL "Edit your monitor: $muri\n";
close(MAIL);
print " notified $re\n";
}
}
}
dbmclose(%uris);
dbmclose(%monitors);
close(LOCK);
}
sub poll_to_checksum
{
require LWP::UserAgent;
@Apache::MONITOR::ISA = qw(LWP::UserAgent);
my $ua = __PACKAGE__->new;
my $args = @_ ? \@_ : \@ARGV;
my ($uri) = @$args;
my $req = HTTP::Request->new('GET' => $uri);
my $res = $ua->request($req);
if($res->is_success)
{
my $s = $res->content;
$s =~ s/<meta[^>]+>//gi;
my $cs = cksum($s);
return ($cs,0,'');
}
else
{
return (0,1,'GET error');
}
}
1;
__END__
=head1 NAME
Apache::MONITOR - Implementation of the HTTP MONITOR method
=head1 SYNOPSIS
=head1 DESCRIPTION
This module implements a MONITOR HTTP method, which adds notifications to the
World Wide Web.
=head1 CONFIGURATION
httpd.conf:
PerlSetVar MonitorDataDir /home/httpd/monitors
PerlSetVar MonitorUrlPrefix http://myserver/monitors/
PerlPostReadRequestHandler Apache::MONITOR
PerlHeaderParserHandler Apache::MONITOR::hp_handler
<Location /monitors/>
SetHandler perl-script
PerlHandler Apache::MONITOR::moo
</Location>
crontab:
# check for changes every 30 minutes
0,30 * * * * perl -MApache::MONITOR -e NOTIFY /home/httpd/monitors &>/dev/null
=head1 COMMANDLINE TOOLS
Subscribe:
perl -MApache::MONITOR -e SUBSCRIBE http://www.mopo.de mailto:joe@the.org
Show all subscriptions:
perl -MApache::MONITOR -e SHOW /path/to/monitors
( run in 1.263 second using v1.01-cache-2.11-cpan-39bf76dae61 )