File Coverage

blib/lib/Net/Gnip.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Net::Gnip;
2              
3 4     4   104023 use strict;
  4         9  
  4         156  
4              
5 4     4   9072 use DateTime;
  4         801616  
  4         173  
6 4     4   4569 use DateTime::Format::Strptime;
  4         35254  
  4         301  
7 4     4   4783 use LWP::UserAgent;
  4         230874  
  4         324  
8              
9 4     4   3511 use Net::Gnip::ActivityStream;
  0            
  0            
10             use Net::Gnip::FilterStream;
11             use Net::Gnip::PublisherStream;
12              
13             our $VERSION = "0.3";
14              
15             use constant GNIP_BASE_ADDRESS => 'prod.gnipcentral.com';
16             use constant GNIP_BASE_URL => 'https://'.GNIP_BASE_ADDRESS;
17              
18             =head1 NAME
19              
20             Net::Gnip - interact with Gnip
21              
22             =head1 SYNOPSIS
23              
24             use Net::Gnip;
25             my $gnip = Net::Gnip->new($user, $pass, $publisher_name);
26              
27             # Get a list of publisher
28             my @publisher = $gnip->publishers();
29             $gnip->create_publisher($name);
30              
31              
32             # Create an activity and publish it
33             my $activity = Net::Gnip::Activity->new('added_friend', 'me');
34             $gnip->publish($publisher_name, $activity);
35             # or
36             $gnip->publish($publisher_name, @activities);
37             # or
38             $gnip->publish($activity_stream);
39              
40             # Retrieve activities for a given publisher
41             my $stream = $gnip->fetch(notification => $publisher_name);
42             foreach my $activity ($stream->activities) {
43             print "Type=".$activity->type."\n";
44             }
45              
46             # Retrieve activities for a given publisher 10 minutes ago
47             my $stream = $gnip->fetch(notification => $publisher_name, time => 10*60);
48              
49             # Retrieve activities for a given publisher from a specific time
50             my $stream = $gnip->fetch(notification => $publisher_name, time => $dt);
51              
52             # The same but get the full date
53             my $stream = $gnip->fetch(activity => $publisher_name, time => $dt);
54              
55              
56             # Create a filter and
57             my @rules = ( { type => 'actor', value => 'joe' } );
58             my $filter = Net::Gnip::Filter->new('my_filter', 'true', [@rules]);
59             my $result = $gnip->create_filter($publisher_name, $filter);
60              
61             # Get a list of filters
62             foreach my $filters ($gnip->filters($publisher_name)) {
63             print $filter->name."\n";
64             }
65              
66            
67             # Get the activities from it
68             my $stream = $gnip->fetch(activity => $publisher_name, filter => $filter_name);
69             foreach my $activity ($stream->activities) {
70             print "Type=".$activity->type."\n";
71             }
72            
73             # Update it
74             $filter->full('false');
75             $gnip->update_filter($publisher_name, $filter);
76              
77             $gnip->add_filter_rule($filter, 'actor', 'simon');
78             $gnip->delete_filter_rule($filter, 'actor', 'simon')
79              
80            
81             # Delete it
82             $gnip->delete_filter($publisher_name, $filter);
83              
84              
85              
86             =head2 METHODS
87              
88             =cut
89              
90             =head2 new
91              
92             Create a new Gnip object
93              
94             =cut
95              
96             sub new {
97             my ($class, $username, $password, %self) = @_;
98             $self{'_username'} = $username;
99             $self{'_password'} = $password;
100             return bless {%self}, $class;
101             }
102              
103              
104              
105             =head2 fetch [datetime])
106              
107             Gets all of the data for a specific publisher, based on the
108             datetime parameter.
109              
110             If datetime is not passed in, the current time will be used.
111              
112             Note that all times need to be as UTC DateTime objects.
113              
114             Returns a C object.
115              
116             =cut
117              
118             sub fetch {
119             my $self = shift;
120             my %opts = @_;
121              
122             my $what;
123             my $name;
124              
125             for my $key (qw(notification activity)) {
126             next unless defined $opts{$key};
127             $what = $key;
128             $name = $opts{$key};
129             }
130             die "You must must pass in either a 'notification' or 'activity' key with a publisher name"
131             unless defined $what;
132              
133            
134             my $path = "publishers/${name}";
135             if (defined $opts{filter}) {
136             $path .= "/filters/".$opts{filter};
137             }
138             $path .= "/${what}";
139              
140             my $datetime = $opts{time};
141             my $file = "current.xml";
142              
143             if (defined $datetime) {
144             $datetime = DateTime->now->subtract( seconds => $datetime) unless ref($datetime);
145             unless ($self->{no_time_sync}) {
146             my $gnip_time = $self->sync_with_gnip_clock;
147             my $local_time = DateTime->now;
148             $datetime = $datetime + ($gnip_time - $local_time);
149             }
150             my $rounded = $self->round_time_to_nearest_bucket($datetime);
151             my $time_string = $self->time_to_string($rounded);
152             $file = "${time_string}.xml";
153             }
154             my $url = $self->GNIP_BASE_URL."/".$path."/".$file;
155             my $xml = $self->get($url) || return;
156             return Net::Gnip::ActivityStream->parse($xml, _no_dt => $self->{_no_dt});
157             }
158              
159             =head2 publish
160              
161             Publish an activity stream.
162              
163             =cut
164              
165             =head2 publish
166              
167             =cut
168             sub publish {
169             my $self = shift;
170             my $publisher = shift;
171             my $stream;
172             if (ref $publisher) {
173             $stream = $publisher;
174             $publisher = $stream->publisher;
175             die "An activity stream must have a publisher set if it's the only argument to publish()"
176             unless defined $publisher;
177             }
178             die "You need to pass in some activities" unless @_;
179             $stream = Net::Gnip::ActivityStream->new( publisher => $publisher);
180             $stream->activities(@_);
181             my $url = $self->GNIP_BASE_URL."/publishers/" . $publisher . "/activity";
182             $self->post($url, $stream);
183             }
184              
185              
186              
187             =head2 filters
188              
189             Get a list of filters for this publisher.
190              
191             Returns a list of C objects.
192              
193             =cut
194             sub filters {
195             my $self = shift;
196             my $publisher = shift;
197             my $url = $self->GNIP_BASE_URL."/publishers/$publisher/filters.xml";
198             my $xml = $self->get($url) || return;
199             return Net::Gnip::FilterStream->parse($xml)->filters;
200             }
201              
202              
203             =head2 create_filter
204              
205             Creates a new filter.
206              
207             =cut
208             sub create_filter {
209             my ($self, $publisher, $filter) = @_;
210             my $url = $self->GNIP_BASE_URL."/publishers/$publisher/filters.xml";
211             return $self->post($url, $filter);
212             }
213              
214             =head2 get_filter
215              
216             Fetches an existing filter.
217              
218             C can either be a filter object or a name.
219              
220             Returns a C object.
221              
222             =cut
223             sub get_filter {
224             my $self = shift;
225             my $xml = $self->_filter_method('get', @_) || return;
226             return Net::Gnip::Filter->parse($xml);
227             }
228              
229             =head2 update_filter
230              
231             Updates an existing filter.
232              
233             C can either be a filter object or a name.
234              
235             Returns 1 on success and 0 on failure.
236              
237             =cut
238             sub update_filter {
239             my $self = shift;
240             return $self->_filter_method('put', @_);
241             }
242              
243             =head2 delete_filter
244              
245             Deletes an existing filter.
246              
247             C can either be a filter object or a name.
248              
249             =cut
250             sub delete_filter {
251             my $self = shift;
252             return $self->_filter_method('delete', @_);
253             }
254              
255             =head2 add_filter_rule
256              
257             Incrementally add a filter rule.
258              
259             =cut
260             sub add_filter_rule {
261             my $self = shift;
262             $self->_filter_method('post', @_);
263             }
264              
265             =head2 delete_filter_rule
266              
267             Incrementally delete a filter rule.
268              
269             =cut
270             sub delete_filter_rule {
271             my $self = shift;
272             $self->_filter_method('delete', @_);
273             }
274              
275             sub _filter_method {
276             my $self = shift;
277             my $method = shift;
278             my $publisher = shift;
279             my $filter = shift;
280             my $type = shift;
281             my $value = shift;
282             my $name = (ref($filter))? $filter->name : $filter;
283             my $url = $self->GNIP_BASE_URL."/publishers/$publisher/filters/$name";
284             if (defined $type && defined $value) {
285             $url .= "/rules.xml?type=${type}&value=${value}";
286             if ($method eq 'post') {
287             $filter = Net::Gnip::Filter->_create_rule({ type => $type, value => $value })->toString(1);
288             }
289             } else {
290             $url .= ".xml";
291             }
292             return $self->$method($url, $filter);
293             }
294              
295              
296             =head2 publishers
297              
298             Gets a list of publishers on the system
299              
300             =cut
301             sub publishers {
302             my ($self) = @_;
303              
304             my $url = $self->GNIP_BASE_URL."/publishers.xml";
305              
306             my $xml = $self->get($url) || return;
307             return map { $_->name } Net::Gnip::PublisherStream->parse($xml)->publishers;
308             }
309              
310              
311              
312             =head2 create_publisher
313              
314             Takes one or more C objects and creates them.
315              
316             Returns 1 on success and undef on failure (and sets C<$@>)
317              
318             =cut
319             sub create_publisher {
320             my $self = shift;
321             my $name = shift;
322             my $stream = Net::Gnip::PublisherStream->new(children => [ @_ ] );
323             my $url = $self->GNIP_BASE_URL."/publishers.xml";
324             return $self->post($url, $stream);
325              
326             }
327              
328             =head2 get
329              
330             Does an HTTP GET request of the passed in C, and returns
331             the result from the server.
332              
333             Returns undef on failure (and sets C<$@>)
334              
335             =cut
336              
337             sub get {
338             my $self = shift;
339             return $self->_do_http('GET', @_);
340             }
341              
342             =head2 post
343              
344             Does a HTTP POST request of the passed in url and data object, and returns
345             the result from the server.
346              
347             Returns undef on failure (and sets C<$@>)
348              
349             =cut
350              
351             sub post {
352             my $self = shift;
353             return $self->_do_http('POST', @_);
354             }
355              
356             sub _do_http {
357             my $self = shift;
358             my $type = shift;
359             my $url = shift;
360             my $response = $self->_do_request(1, $type, $url, @_);
361             # Check the outcome of the response
362             if ($response->is_success) {
363             return $response->content;
364             } else {
365             $@ = "Failed to $type $url ".$response->status_line."\n\n".$response->as_string;
366             return;
367             }
368             }
369              
370             sub _do_request {
371             my $self = shift;
372             my ($auth, $type, $url, $data) = @_;
373             my $agent = $self->{_agent} ||= LWP::UserAgent->new;
374             # Load proxy settings from *_proxy environment variables
375             $agent->env_proxy;
376             $agent->agent(__PACKAGE__."-".$VERSION);
377             my $request = HTTP::Request->new($type => $url);
378             $request->authorization_basic($self->{_username}, $self->{_password}) if $auth;
379             if (defined $data) {
380             $request->content_type('application/xml');
381             $request->content((ref $data)?$data->as_xml:$data);
382             }
383             return $agent->request($request);
384             }
385              
386              
387             =head2 put
388              
389             Does an HTTP PUT request of the passed in url and data object, and returns
390             the result from the server.
391              
392             Returns undef on failure (and sets C<$@>)
393              
394             =cut
395              
396             sub put {
397             my $self = shift;
398             return $self->_do_http('PUT', @_)
399             }
400              
401             =head2 delete
402              
403             Does a HTTP Delete request of the passed in url and returns
404             the result from the server.
405              
406             Returns undef on failure (and sets C<$@>)
407              
408             =cut
409              
410             sub delete {
411             my $self = shift;
412             return $self->_do_http('DELETE', @_)
413             }
414              
415             =head2 round_time_to_nearest_bucket
416              
417             Rounds the time passed in down to the previous 1 minute mark.
418              
419             Returns a new C object.
420              
421             =cut
422              
423             sub round_time_to_nearest_bucket {
424             my $self = shift;
425             my $datetime = shift->clone;
426              
427             my $min = $datetime->minute();
428             my $new = $min - ($min % 1);
429              
430             $datetime->set(minute => $new);
431             $datetime->set(second => 0);
432              
433             return $datetime;
434             }
435              
436             =head2 sync_with_gnip_clock
437              
438             This method gets the current time from the Gnip server.
439              
440             Returns a new C object.
441              
442             =cut
443              
444             sub sync_with_gnip_clock {
445             my $self = shift;
446              
447             my $response = $self->_do_request(0, 'HEAD', GNIP_BASE_URL);
448             my $formatter = DateTime::Format::Strptime->new( pattern => '%a, %d %b %Y %H:%M:%S %Z' );
449             my $gnip_time = $formatter->parse_datetime($response->header('Date'));
450             return $gnip_time;
451             }
452              
453             =head2 time_to_string
454              
455             Converts the time passed in to a string of the form YYYYMMDDHHMM.
456              
457             =cut
458              
459             sub time_to_string {
460             my ($self, $datetime) = @_;
461             return $datetime->strftime("%Y%m%d%H%M");
462             }
463              
464             =head1 AUTHOR
465              
466             Simon Wistow
467              
468             Based on code by ajackson from http://github.com/gnip/gnip-perl/tree/master
469              
470             =head1 COPYRIGHT
471              
472             Copyright 2008, Simon Wistow
473              
474             Release under the same terms as Perl itself.
475              
476             =cut
477             1;
478