package UserAgentWithStats; =pod #### ## author: bliako ## date: 03/06/2018 ## A subclass of LWP::UserAgent which adds a handler ## (if requested) to the "request_send" phase of LWP's request() ## the purpose of which is to increment our internal counter ## every time a request is sent by LWP. ## There are three counters here, one counts the hits and the ## other two record the time started (unix epoch) recording and tim,e last-hit occured. ## The aim is to know the amount of hits and the time interval ## they occured in. Therefore each time a hit happens, the hit ## counter is incremented and "hit-count-time-last-hit" variable is ## updated with the current time(). There is also another time-keeping ## variable which is "hit-count-time-stopped". It records the time ## when the counter is turned off. So 2 time intervals for the same number ## of hits from turn-on to 1) time-last-hit and 2) time-stopped (or now if not stopped) ## #### use UserAgentWithStats; my $ua = UserAgentWithStats->new(); my $urlstr = "http://www.python.org"; $ua->hit_counter_on(); print "$0 : hit count is now: ".$ua->hit_counter_statistics_toString()."\n"; print "$0 : hitting site '$urlstr' ...\n"; my $aresponse = $ua->get($urlstr); if ($aresponse->is_success) { print "$0 : success hitting $urlstr\n"; } else { die "$urlstr : $aresponse->status_line"; } print "$0 : hit count is now: ".$ua->hit_counter_statistics_toString()."\n"; my ($T1, $T2, $numhits) = @{$ua->hit_counter_statistics()}; print "$0 : resetting hit counter ...\n"; $ua->hit_counter_reset(); print "$0 : hit count is now: ".$ua->hit_counter_statistics_toString()."\n"; =cut use strict; use warnings; use parent 'LWP::UserAgent'; our $VERSION = '1.0'; sub new { my $class = $_[0]; my $params = $_[1]; my $parent = ( caller(1) )[3] || "N/A"; my $whoami = ( caller(0) )[3]; # call parent constructor my $self = $class->SUPER::new(); # extra attributes in class $self->{'ua-stats'} = { # UA can have callbacks defined so when a request is made # a counter is hit. When doing hit counts we record thetime hit count was turned on too 'hit-count-time-started' => -1, # unix epoch, 'hit-count-time-stopped' => -1, # ditto 'hit-count-time-last-hit' => -1, # ditto 'hit-count' => 0, }; bless($self, $class); return $self; } # increment a count each time a request is made, can also record the url etc. sub hit_counter_on { my $self = $_[0]; $self->add_handler( 'request_send', sub { my($response, $ua, $h) = @_; $self->register_a_hit(); return undef # we bloody need this }, ('owner' => 'hit_counter_on') # use this id for when removing it ); # reset previous counter and set the time when recording started $self->hit_counter_reset(); } # increments the hit counter by 1 sub increment_hit_count { $_[0]->{'ua-stats'}->{'ua-hit-count'} += 1 } # registers a hit meaning that hit counter is incremented by 1 and # last time a hit happens becomes current time. sub register_a_hit { my $self = $_[0]; $self->increment_hit_count(); $self->{'ua-stats'}->{'hit-count-time-last-hit'} = time; } sub hit_counter_reset { my $self = $_[0]; $self->{'ua-stats'}->{'ua-hit-count'} = 0; $self->{'ua-stats'}->{'hit-count-time-started'} = time; $self->{'ua-stats'}->{'hit-count-time-stopped'} = -1; $self->{'ua-stats'}->{'hit-count-time-last-hit'} = -1; } sub hit_counter_off { my $self = $_[0]; $self->remove_handler( 'request_send', # phase we set it in ('owner' => 'hit_counter_on') # our id to remove ); $self->{'ua-stats'}->{'hit-count-time-stopped'} = time; } sub hit_count { return $_[0]->{'ua-stats'}->{'ua-hit-count'} } sub time_interval_to_last_hit { my $self = $_[0]; return $self->{'ua-stats'}->{'hit-count-time-last-hit'} == -1 ? # no hits yet 0 : #( # hits recorded $self->{'ua-stats'}->{'hit-count-time-last-hit'} - $self->{'ua-stats'}->{'hit-count-time-started'} ; #) } sub time_interval_to_now_or_when_stopped { my $self = $_[0]; return $self->{'ua-stats'}->{'hit-count-time-stopped'} == -1 ? # if hit-counting is still on, then time interval is up to now time - $self->{'ua-stats'}->{'hit-count-time-started'} : #( # else hit-counting was turned off, so give last time interval $self->{'ua-stats'}->{'hit-count-time-stopped'} - $self->{'ua-stats'}->{'hit-count-time-started'} ; #) } # returns an arrayref of [TimeTimerval, Hits] # see below for a string equivalent of this sub hit_counter_statistics { my $self = $_[0]; return [ $self->time_interval_to_last_hit(), $self->time_interval_to_now_or_when_stopped(), $self->hit_count() ] } sub hit_counter_statistics_toString { my ($T1, $T2, $H) = @{$_[0]->hit_counter_statistics()}; return "$H hits over $T1 s (to last hit) or over $T2 s (to now/when stopped) (" .sprintf("%.2f", 3600*$H/($T1==0?($T1+1):$T1)) ." or ".sprintf("%.2f", 3600*$H/($T2==0?($T2+1):$T2)) ." hits/hour)" ; } 1; __END__