File Coverage

blib/lib/WebService/Antigate.pm
Criterion Covered Total %
statement 57 68 83.8
branch 14 24 58.3
condition 19 43 44.1
subroutine 12 14 85.7
pod 7 7 100.0
total 109 156 69.8


line stmt bran cond sub pod time code
1             package WebService::Antigate;
2              
3 4     4   192719 use strict;
  4         34  
  4         98  
4 4     4   1640 use LWP::UserAgent ();
  4         141546  
  4         105  
5 4     4   39 use Carp ();
  4         9  
  4         1062  
6              
7             our $VERSION = '0.10';
8              
9             our $DOMAIN = 'anti-captcha.com'; # service domain often changes because of the abuse
10             our $WAIT = 220; # default time that recognize() or upload() can work
11             our $DELAY = 5; # sleep time before retry while uploading or recognizing captcha
12             our $FNAME = 'captcha.jpg'; # default name of the uploaded captcha if name not specified and can't be determined
13              
14             my %API_VERSIONS = (
15             1 => sub { require WebService::Antigate::V1; 'WebService::Antigate::V1' },
16             2 => sub { require WebService::Antigate::V2; 'WebService::Antigate::V2' },
17             );
18              
19             sub new {
20 8     8 1 4944 my ($class, %args) = @_;
21            
22 8 100       231 Carp::croak "Option `key' should be specified" unless defined $args{key};
23            
24 7         28 my $self = {};
25 7         31 $self->{key} = $args{key};
26 7         38 $self->{wait} = $args{wait};
27 7         23 $self->{attempts} = $args{attempts};
28 7   33     108 $self->{ua} = $args{ua} || LWP::UserAgent->new();
29 7   66     8436 $self->{domain} = $args{domain} || $DOMAIN;
30 7   66     33 $self->{delay} = $args{delay} || $DELAY;
31 7   100     39 $self->{scheme} = $args{scheme} || 'http';
32 7         23 $self->{subdomain} = $args{subdomain};
33 7   100     33 $self->{api_version} = $args{api_version} || 1;
34            
35 7 50 33     52 $self->{wait} = $WAIT unless defined($self->{wait}) || defined($self->{attempts});
36            
37 7 50       28 Carp::croak "Unsupported `api_version' specified" unless exists $API_VERSIONS{ $self->{api_version} };
38 7 100       74 bless $self, $class eq __PACKAGE__ ? $API_VERSIONS{ $self->{api_version} }->() : $class;
39             }
40              
41             # generate sub's for get/set object properties using closure
42             foreach my $key (qw(key wait attempts ua scheme domain subdomain delay)) {
43 4     4   32 no strict 'refs';
  4         13  
  4         2142  
44             *$key = sub {
45 2     2   658 my $self = shift;
46            
47 2 50       34 return $self->{$key} = $_[0] if defined $_[0];
48 0         0 return $self->{$key};
49             }
50             }
51              
52             sub errno {
53 4     4 1 26 return $_[0]->{errno};
54             }
55              
56             sub errstr {
57 1     1 1 12 return $_[0]->{errstr};
58             }
59              
60             sub upload {
61 2     2 1 31 my ($self, %opts) = @_;
62            
63 2         4 my $start = time();
64 2         4 my $attempts = 0;
65 2         4 my $captcha_id;
66            
67             do {
68 2         2 $attempts ++;
69 2         8 $captcha_id = $self->try_upload(%opts);
70             }
71             while ( !$captcha_id &&
72             ($self->{errno} eq 'ERROR_NO_SLOT_AVAILABLE' || $self->{errno} eq 'HTTP_ERROR') &&
73             (defined($self->{wait}) ? ( time() - $start ) < $self->{wait} : 1) &&
74             $attempts != $self->{attempts} &&
75             sleep( $self->{delay} )
76 2 0 0     4 );
      33        
      0        
      0        
      0        
77              
78 2         40 return $captcha_id;
79             }
80              
81             sub recognize {
82 4     4 1 16 my ($self, $id) = @_;
83            
84 4         9 my $start = time();
85 4         9 my $captcha_text;
86 4         10 my $attempts = 0;
87            
88             do
89             {
90 5         11 $attempts ++;
91 5         5004627 sleep( $self->{delay} );
92 5         117 $captcha_text = $self->try_recognize($id);
93             }
94             while ( !$captcha_text &&
95             ($self->{errno} eq 'CAPCHA_NOT_READY' || $self->{errno} eq 'HTTP_ERROR') &&
96             (defined($self->{wait}) ? ( time() - $start ) < $self->{wait} : 1) &&
97             $attempts != $self->{attempts}
98 4 50 66     9 );
      100        
      66        
      33        
99            
100 4         40 return $captcha_text;
101             }
102              
103             sub upload_and_recognize {
104 0     0 1 0 my ($self, %opts) = @_;
105            
106 0         0 my $captcha_id;
107 0 0       0 unless($captcha_id = $self->upload(%opts))
108             {
109 0         0 return undef;
110             }
111            
112 0         0 return $self->recognize($captcha_id);
113             }
114              
115             sub last_captcha_id {
116 2     2 1 8 my ($self) = @_;
117 2         8 return $self->{last_captcha_id};
118             }
119              
120             sub _name_by_signature {
121 4 100   4   130 if ($_[1] =~ /^\x47\x49\x46\x38(?:\x37|\x39)\x61/)
122             {
123 1         6 return 'captcha.gif';
124             }
125              
126 3 100       9 if ($_[1] =~ /^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A/)
127             {
128 1         9 return 'captcha.png';
129             }
130              
131 2 100       9 if ($_[1] =~ /^\xFF\xD8\xFF\xE0..\x4A\x46\x49\x46\x00/)
132             {
133 1         5 return 'captcha.jpg';
134             }
135            
136 1         5 return $FNAME;
137             }
138              
139             sub _name_by_file_signature {
140 0     0     my $self = shift;
141            
142 0 0         open my $fh, '<:raw', $_[0] or return $self->_name_by_signature('');
143 0           sysread($fh, my $buf, 20);
144 0           close $fh;
145 0           return $self->_name_by_signature($buf);
146             }
147              
148             1;
149              
150             __END__