#!/home/estar/Perl/bin/perl use strict; use warnings; use File::Spec; use Config::User; use Carp; use Getopt::Long; use Data::Dumper; use XMLRPC::Lite; use XML::RSS; use XML::RSS::Parser; use LWP::UserAgent; use HTTP::Request; use Net::Domain qw(hostname hostdomain); use Fcntl qw(:DEFAULT :flock); use Astro::VO::VOEvent; # C O M M A N D L I N E -------------------------------------------------- # Grab the username and password from the command line unless( scalar @ARGV >= 2 ) { croak( "USAGE: $0 -user username -pass password " . "[-community community] [-feed url]" ); } my ( $user, $pass, $community, $rss_url ); my $option_status = GetOptions( "user=s" => \$user, "pass=s" => \$pass, "community=s" => $community, "feed=s" => \$rss_url ); unless ( defined $user && defined $pass ) { croak( "You must enter a valid username and password" ); } # Assume a community unless ( defined $community ) { $community = "org.astrogrid.workshop"; } # We want the eSTAR feed? unless ( defined $rss_url ) { $rss_url = "http://www.estar.org.uk/voevent/eSTAR/eSTAR.rdf"; } # R P C ------------------------------------------------------------------- # Grab an RPC endpoint for the ACR my $file = File::Spec->catfile( Config::User->Home(), ".astrogrid-desktop" ); croak( "Unable to open file $file" ) unless open(PREFIX, "<$file" ); my $prefix = ; close( PREFIX ); chomp( $prefix ); my $endpoint = $prefix . "xmlrpc"; my $rpc = new XMLRPC::Lite(); $rpc->proxy($endpoint); # L O G I N --------------------------------------------------------------- # Check to see whether we're already logged into AstroGrid my $login; eval { $login = $rpc->call( 'astrogrid.community.isLoggedIn' ); }; if( $@ ) { croak( "Unable to check login status: $@" ); } # If we're not logged in, then login... unless ( $login->result() ) { print "Logging into Astrogrid as '". $user ."' with password '".$pass."'...\n"; my $do_login; eval { $do_login = $rpc->call( 'astrogrid.community.login', $user, $pass, $community ); }; # Check for exceptions if( $@ ) { croak( "Failed to login: $@" ); } # Check for faults if( $do_login->faultcode() ) { croak( "Failed to login: " . $do_login->faultstring() ); } } # Check that the login call really has worked eval{ $login = $rpc->call( 'astrogrid.community.isLoggedIn' ); }; if( $@ ) { croak( "Unable to check login status: $@" ); } else { if( $login->result() ) { print "Successfully logged into AstroGrid.\n"; } else { croak( "Login unsucessful, exiting..." ); } } # M A I N B L O C K ===================================================== # G R A B R S S F E E D ----------------------------------------------- print "Staring LWP::UserAgent...\n"; my $lwp = new LWP::UserAgent( timeout => 10 ); $lwp->env_proxy(); $lwp->agent( "AstroGrid Workshop (" . hostname() . "." . hostdomain() .")"); print "Grabbing RSS feed from $rss_url\n"; my $request = new HTTP::Request('GET', $rss_url); my $reply = $lwp->request($request); # check for valid reply if ( ${$reply}{"_rc"} eq 200 ) { print "Recieved document of type " . ${${$reply}{"_headers"}}{"content-type"} . "\n"; if ( ${${$reply}{"_headers"}}{"content-type"} eq "application/rdf+xml" && ${$reply}{"_content"} =~ 'rss version="2.0"' ) { print "The document appears to be a valid RSS feed...\n"; } else { croak( "Error: Document doesn't seem to be RSS2.0" ); } } else { croak( "Error: Unable to retrieve RSS feed: " . ${$reply}{_msg} ); } print "Parsing feed..."; my $content = ${$reply}{"_content"}; my $parser = new XML::RSS::Parser(); my $feed = $parser->parse_string( $content ); # output some values my $count = $feed->item_count; print " $count items\n"; my @items = $feed->query('//item'); my $counter = 0; foreach my $i ( @items ) { $counter = $counter + 1; my $link = $i->query('link'); print "Downloading $counter of ". scalar( @items) . " items...\n"; my $item_request = new HTTP::Request('GET', $link->text_content ); my $item_reply = $lwp->request($item_request); # check for valid reply my $store_status; if ( ${$item_reply}{"_rc"} eq 200 ) { $store_status = store_voevent( ${$item_reply}{"_content"} ); } else { carp( "Waring: Unable to retrieve feed item: " . ${$item_reply}{_msg} ); } if ( ! defined $store_status ) { croak( "File wasn't written to disk" ); } elsif ( $store_status eq "0" ) { print "Already dealt with this event...\n"; next; } print "Uploading ".$link->text_content() ."\n"; my $upload_status = upload_voevent( ${$item_reply}{"_content"}, $rpc ); } print "Done.\n"; # C L E A N U P --------------------------------------------------------- # Check that the login call really has worked #eval{ $login = $rpc->call( 'astrogrid.community.logout' ); }; # Check for exceptions #if( $@ ) { # croak( "Unable to logout: $@" ); #} # Check for faults #if( $login->faultcode() ) { # croak( "Unable to login: " . $login->faultstring() ); #} #print "Successfully logged out of AstroGrid.\n"; exit; # S U B R O U T I N E S ---------------------------------------------------- sub store_voevent { my $message = shift; my $dir = File::Spec->curdir(); my $object = new Astro::VO::VOEvent( XML => $message ); my $id; eval { $id = $object->id( ); }; if ( $@ ) { croak( "Error: $@" ); } unless ( defined $id && $id ne "" ) { carp( "Warning: \$id is undefined, not writing event file"); return undef; } my $idpath = $id; $idpath =~ s/#/\//; my @path = split( "/", $idpath ); if ( $path[0] eq "ivo:" ) { splice @path, 0 , 1; } if ( $path[0] eq "" ) { splice @path, 0 , 1; } # Build path to save file in... yuck! if ( opendir ( DIR, $dir ) ) { closedir DIR; } else { mkdir $dir, 0755; if ( opendir ( DIR, $dir ) ) { closedir DIR; } else { carp( "Warning: Unable to create $dir"); return undef; } } foreach my $i ( 0 ... ($#path - 1) ) { if ( $path[$i] eq "" ) { next; } $dir = File::Spec->catdir( $dir, $path[$i] ); if ( opendir ( DIR, $dir ) ) { closedir DIR; next; } else { mkdir $dir, 0755; if ( opendir ( DIR, $dir ) ) { closedir DIR; next; } else { carp ( "Warning: Unable to create $dir"); return undef; } } } my $file = File::Spec->catfile( $dir, "$path[$#path].xml"); if ( -s $file ) { return 0; } # write the observation object to disk. unless ( open ( SERIAL, "+>$file" )) { carp( "Warning: Unable to write file $file"); return undef; } else { unless ( flock( SERIAL, LOCK_EX ) ) { carp("Warning: unable to acquire exclusive lock: $!"); return undef; } print SERIAL $message; close(SERIAL); } return $file; } sub upload_voevent { my $message = shift; my $rpc = shift; my ( $object, $id ); eval { $object = new Astro::VO::VOEvent( XML => $message ); }; if ( $@ ) { croak( "Error: $@" ); } eval { $id = $object->id( ); }; if ( $@ ) { croak( "Error: $@" ); } unless ( defined $id && $id ne "" ) { carp( "Warning: \$id is undefined, not writing event file"); return undef; } my $idpath = $id; $idpath =~ s/#/\//; my @path = split( "/", $idpath ); if ( $path[0] eq "ivo:" ) { splice @path, 0 , 1; } if ( $path[0] eq "" ) { splice @path, 0 , 1; } # Build path to save file in... yuck! my $dir = "#"; unless ( $rpc->call('astrogrid.myspace.exists', $dir ) ) { $rpc->call('astrogrid.myspace.createFolder', $dir ); unless( $rpc->call('astrogrid.myspace.exists', $dir ) ) { carp( "Warning: Unable to create $dir"); return undef; } } foreach my $i ( 0 ... ($#path - 1) ) { if ( $path[$i] eq "" ) { next; } $dir = $dir . "/" . $path[$i]; if ( $rpc->call('astrogrid.myspace.exists', $dir ) ) { next; } else { $rpc->call('astrogrid.myspace.createFolder', $dir ); if ( $rpc->call('astrogrid.myspace.exists', $dir ) ) { next; } else { carp ( "Warning: Unable to create $dir"); return undef; } } } my $file = $dir . "/$path[$#path].xml"; # write the observation object to disk. unless ( $rpc->call('astrogrid.myspace.write', $file, $message ) ) { carp( "Warning: Unable to write file $file"); return undef; } return $file; }