Submit Spider for GPU72
#!/usr/bin/perl -w
######################################################
# submit_spider version 0.25
#
# Copyright 2014-2017 Chris Halsall et al.
# All rights reserved.
#
# Much thanks to "Bdot" for the delta to handle the
# new Primenet log-in method.
#
# Released under the GPL license version 2.0 or later.
# http://www.gnu.org/copyleft/gpl.html
#
# This is part of the GPU to 72 Project.
# http://www.gpu72.com/
#
# This software is provided with no warrantees. Use
# at your own risk.
# Updates:
#
# 2017.02.23
# Changed $PrimeNetURL to use https.
# Thanks to Sebastian "Brain" (from the Mersenne Forum)
# for the delta.
use strict;
use LWP::UserAgent;
use HTTP::Cookies;
##################################################
# Set these to be appropriate for your environment
#
# Change this if you use a web proxy.
my $PrimeNetURL = "https://www.mersenne.org/";
# Your PrimeNet username.
my $PNUsername = "YOUR_USERNAME";
# Your PrimeNet password.
my $PNPassword = "YOUR_PASSWORD";
# If you trust this script enough, you can have it delete the results file after successful submissions.
my $DeleteAfterSend = 0;
# The spider's log file. Use an explicit path to place the file somewhere other than the current directory.
my $SpiderLog = "spider.log";
# 0 for deep debugging; 1 for information; 2 for warnings; 3 for errors only; 4 or higher for silence.
my $LoggingLevel = 1;
# Set to 4 for crontab usage.
my $ConsoleLevel = 1;
#################################################
# You should not need to modify anything below...
#
my $Cookies = HTTP::Cookies->new;
my $LogOpen = 0;
# Change into the appropriate directory, if passed as a parameter. Intended for crontabs.
if (defined($ARGV[0])) {
if (! chdir ($ARGV[0])) {
print STDERR "ERROR: Cannot change to directory \"${ARGV[0]}\n";
exit;
}
}
Log(1, "Submission spider starting...");
if (! -e "results.txt" || -z "results.txt") {
Log(2, "No results.txt file exists or it is empty. Exiting.");
LogClose();
exit;
}
# Attempt to log into Mersenne PrimeNet.
if (LogIntoPrimeNet($PNUsername, $PNPassword)) {
# Log in successful. Do the submissions...
DoSubmissions();
}
Log(1, "Spider has finished. Exiting.\n\n");
LogClose();
exit;
sub DoSubmissions {
my ($Now) = UTCString();
my $Success;
# Move the results file so it won't get clobbered.
rename("results.txt","submitting_${Now}.txt");
# Sleep for two seconds to ensure any other users of results.txt finish up.
sleep(2);
if (open (IN, "submitting_${Now}.txt")) {
while () {
$Success = DoSubmit($_);
if (! $Success) {
close (IN);
Log(3, "Submission not complete. Moving results file to \"not_completely_submitted_${Now}.txt\"");
rename("submitting_${Now}.txt", "not_completely_submitted_${Now}.txt");
return;
}
sleep(1); # To lessen the load on PrimeNet
}
} else {
Log(3, "Weird. We couldn't open \"submitting_${Now}.txt\"");
rename("submitting_${Now}.txt", "not_completely_submitted_${Now}.txt");
return;
}
close (IN);
if ($DeleteAfterSend) {
Log(1, "Submission complete. Deleting results file.");
unlink("submitting_${Now}.txt");
} else {
Log(1, "Submission complete. Moving results file to \"submitted_${Now}.txt\"");
rename("submitting_${Now}.txt", "submitted_${Now}.txt");
}
}
sub DoSubmit() {
my ($Line) = $_;
my ($Page, $Succ, $Text);
my ($Result, $GHzDays, $Candidate);
my $Success = 1;
if ($Line =~ /no factor for (M\d*)/ || $Line =~ /(M\d*) has a factor/
|| $Line =~ /(M\d*) no factor from/) {
$Candidate = $1;
$Page = "manual_result/";
($Succ, $Text) = TalkToPrimeNet($Page, $Line);
if ($Succ) {
($Result, $GHzDays) = ParseResponse($Text);
if ($Result == 0) {
Log(1, "${Candidate} submitted; ${GHzDays} GHz Days credit.");
} elsif ($Result == 40) {
Log(2, "${Candidate} result not needed.");
} else {
# Probably want to handle other codes non-fatally in the future, such as "Database not available".
Log(3, "Error from PrimeNet. Code: ${Result}; Message: \"${Text}\"");
$Success = 0;
}
} else {
Log(3, "Error from Network. Message: \"${Text}\"");
$Success = 0;
}
}
return ($Success);
}
sub ParseResponse {
my ($Result) = @_;
if ($Result =~ /CPU credit is (.*) GHz-days./) {
return (0, $1);
}
if ($Result =~ /Error code: (\d*), error text:(.*)\n/) {
return ($1, $2);
}
return (99, $Result);
}
sub LogIntoPrimeNet {
my ($UN, $PW) = @_;
my ($ua, $Response, $Success, $Text);
my $Page = '/account/default.php';
Log(1, "Attempting to log into PrimeNet. This can take a little while...");
$ua = LWP::UserAgent->new();
$ua->agent("GPU_to_72 Submission Spider (v 0.25)");
$ua->timeout(20);
$ua->cookie_jar($Cookies);
$Response = $ua->post("${PrimeNetURL}${Page}", { 'user_login' => $UN,
'user_password' => $PW } );
if ($Response->is_success) {
$Text = $Response->decoded_content();
$Success = 1;
Log(0, "Response was:\n${Text}\n\n");
} else {
$Text = $Response->status_line;
Log(3, "Bad response:\n${Text}\n\n");
$Success = 0;
}
return $Success;
}
sub TalkToPrimeNet {
my ($Page, $Data) = @_;
my ($Browser, $Response, $Success, $Text);
$Success = 1;
$Browser = LWP::UserAgent->new;
$Browser->agent("GPU_to_72 Submission Spider");
$Browser->timeout(20);
$Browser->cookie_jar($Cookies);
$Response = $Browser->post("${PrimeNetURL}${Page}", { 'data' => $Data } );
if ($Response->is_success) {
$Text = $Response->content;
Log(0, "Response was:\n${Text}\n\n");
} else {
$Text = $Response->status_line;
Log(3, "Bad response:\n${Text}\n\n");
$Success = 0;
}
return ($Success, $Text);
}
sub Log {
my ($Level, $Msg) = @_;
my @Levels = ("DEEP", "INFO", "WARN", "ERR ");
my $Now = UTCString();
if (! $LogOpen) {
if (open (LOG, ">>${SpiderLog}")) {
$LogOpen = 1;
} else {
print STDERR "ERROR: Could not open log file: \"${SpiderLog}\". Exiting\n";
exit;
}
}
if ($Level >= $LoggingLevel) {
print LOG "${Now} ${Levels[$Level]}: ${Msg}\n";
}
if ($Level >= $ConsoleLevel) {
print "${Now} ${Levels[$Level]}: ${Msg}\n";
}
}
sub LogClose {
if ($LogOpen) {
close(LOG);
}
}
sub UTCString {
my ($sec,$min,$hour,$mday,$mon,$year) = gmtime(time);
return sprintf("%04d%02d%02d_%02d%02d%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
}
|