File Coverage

blib/lib/JSON/RPC/LWP.pm
Criterion Covered Total %
statement 11 13 84.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 16 18 88.8


line stmt bran cond sub pod time code
1             package JSON::RPC::LWP;
2             BEGIN {
3 4     4   123377 $JSON::RPC::LWP::VERSION = '0.006';
4             }
5 4     4   108 use 5.008;
  4         14  
  4         315  
6 4     4   4045 use URI 1.58;
  4         38747  
  4         115  
7 4     4   6542 use LWP::UserAgent;
  4         952204  
  4         151  
8 4     4   15366 use JSON::RPC::Common;
  0            
  0            
9             use JSON::RPC::Common::Marshal::HTTP; # uses Moose
10              
11             use Moose::Util::TypeConstraints;
12              
13             # might as well use it, it gets loaded anyway
14             use JSON::RPC::Common::TypeConstraints qw(JSONValue);
15              
16             subtype 'JSON.RPC.Version'
17             => as 'Str'
18             => where {
19             $_ eq '1.0' ||
20             $_ eq '1.1' ||
21             $_ eq '2.0'
22             };
23              
24             coerce 'JSON.RPC.Version'
25             => from 'Int',
26             => via {
27             $_.'.0'
28             }
29             ;
30              
31             use namespace::clean 0.20;
32             use Moose;
33              
34             has agent => (
35             is => 'rw',
36             isa => 'Maybe[Str]',
37             lazy => 1,
38             default => sub{
39             my($self) = @_;
40             $self->_agent;
41             },
42             trigger => sub{
43             my($self,$agent) = @_;
44             unless( defined $agent ){
45             $agent = $self->_agent;
46             }
47             if( length $agent ){
48             if( substr($agent,-1) eq ' ' ){
49             $agent .= $self->_agent;
50             }
51             }
52             $self->{agent} = $agent;
53             $self->ua->agent($agent);
54             $self->marshal->user_agent($agent);
55             }
56             );
57              
58             has _agent => (
59             is => 'ro',
60             isa => 'Str',
61             lazy_build => 1,
62             builder => '_build_agent',
63             init_arg => undef,
64             );
65             sub _build_agent{
66             my($self) = @_;
67             my $class = blessed($self) || $self;
68              
69             no strict qw'vars refs';
70             if( $class eq __PACKAGE__ ){
71             return "JSON-RPC-LWP/$VERSION"
72             }else{
73             my $version = ${$class.'::VERSION'};
74             if( $version ){
75             return "$class/$version";
76             }else{
77             return $class;
78             }
79             }
80             }
81              
82             my @ua_handles = qw{
83             timeout
84             proxy
85             no_proxy
86             env_proxy
87             from
88             credentials
89             };
90              
91             has ua => (
92             is => 'rw',
93             isa => 'LWP::UserAgent',
94             default => sub{
95             my $lwp = LWP::UserAgent->new(
96             env_proxy => 1,
97             keep_alive => 1,
98             parse_head => 0,
99             );
100             },
101             handles => \@ua_handles,
102             );
103              
104             my @marshal_handles = qw{
105             prefer_get
106             rest_style_methods
107             prefer_encoded_get
108             };
109              
110             has marshal => (
111             is => 'rw',
112             isa => 'JSON::RPC::Common::Marshal::HTTP',
113             default => sub{
114             JSON::RPC::Common::Marshal::HTTP->new;
115             },
116             handles => \@marshal_handles,
117             );
118              
119             my %from = (
120             map( { $_, 'ua' } @ua_handles ),
121             map( { $_, 'marshal' } @marshal_handles ),
122             );
123              
124             sub BUILD{
125             my($self,$args) = @_;
126              
127             while( my($key,$value) = each %$args ){
128             if( exists $from{$key} ){
129             my $attr = $from{$key};
130             $self->$attr->$key($value);
131             }
132             }
133             }
134              
135             has version => (
136             is => 'rw',
137             isa => 'JSON.RPC.Version',
138             default => '2.0',
139             coerce => 1,
140             );
141              
142             has previous_id => (
143             is => 'ro',
144             isa => JSONValue,
145             init_arg => undef,
146             writer => '_previous_id',
147             predicate => 'has_previous_id',
148             clearer => 'clear_previous_id',
149             );
150              
151             # default id generator is a simple incrementor
152             my $default_id_gen = sub{
153             my($self,$prev) = @_;
154             $prev ||= 0;
155             return $prev + 1;
156             };
157              
158             has id_generator => (
159             is => 'rw',
160             isa => 'Maybe[CodeRef]',
161             default => sub{ $default_id_gen },
162             trigger => sub{
163             my($self,$coderef) = @_;
164             unless( $coderef ){
165             $self->{id_generator} = $default_id_gen;
166             }
167             },
168             );
169              
170             sub call{
171             my($self,$uri,$method,@rest) = @_;
172              
173             $uri = URI->new($uri) unless blessed $uri;
174              
175             my $params;
176             if( @rest == 1 and ref $rest[0] ){
177             ($params) = @rest;
178             }else{
179             $params = \@rest;
180             }
181             $self->{count}++;
182              
183             my $next_id;
184             if( $self->has_previous_id ){
185             $next_id = $self->id_generator->($self);
186             }else{
187             $next_id = $self->id_generator->($self,$self->previous_id);
188             }
189             $self->_previous_id($next_id);
190              
191             my $request = $self->marshal->call_to_request(
192             JSON::RPC::Common::Procedure::Call->inflate(
193             jsonrpc => $self->version,
194             id => $next_id,
195             method => $method,
196             params => $params,
197             ),
198             uri => $uri,
199             );
200             my $response = $self->ua->request($request);
201             my $result = $self->marshal->response_to_result($response);
202              
203             return $result;
204             }
205              
206             sub notify{
207             my($self,$uri,$method,@rest) = @_;
208              
209             $uri = URI->new($uri) unless blessed $uri;
210              
211             my $params;
212             if( @rest == 1 and ref $rest[0] ){
213             $params = $rest[0];
214             }else{
215             $params = \@rest;
216             }
217             $self->{count}++;
218              
219             my $request = $self->marshal->call_to_request(
220             JSON::RPC::Common::Procedure::Call->inflate(
221             jsonrpc => $self->version,
222             method => $method,
223             params => $params,
224             ),
225             uri => $uri,
226             );
227             my $response = $self->ua->request($request);
228              
229             return $response;
230             }
231              
232             no Moose;
233             __PACKAGE__->meta->make_immutable;
234             1;
235             #ABSTRACT: Use any version of JSON RPC over any libwww supported transport protocols.
236              
237             __END__
238             =pod
239              
240             =head1 NAME
241              
242             JSON::RPC::LWP - Use any version of JSON RPC over any libwww supported transport protocols.
243              
244             =head1 VERSION
245              
246             version 0.006
247              
248             =head1 SYNOPSIS
249              
250             use JSON::RPC::LWP;
251              
252             my $rpc = JSON::RPC::LWP->new(
253             from => 'name@address.com',
254             agent => 'Example ',
255             );
256              
257             my $login = $rpc->call(
258             'https://us1.lacunaexpanse.com/empire', # uri
259             'login', # service
260             [$empire,$password,$api_key] # JSON container
261             );
262              
263             =head1 METHODS
264              
265             =over 4
266              
267             =item C<< call( $uri, $method ) >>
268              
269             =item C<< call( $uri, $method, {...} ) >>
270              
271             =item C<< call( $uri, $method, [...] ) >>
272              
273             =item C<< call( $uri, $method, param1, param2, ... ) >>
274              
275             Initiate a L<JSON::RPC::Common::Procedure::Call>
276              
277             Uses L<LWP::UserAgent> for transport.
278              
279             Then returns a L<JSON::RPC::Common::Procedure::Return>
280              
281             =item C<< notify( $uri, $method ) >>
282              
283             =item C<< notify( $uri, $method, {...} ) >>
284              
285             =item C<< notify( $uri, $method, [...] ) >>
286              
287             =item C<< notify( $uri, $method, param1, param2, ... ) >>
288              
289             Initiate a L<JSON::RPC::Common::Procedure::Call>
290              
291             Uses L<LWP::UserAgent> for transport.
292              
293             Basically this is the same as a call, except without the C<id> key,
294             and doesn't expect a JSON RPC result.
295              
296             Returns the L<HTTP::Response> from L<C<ua>|LWP::UserAgent>.
297              
298             To check for an error use the C<is_error> method of the returned
299             response object.
300              
301             =back
302              
303             =head1 ATTRIBUTES
304              
305             =over 4
306              
307             =item C<previous_id>
308              
309             Returns the previous id used in the C<call()> method.
310              
311             =item C<has_previous_id>
312              
313             Returns true if the C<previous_id> has any value associated with it.
314              
315             =item C<clear_previous_id>
316              
317             Clears the previous id, useful for generators that do something different
318             the first time they are used.
319              
320             =item C<id_generator>
321              
322             This is used for generating the next id to be used in the C<call()> method.
323              
324             The default is just an incrementing subroutine.
325              
326             The call-back gets called with 1 or 2 arguments.
327              
328             The first is the object which is calling it.
329              
330             The secound is the previous id, if the object has one.
331              
332             The C<previous_id> attribute gets set to the return value of the call-back
333             B<before> the call actually goes through
334              
335             The reason for this attribute, is to make it easy to change the order
336             of the id's that get used.
337              
338             =item C<version>
339              
340             The JSON RPC version to use. one of 1.0 1.1 or 2.0
341              
342             =item C<agent>
343              
344             Get/set the product token that is used to identify the user agent on the network.
345             The agent value is sent as the "User-Agent" header in the requests.
346             The default is the string returned by the C<_agent> attribute (see below).
347              
348             If the agent ends with space then the C<_agent> string is appended to it.
349              
350             The user agent string should be one or more simple product identifiers
351             with an optional version number separated by the "/" character.
352              
353             Setting this will also set C<< ua->agent >> and C<< marshal->user_agent >>.
354              
355             =item C<_agent>
356              
357             Returns the default agent identifier.
358             This is a string of the form "JSON-RPC-LWP/#.###", where "#.###" is
359             substituted with the version number of this library.
360              
361             =item C<marshal>
362              
363             An instance of L<JSON::RPC::Common::Marshal::HTTP>.
364             This is used to convert from a L<JSON::RPC::Common::Procedure::Call>
365             to a L<HTTP::Request>,
366             and from an L<HTTP::Response> to a L<JSON::RPC::Common::Procedure::Return>.
367              
368             B<Attributes delegated to C<marshal>>
369              
370             =over 4
371              
372             =item C<prefer_get>
373              
374             =item C<rest_style_methods>
375              
376             =item C<prefer_encoded_get>
377              
378             =back
379              
380             =item C<ua>
381              
382             An instance of L<LWP::UserAgent>.
383             This is used for the transport layer.
384              
385             B<Attributes delegated to C<ua>>
386              
387             =over 4
388              
389             =item C<timeout>
390              
391             =item C<proxy>
392              
393             =item C<no_proxy>
394              
395             =item C<env_proxy>
396              
397             =item C<from>
398              
399             =item C<credentials>
400              
401             =back
402              
403             =back
404              
405             =for Pod::Coverage BUILD
406              
407             =head1 AUTHOR
408              
409             Brad Gilbert <b2gills@gmail.com>
410              
411             =head1 COPYRIGHT AND LICENSE
412              
413             This software is copyright (c) 2011 by Brad Gilbert.
414              
415             This is free software; you can redistribute it and/or modify it under
416             the same terms as the Perl 5 programming language system itself.
417              
418             =cut
419