File Coverage

blib/lib/Games/Lacuna/Client/RPC.pm
Criterion Covered Total %
statement 31 33 93.9
branch n/a
condition n/a
subroutine 11 11 100.0
pod n/a
total 42 44 95.4


line stmt bran cond sub pod time code
1             package Games::Lacuna::Client::RPC;
2             {
3             $Games::Lacuna::Client::RPC::VERSION = '0.003';
4             }
5 1     1   163 use 5.0080000;
  1         9  
  1         47  
6 1     1   7 use strict;
  1         2  
  1         59  
7 1     1   4 use warnings;
  1         2  
  1         34  
8 1     1   5 use Carp 'croak';
  1         3  
  1         78  
9 1     1   6 use Scalar::Util 'weaken';
  1         2  
  1         55  
10 1     1   1035 use Time::HiRes qw( sleep );
  1         2171  
  1         5  
11              
12 1     1   198 use Games::Lacuna::Client;
  1         2  
  1         33  
13              
14 1     1   1814 use IO::Interactive qw( is_interactive );
  1         6362  
  1         7  
15              
16             our @CARP_NOT = qw(
17             Games::Lacuna::Client
18             Games::Lacuna::Client::Alliance
19             Games::Lacuna::Client::Body
20             Games::Lacuna::Client::Buildings
21             Games::Lacuna::Client::Captcha
22             Games::Lacuna::Client::Empire
23             Games::Lacuna::Client::Inbox
24             Games::Lacuna::Client::Map
25             Games::Lacuna::Client::Stats
26             );
27              
28             use Exception::Class (
29 1         9 'LacunaException',
30             'LacunaRPCException' => {
31             isa => 'LacunaException',
32             description => 'The RPC service generated an error.',
33             fields => [qw(code text)],
34             },
35 1     1   1842 );
  1         18868  
36              
37 1     1   2886 use namespace::clean;
  1         36045  
  1         7  
38              
39 1     1   621 use Moose;
  0            
  0            
40              
41             extends 'JSON::RPC::LWP';
42              
43             has client => (
44             is => 'ro',
45             isa => 'Games::Lacuna::Client',
46             required => 1,
47             weak_ref => 1,
48             );
49              
50             # was always called with ( id => "1" )
51             has '+id_generator' => (
52             default => sub{sub{1}},
53             );
54              
55             around call => sub {
56             my $orig = shift;
57             my $self = shift;
58             my $uri = shift;
59             my $method = shift;
60             my $params = shift;
61              
62              
63             # Call the method. If a Captcha error is returned, attempt to handle it
64             # and re-call the method, up to 3 times
65             my $trying = 1;
66             my $is_interactive = is_interactive();
67             my $try_captcha = $self->{client}->open_captcha || $self->{client}->prompt_captcha;
68             my $captcha_attempts = 0;
69             my $res;
70              
71             while ($trying) {
72             $trying = 0;
73              
74             $res = $self->$orig($uri,$method,$params);
75              
76             # Throttle per 3.0 changes
77             sleep($self->{client}->rpc_sleep) if $self->{client}->rpc_sleep;
78              
79             if ($res and $res->has_error
80             and $res->error->code eq '1016'
81             and $is_interactive
82             and $try_captcha
83             and ++$captcha_attempts <= 3
84             ) {
85             my $captcha = $self->{client}->captcha;
86             my $browser;
87            
88             if ( $self->{client}->open_captcha ) {
89             $browser = $captcha->open_in_browser;
90             }
91            
92             if ( !defined $browser && $self->{client}->prompt_captcha ) {
93             $captcha->print_url;
94             }
95            
96             my $answer = $captcha->prompt_for_solution;
97            
98             $captcha->solve($answer);
99             $trying = 1;
100             }
101             }
102              
103             if ($self->{client}->{verbose_rpc}) {
104             my @tmp = @$params;
105             shift @tmp;
106             printf("RPC: %s(%s)\n",$method,@tmp);
107             }
108             $self->{client}->{total_calls}++;
109             $self->{client}{call_stats}{$method}++;
110              
111             LacunaRPCException->throw(
112             error => "RPC Error (" . $res->error->code . "): " . $res->error->message,
113             code => $res->error->code,
114             ## Note we don't use the key 'message'. Exception::Class stringifies based
115             ## on "message or error" attribute. For backwards compatiblity we don't
116             ## want to change how this object will stringify.
117             text => $res->error->message,
118             ) if $res->error;
119              
120             return $res->deflate;
121             };
122              
123              
124             no Moose;
125             __PACKAGE__->meta->make_immutable;
126             1;
127             __END__
128              
129             =head1 NAME
130              
131             Games::Lacuna::Client::RPC - The actual RPC client
132              
133             =head1 SYNOPSIS
134              
135             use Games::Lacuna::Client;
136              
137             =head1 DESCRIPTION
138              
139             =head1 EXCEPTIONS
140              
141             =head2 LacunaRPCException
142              
143             This exception is generated if the RPC call fails. It is an Exception::Class object that has the RPC error details.
144              
145             Attribute C<< $e->code >> contains the error code. Attribute C<< $e->text >> contains the error text.
146              
147             =head1 AUTHOR
148              
149             Steffen Mueller, E<lt>smueller@cpan.orgE<gt>
150              
151             =head1 COPYRIGHT AND LICENSE
152              
153             Copyright (C) 2010 by Steffen Mueller
154              
155             This library is free software; you can redistribute it and/or modify
156             it under the same terms as Perl itself, either Perl version 5.10.0 or,
157             at your option, any later version of Perl 5 you may have available.
158              
159             =cut