File Coverage

blib/lib/AnyEvent/Campfire/Stream.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package AnyEvent::Campfire::Stream;
2             {
3             $AnyEvent::Campfire::Stream::VERSION = '0.0.3';
4             }
5              
6             # Abstract: Receive Campfire streaming API in an event loop
7 1     1   21300 use Moose;
  0            
  0            
8             use namespace::autoclean;
9              
10             extends 'AnyEvent::Campfire';
11              
12             use AnyEvent;
13             use AnyEvent::HTTP;
14             use URI;
15             use JSON::XS;
16             use Try::Tiny;
17              
18             sub BUILD {
19             my $self = shift;
20              
21             if ( !$self->authorization || !scalar @{ $self->rooms } ) {
22             print STDERR
23             "Not enough parameters provided. I Need a token and rooms\n";
24             exit(1);
25             }
26              
27             my %headers = (
28             Accept => '*/*',
29             Authorization => $self->authorization,
30             );
31              
32             my $on_json = sub {
33             my $json = shift;
34             if ( $json !~ /^\s*$/ ) {
35             my $data;
36             try {
37             $data = decode_json($json);
38             $self->emit( 'stream', $data );
39             }
40             catch {
41             $self->emit( 'error', "Campfire data parse error: $_" );
42             };
43             }
44             };
45              
46             my $on_header = sub {
47             my ($hdr) = @_;
48             if ( $hdr->{Status} !~ m/^2/ ) {
49             $self->emit( 'error', "$hdr->{Status}: $hdr->{Reason}" );
50             return;
51             }
52             return 1;
53             };
54              
55             my $callback = sub {
56             my ( $handle, $headers ) = @_;
57              
58             return unless $handle;
59              
60             my $chunk_reader = sub {
61             my ( $handle, $line ) = @_;
62              
63             $line =~ /^([0-9a-fA-F]+)/ or die 'bad chunk (incorrect length)';
64             my $len = hex $1;
65              
66             $handle->push_read(
67             chunk => $len,
68             sub {
69             my ( $handle, $chunk ) = @_;
70              
71             $handle->push_read(
72             line => sub {
73             length $_[1]
74             and die 'bad chunk (missing last empty line)';
75             }
76             );
77              
78             $on_json->($chunk);
79             }
80             );
81             };
82             my $line_reader = sub {
83             my ( $handle, $line ) = @_;
84             $on_json->($line);
85             };
86              
87             $handle->on_error(
88             sub {
89             undef $handle;
90             $self->emit( 'error', $_[2] );
91             }
92             );
93              
94             $handle->on_eof( sub { undef $handle } );
95             if ( ( $headers->{'transfer-encoding'} || '' ) =~ /\bchunked\b/i ) {
96             $handle->on_read(
97             sub {
98             my ($handle) = @_;
99             $handle->push_read( line => $chunk_reader );
100             }
101             );
102             }
103             else {
104             $handle->on_read(
105             sub {
106             my ($handle) = @_;
107             $handle->push_read( line => $line_reader );
108             }
109             );
110             }
111             };
112              
113             for my $room ( @{ $self->rooms } ) {
114             my $uri =
115             URI->new("https://streaming.campfirenow.com/room/$room/live.json");
116             http_request(
117             'GET',
118             $uri,
119             headers => \%headers,
120             keepalive => 1,
121             want_body_handle => 1,
122             on_header => $on_header,
123             $callback,
124             );
125             }
126              
127             return $self;
128             }
129              
130             __PACKAGE__->meta->make_immutable;
131              
132             1;
133              
134             __END__
135              
136             =pod
137              
138             =encoding utf-8
139              
140             =head1 NAME
141              
142             AnyEvent::Campfire::Stream
143              
144             =head1 VERSION
145              
146             version 0.0.3
147              
148             =head1 SYNOPSIS
149              
150             use AnyEvent::Campfire::Stream;
151             my $stream = AnyEvent::Campfire::Stream->new(
152             token => 'xxx',
153             rooms => '1234', # hint: room id is in the url
154             # seperated by comma `,`
155             );
156              
157             $stream->on('stream', sub {
158             my ($s, $data) = @_; # $s is $stream
159             print "$data->{id}: $data->{body}\n";
160             });
161              
162             $stream->on('error', sub {
163             my ($s, $error) = @_;
164             print STDERR "$error\n";
165             });
166              
167             =head1 SEE ALSO
168              
169             =over
170              
171             =item L<https://github.com/37signals/campfire-api/blob/master/sections/streaming.md>
172              
173             =back
174              
175             =head1 AUTHOR
176              
177             Hyungsuk Hong <hshong@perl.kr>
178              
179             =head1 COPYRIGHT AND LICENSE
180              
181             This software is copyright (c) 2012 by Hyungsuk Hong.
182              
183             This is free software; you can redistribute it and/or modify it under
184             the same terms as the Perl 5 programming language system itself.
185              
186             =cut