line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTTP::MultiGet::Role; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
1212017
|
use Modern::Perl; |
|
2
|
|
|
|
|
17
|
|
|
2
|
|
|
|
|
13
|
|
4
|
2
|
|
|
2
|
|
270
|
use Moo::Role; |
|
2
|
|
|
|
|
11
|
|
|
2
|
|
|
|
|
14
|
|
5
|
2
|
|
|
2
|
|
1775
|
use MooX::Types::MooseLike::Base qw(:all); |
|
2
|
|
|
|
|
13126
|
|
|
2
|
|
|
|
|
702
|
|
6
|
2
|
|
|
2
|
|
1056
|
use AnyEvent::HTTP::MultiGet; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
68
|
|
7
|
2
|
|
|
2
|
|
19
|
use AnyEvent; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
53
|
|
8
|
2
|
|
|
2
|
|
1539
|
use JSON qw(); |
|
2
|
|
|
|
|
16517
|
|
|
2
|
|
|
|
|
58
|
|
9
|
2
|
|
|
2
|
|
15
|
use Data::Dumper; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
118
|
|
10
|
2
|
|
|
2
|
|
14
|
use Carp qw(croak); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
94
|
|
11
|
2
|
|
|
2
|
|
12
|
use namespace::clean; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
17
|
|
12
|
2
|
|
|
2
|
|
1623
|
use Ref::Util qw(is_plain_arrayref); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
128
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
BEGIN { |
15
|
2
|
|
|
2
|
|
15
|
with 'Log::LogMethods','Data::Result::Moo'; |
16
|
|
|
|
|
|
|
} |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
our $AUTOLOAD; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 NAME |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
HTTP::MultiGet::Role - Role for building blocking/non-blocking AnyEvent friendly REST Clients |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 SYNOPSIS |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
package My::Rest::Class; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
use Modern::Perl; |
29
|
|
|
|
|
|
|
use Moo; |
30
|
|
|
|
|
|
|
BEGIN { with 'HTTP::MultiGet::Role' } |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub que_some_request { |
33
|
|
|
|
|
|
|
my ($self,$cb)=@_; |
34
|
|
|
|
|
|
|
my $request=HTTP::Request->new(GET=>'https://some_json_endpoint'); |
35
|
|
|
|
|
|
|
return $self->queue_request($request,$cb); |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Blocking Example |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# blocking context |
42
|
|
|
|
|
|
|
use My::Rest::Class; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
my $self=new My::Rest::Class; |
45
|
|
|
|
|
|
|
my $result=$self->some_request; |
46
|
|
|
|
|
|
|
die $result unless $result; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
NonBlocking Example |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# non blocking |
52
|
|
|
|
|
|
|
use AnyEvent::Loop; |
53
|
|
|
|
|
|
|
use My::Rest::Class; |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
my $self=new My::Rest::Class; |
56
|
|
|
|
|
|
|
my $id=$self->some_request(sub { |
57
|
|
|
|
|
|
|
my ($self,$id,$result,$request,$response)=@_; |
58
|
|
|
|
|
|
|
}); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
$obj->agent->run_next; |
61
|
|
|
|
|
|
|
AnyEvent::Loop::run; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head1 DESCRIPTION |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
In the real world we are often confronted with a situation of needing and or wanting blocking and non-blocking code, but we normally only have time to develop one or the other. This class provided an AnyEvent friendly framework that solves some of the issues involved in creating both with 1 code base. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
The solution presented by this module is to simply develop the non blocking interface and dynamically AUTOLOAD the blocking interface as needed. One of the major advantages of this model of coding is it becomes possible to create asyncronous calls in what looks like syncronous code. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
More documentation comming soon.. time permitting. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=cut |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
our %MULTIGET_ARRGS=( |
74
|
|
|
|
|
|
|
timeout=>300, |
75
|
|
|
|
|
|
|
max_que_count=>20, |
76
|
|
|
|
|
|
|
); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
our $VERSION=$HTTP::MultiGet::VERSION; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head1 OO Declarations |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
This section documents the Object Declarations. ALl of these arguments are optional and autogenerated on demand if not passed into the constructor. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
agnet: AnyEvent::HTTP::MultiGet object |
85
|
|
|
|
|
|
|
json: JSON object |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Run Time State Settings ( modify at your own risk!! ) |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
is_blocking: Boolean ( denotes if we are in a blocking context or not ) |
90
|
|
|
|
|
|
|
block_for_more: array ref of additoinal ids to block for in a blocking context |
91
|
|
|
|
|
|
|
pending: hash ref that outbound request objects |
92
|
|
|
|
|
|
|
result_map: hash ref that contains the inbound result objects |
93
|
|
|
|
|
|
|
jobs: anonymous hash, used to keep our results that never hit IO |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
Success Range for parsing json |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
As of version 1.017 a range of codes can now be set to validate if the response should be parsed as json |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
code_parse_start: 199 # if the response code is greater than |
100
|
|
|
|
|
|
|
code_parse_end: 300 # if the response code is less than |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=cut |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
has agent=>( |
105
|
|
|
|
|
|
|
is=>'ro', |
106
|
|
|
|
|
|
|
isa=>Object, |
107
|
|
|
|
|
|
|
required=>1, |
108
|
|
|
|
|
|
|
default=>sub { |
109
|
|
|
|
|
|
|
new AnyEvent::HTTP::MultiGet(%MULTIGET_ARRGS) |
110
|
|
|
|
|
|
|
}, |
111
|
|
|
|
|
|
|
lazy=>1, |
112
|
|
|
|
|
|
|
); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
has jobs=>( |
116
|
|
|
|
|
|
|
is=>'ro', |
117
|
|
|
|
|
|
|
default=>sub { {} }, |
118
|
|
|
|
|
|
|
lazy=>1, |
119
|
|
|
|
|
|
|
); |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
has is_blocking=>( |
122
|
|
|
|
|
|
|
is=>'rw', |
123
|
|
|
|
|
|
|
isa=>Bool, |
124
|
|
|
|
|
|
|
default=>0, |
125
|
|
|
|
|
|
|
lazy=>1, |
126
|
|
|
|
|
|
|
); |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
has block_for_more=>( |
129
|
|
|
|
|
|
|
is=>'rw', |
130
|
|
|
|
|
|
|
isa=>ArrayRef, |
131
|
|
|
|
|
|
|
default=>sub { [] }, |
132
|
|
|
|
|
|
|
lazy=>1, |
133
|
|
|
|
|
|
|
); |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
has json =>( |
136
|
|
|
|
|
|
|
is=>'ro', |
137
|
|
|
|
|
|
|
isa=>Object, |
138
|
|
|
|
|
|
|
required=>1, |
139
|
|
|
|
|
|
|
lazy=>1, |
140
|
|
|
|
|
|
|
default=>sub { |
141
|
|
|
|
|
|
|
my $json=JSON->new->allow_nonref(&JSON::true)->utf8->relaxed(&JSON::true); |
142
|
|
|
|
|
|
|
return $json; |
143
|
|
|
|
|
|
|
}, |
144
|
|
|
|
|
|
|
); |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
has pending=>( |
147
|
|
|
|
|
|
|
is=>'ro', |
148
|
|
|
|
|
|
|
isa=>HashRef, |
149
|
|
|
|
|
|
|
required=>1, |
150
|
|
|
|
|
|
|
default=>sub { {} }, |
151
|
|
|
|
|
|
|
lazy=>1, |
152
|
|
|
|
|
|
|
); |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
has result_map=>( |
155
|
|
|
|
|
|
|
is=>'ro', |
156
|
|
|
|
|
|
|
isa=>HashRef, |
157
|
|
|
|
|
|
|
required=>1, |
158
|
|
|
|
|
|
|
default=>sub { {} }, |
159
|
|
|
|
|
|
|
lazy=>1, |
160
|
|
|
|
|
|
|
); |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
has code_parse_start=>( |
163
|
|
|
|
|
|
|
is=>'rw', |
164
|
|
|
|
|
|
|
isa=>Int, |
165
|
|
|
|
|
|
|
default=>199 |
166
|
|
|
|
|
|
|
); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
has code_parse_end=>( |
169
|
|
|
|
|
|
|
is=>'rw', |
170
|
|
|
|
|
|
|
isa=>Int, |
171
|
|
|
|
|
|
|
default=>300 |
172
|
|
|
|
|
|
|
); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head1 OO Methods |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=over 4 |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=item * my $result=$self->new_true({qw( some data )}); |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
Returns a new true Data::Result object. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=item * my $result=$self->new_false("why this failed") |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Returns a new false Data::Result object |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item * my $code=$self->cb; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Internal object used to construct the global callback used for all http responses. You may need to overload this method in your own class. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=cut |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub cb { |
193
|
2
|
|
|
2
|
1
|
24
|
my ($self)=@_; |
194
|
2
|
100
|
|
|
|
10
|
return $self->{cb} if exists $self->{cb}; |
195
|
|
|
|
|
|
|
my $code=sub { |
196
|
2
|
|
|
2
|
|
7
|
my ($mg,$ref,$response)=@_; |
197
|
2
|
50
|
|
|
|
6
|
my $request=is_plain_arrayref($ref) ? $ref->[0] : $ref; |
198
|
2
|
50
|
|
|
|
35
|
unless(exists $self->pending->{$request}) { |
199
|
|
|
|
|
|
|
|
200
|
0
|
|
|
|
|
0
|
$self->log_error("Request wasn't found!"); |
201
|
0
|
|
|
|
|
0
|
croak "Request Object wasn't found!"; |
202
|
|
|
|
|
|
|
} |
203
|
2
|
|
|
|
|
19
|
my ($id,$cb)=@{delete $self->pending->{$request}}; |
|
2
|
|
|
|
|
33
|
|
204
|
2
|
|
|
|
|
23
|
my $result=$self->parse_response($request,$response); |
205
|
2
|
|
|
|
|
450
|
$cb->($self,$id,$result,$request,$response); |
206
|
1
|
|
|
|
|
7
|
}; |
207
|
1
|
|
|
|
|
3
|
$self->{cb}=$code; |
208
|
1
|
|
|
|
|
7
|
return $code; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=item * my $result=$self->parse_response($request,$response); |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
Returns a Data::Result object, if true it contains the parsed result object, if false it contains why it failed. If you are doing anything other than parsing json on a 200 to 299 response you will need to overload this method. |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=cut |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub parse_response { |
218
|
309
|
|
|
309
|
1
|
373914
|
my ($self,$request,$response)=@_; |
219
|
|
|
|
|
|
|
|
220
|
309
|
|
|
|
|
837
|
my $content=$response->decoded_content; |
221
|
309
|
50
|
|
|
|
34051
|
$content='' unless defined($content); |
222
|
309
|
100
|
100
|
|
|
753
|
if($response->code >$self->code_parse_start && $response->code <$self->code_parse_end) { |
223
|
301
|
50
|
33
|
|
|
19653
|
if(length($content)!=0 and $content=~ /^\s*[\[\{\"]/s) { |
224
|
301
|
|
|
|
|
530
|
my $data=eval {$self->json->decode($content)}; |
|
301
|
|
|
|
|
4877
|
|
225
|
301
|
50
|
|
|
|
3625
|
if($@) { |
226
|
0
|
|
|
|
|
0
|
return $self->new_false("Code: [".$response->code."] JSON Decode error [$@] Content: $content"); |
227
|
|
|
|
|
|
|
} else { |
228
|
301
|
|
|
|
|
905
|
return $self->new_true($data); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
} else { |
231
|
0
|
|
|
|
|
0
|
return $self->new_true($content,$response); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
} else { |
234
|
8
|
|
|
|
|
467
|
return $self->new_false("Code: [".$response->code."] http error [".$response->status_line."] Content: $content"); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=item * my $id=$self->queue_request($request,$cb|undef); |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Returns an Id for the qued request. If $cb is undef then the default internal blocking callback is used. |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=cut |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub queue_request { |
245
|
2
|
|
|
2
|
1
|
7471
|
my ($self,$request,$cb)=@_; |
246
|
2
|
50
|
|
|
|
8
|
$cb=$self->get_block_cb unless defined($cb); |
247
|
2
|
|
|
|
|
47
|
my $id=$self->agent->add_cb($request,$self->cb); |
248
|
2
|
50
|
|
|
|
8
|
my $req=is_plain_arrayref($request) ? $request->[0] : $request; |
249
|
2
|
|
|
|
|
43
|
$self->pending->{$req}=[$id,$cb]; |
250
|
2
|
|
|
|
|
62
|
return $id; |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=item * my $id=$self->queue_result($cb,$result); |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Alows for result objects to look like they were placed in the the job que but wern't. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Call back example |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub { |
260
|
|
|
|
|
|
|
my ($self,$id,$result,undef,undef)=@_; |
261
|
|
|
|
|
|
|
# 0 Current object class |
262
|
|
|
|
|
|
|
# 1 fake_id |
263
|
|
|
|
|
|
|
# 2 Data::Result Object ( passed into $self->queue_result ) |
264
|
|
|
|
|
|
|
# 3 undef |
265
|
|
|
|
|
|
|
# 4 undef |
266
|
|
|
|
|
|
|
}; |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=cut |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub queue_result { |
271
|
4
|
|
|
4
|
1
|
4950
|
my ($self,$cb,$result)=@_; |
272
|
4
|
100
|
|
|
|
14
|
$cb=\&block_cb unless $cb; |
273
|
4
|
50
|
|
|
|
11
|
$result=$self->new_false("unknown error") unless defined($result); |
274
|
4
|
|
|
|
|
8
|
my $id; |
275
|
|
|
|
|
|
|
$id=$self->agent->add_result(sub { |
276
|
4
|
|
|
4
|
|
13
|
$cb->($self,$id,$result,undef,undef); |
277
|
4
|
|
|
|
|
132
|
}); |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub has_fake_jobs { |
281
|
0
|
|
|
0
|
0
|
0
|
return $_[0]->agent->has_fake_jobs; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=item * my $results=$self->block_on_ids(@ids); |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Scalar context returns an array ref. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=item * my @results=$self->block_on_ids(@ids); |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Returns a list of array refrences. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Each List refrence contains the follwing |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
0: Data::Result |
295
|
|
|
|
|
|
|
1: HTTP::Request |
296
|
|
|
|
|
|
|
2: HTTP::Result |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
Example |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
my @results=$self->block_on_ids(@ids); |
301
|
|
|
|
|
|
|
foreach my $set (@results) { |
302
|
|
|
|
|
|
|
my ($result,$request,$response)=@{$set}; |
303
|
|
|
|
|
|
|
if($result) |
304
|
|
|
|
|
|
|
... |
305
|
|
|
|
|
|
|
} else { |
306
|
|
|
|
|
|
|
... |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=cut |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub block_on_ids { |
313
|
6
|
|
|
6
|
1
|
23
|
my ($self,@ids)=@_; |
314
|
6
|
|
|
|
|
17
|
my @init=@ids; |
315
|
|
|
|
|
|
|
|
316
|
6
|
|
|
|
|
109
|
$self->agent->block_for_results_by_id(@ids); |
317
|
6
|
|
|
|
|
772
|
my $ref={}; |
318
|
|
|
|
|
|
|
|
319
|
6
|
|
|
|
|
11
|
while($#{$self->block_for_more}!=-1) { |
|
6
|
|
|
|
|
105
|
|
320
|
0
|
|
|
|
|
0
|
@ids=@{$self->block_for_more}; |
|
0
|
|
|
|
|
0
|
|
321
|
0
|
|
|
|
|
0
|
@{$self->block_for_more}=(); |
|
0
|
|
|
|
|
0
|
|
322
|
0
|
|
|
|
|
0
|
$self->agent->run_next; |
323
|
0
|
|
|
|
|
0
|
$self->agent->block_for_results_by_id(@ids); |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
6
|
|
|
|
|
126
|
my $results=[delete @{$self->result_map}{@init}]; |
|
6
|
|
|
|
|
112
|
|
327
|
6
|
50
|
|
|
|
69
|
return wantarray ? @{$results} : $results; |
|
0
|
|
|
|
|
0
|
|
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=item * $self->add_ids_for_blocking(@ids); |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
This method solves the chicken and the egg senerio when a calback generates other callbacks. In a non blocking context this is fine, but in a blocking context there are 2 things to keep in mind: 1. The jobs created by running the inital request didn't exist when the id was created. 2. The outter most callback id must always be used when processing the final callback or things get wierd. |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
The example here is a litteral copy paste from L<Net::AppDynamics::REST> |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub que_walk_all { |
337
|
|
|
|
|
|
|
my ($self,$cb)=@_; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
my $state=1; |
340
|
|
|
|
|
|
|
my $data={}; |
341
|
|
|
|
|
|
|
my $total=0; |
342
|
|
|
|
|
|
|
my @ids; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
my $app_cb=sub { |
345
|
|
|
|
|
|
|
my ($self,$id,$result,$request,$response)=@_; |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
if($result) { |
348
|
|
|
|
|
|
|
foreach my $obj (@{$result->get_data}) { |
349
|
|
|
|
|
|
|
$data->{ids}->{$obj->{id}}=$obj; |
350
|
|
|
|
|
|
|
$obj->{our_type}='applications'; |
351
|
|
|
|
|
|
|
$data->{applications}->{$obj->{name}}=[] unless exists $data->{applications}->{$obj->{name}}; |
352
|
|
|
|
|
|
|
push @{$data->{applications}->{$obj->{name}}},$obj->{id}; |
353
|
|
|
|
|
|
|
foreach my $method (qw(que_list_nodes que_list_tiers que_list_business_transactions)) { |
354
|
|
|
|
|
|
|
++$total; |
355
|
|
|
|
|
|
|
my $code=sub { |
356
|
|
|
|
|
|
|
my ($self,undef,$result,$request,$response)=@_; |
357
|
|
|
|
|
|
|
return unless $state; |
358
|
|
|
|
|
|
|
return ($cb->($self,$id,$result,$request,$response,$method,$obj),$state=0) unless $result; |
359
|
|
|
|
|
|
|
--$total; |
360
|
|
|
|
|
|
|
foreach my $sub_obj (@{$result->get_data}) { |
361
|
|
|
|
|
|
|
my $target=$method; |
362
|
|
|
|
|
|
|
$target=~ s/^que_list_//; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
foreach my $field (qw(name machineName)) { |
365
|
|
|
|
|
|
|
next unless exists $sub_obj->{$field}; |
366
|
|
|
|
|
|
|
my $name=uc($sub_obj->{$field}); |
367
|
|
|
|
|
|
|
$data->{$target}->{$name}=[] unless exists $data->{$target}->{$name}; |
368
|
|
|
|
|
|
|
push @{$data->{$target}->{$name}},$sub_obj->{id}; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
$sub_obj->{ApplicationId}=$obj->{id}; |
371
|
|
|
|
|
|
|
$sub_obj->{ApplicationName}=$obj->{name}; |
372
|
|
|
|
|
|
|
$sub_obj->{our_type}=$target; |
373
|
|
|
|
|
|
|
$data->{ids}->{$sub_obj->{id}}=$sub_obj; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
if($total==0) { |
377
|
|
|
|
|
|
|
return ($cb->($self,$id,$self->new_true($data),$request,$response,'que_walk_all',$obj),$state=0) |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
}; |
380
|
|
|
|
|
|
|
push @ids,$self->$method($code,$obj->{id}); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
} else { |
384
|
|
|
|
|
|
|
return $cb->($self,$id,$result,$request,$response,'que_list_applications',undef); |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
$self->add_ids_for_blocking(@ids); |
387
|
|
|
|
|
|
|
}; |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
return $self->que_list_applications($app_cb); |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=cut |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub add_ids_for_blocking { |
395
|
0
|
|
|
0
|
1
|
0
|
my ($self,@ids)=@_; |
396
|
0
|
0
|
|
|
|
0
|
return unless $self->is_blocking; |
397
|
0
|
|
|
|
|
0
|
push @{$self->block_for_more},@ids; |
|
0
|
|
|
|
|
0
|
|
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=item * my $code=$self->block_cb($id,$result,$request,$response); |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
For internal use Default callback method used for all que_ methods. |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=cut |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub block_cb { |
407
|
6
|
|
|
6
|
1
|
20
|
my ($self,$id,$result,$request,$response)=@_; |
408
|
6
|
|
|
|
|
110
|
$self->result_map->{$id}=[$result,$request,$response]; |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=item * my $cb=$self->get_block_cb |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
For Internal use, Returns the default blocking callback: \&block_cbblock_cb |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=cut |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
sub get_block_cb { |
418
|
5
|
|
|
5
|
1
|
37
|
return \&block_cb; |
419
|
|
|
|
|
|
|
} |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=back |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=head1 Non-Blocking Interfaces |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
Every Non-Blocking method has a contrasting blocking method that does not accept a code refrence. All of the blocking interfaces are auto generated using AUTOLOAD. This section documents the non blocking interfaces. |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
All Non Blocking methods provide the following arguments to the callback. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
my $code=sub { |
430
|
|
|
|
|
|
|
my ($self,$id,$result,$request,$response)=@_; |
431
|
|
|
|
|
|
|
if($result) { |
432
|
|
|
|
|
|
|
print Dumper($result->get_data); |
433
|
|
|
|
|
|
|
} else { |
434
|
|
|
|
|
|
|
warn $result; |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
$self->que_xxx($code,$sql); |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
The code refrence $code will be calld when the HTTP::Response has been recived. |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
Callback variables |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
$self |
445
|
|
|
|
|
|
|
This Net::AppDynamics::REST Object |
446
|
|
|
|
|
|
|
$id |
447
|
|
|
|
|
|
|
The Job ID ( used internally ) |
448
|
|
|
|
|
|
|
$result |
449
|
|
|
|
|
|
|
A Data::Result Object, when true it contains the results, when false it contains why things failed |
450
|
|
|
|
|
|
|
$request |
451
|
|
|
|
|
|
|
HTTP::Requst Object that was sent to SolarWinds to make this request |
452
|
|
|
|
|
|
|
$response |
453
|
|
|
|
|
|
|
HTTP::Result Object that represents the response from SolarWinds |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=head1 Blocking Interfaces |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
All Blocking interfaces are generated with the AUTOLOAD method. Each method that begins with que_xxx can be calld in a blocking method. |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
Example: |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# my $id=$self->que_list_applications(sub {}); |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
# can called as a blocking method will simply return the Data::Result object |
464
|
|
|
|
|
|
|
my $result=$self->list_applications; |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=cut |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub AUTOLOAD { |
469
|
5
|
|
|
5
|
|
7842
|
my ($self,@args)=@_; |
470
|
|
|
|
|
|
|
|
471
|
5
|
|
|
|
|
35
|
my $method=$AUTOLOAD; |
472
|
5
|
|
|
|
|
29
|
$method=~ s/^.*:://s; |
473
|
5
|
50
|
|
|
|
34
|
return if $method eq 'DESTROY'; |
474
|
|
|
|
|
|
|
|
475
|
5
|
|
|
|
|
129
|
$self->is_blocking(1); |
476
|
5
|
|
|
|
|
241
|
my $que_method="que_$method"; |
477
|
5
|
50
|
|
|
|
19
|
unless($self->can($que_method)) { |
478
|
0
|
|
|
|
|
0
|
croak "Undefined subroutine $method"; |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
5
|
|
|
|
|
20
|
my @ids=$self->$que_method($self->get_block_cb,@args); |
482
|
5
|
|
|
|
|
96
|
$self->agent->run_next; |
483
|
5
|
|
|
|
|
1595
|
my $result=$self->block_on_ids(@ids)->[0]->[0]; |
484
|
|
|
|
|
|
|
|
485
|
5
|
|
|
|
|
126
|
$self->is_blocking(0); |
486
|
5
|
|
|
|
|
215
|
return $result; |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
sub can { |
490
|
22
|
|
|
22
|
0
|
52510
|
my ($self,$method)=@_; |
491
|
22
|
|
|
|
|
133
|
my $sub=$self->SUPER::can($method); |
492
|
|
|
|
|
|
|
|
493
|
22
|
100
|
|
|
|
90
|
return $sub if $sub; |
494
|
|
|
|
|
|
|
|
495
|
4
|
|
|
|
|
15
|
my $que_method="que_$method"; |
496
|
4
|
100
|
|
|
|
36
|
return undef unless $self->SUPER::can($que_method); |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
$sub=sub { |
499
|
1
|
|
|
1
|
|
317
|
$AUTOLOAD=$method; |
500
|
1
|
|
|
|
|
6
|
$self->AUTOLOAD(@_); |
501
|
1
|
|
|
|
|
8
|
}; |
502
|
|
|
|
|
|
|
|
503
|
1
|
|
|
|
|
4
|
return $sub; |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
1
|
0
|
|
sub DEMOLISH { } |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head1 See Also |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
L<https://docs.appdynamics.com/display/PRO43/AppDynamics+APIs> |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
L<AnyEvent::HTTP::MultiGet> |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=head1 AUTHOR |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
Michael Shipper L<mailto:AKALINUX@CPAN.ORG> |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=cut |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
1; |