line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package WWW::Pusher; |
2
|
|
|
|
|
|
|
{ |
3
|
|
|
|
|
|
|
$WWW::Pusher::VERSION = '0.0701'; |
4
|
|
|
|
|
|
|
} |
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
755
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
37
|
|
7
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
27
|
use 5.008; |
|
1
|
|
|
|
|
11
|
|
|
1
|
|
|
|
|
36
|
|
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
6
|
use JSON; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
12
|
1
|
|
|
1
|
|
1115
|
use URI; |
|
1
|
|
|
|
|
5798
|
|
|
1
|
|
|
|
|
35
|
|
13
|
1
|
|
|
1
|
|
1245
|
use LWP::UserAgent; |
|
1
|
|
|
|
|
39572
|
|
|
1
|
|
|
|
|
35
|
|
14
|
1
|
|
|
1
|
|
10
|
use Digest::MD5 qw(md5_hex); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
65
|
|
15
|
1
|
|
|
1
|
|
870
|
use Digest::SHA qw(hmac_sha256_hex); |
|
1
|
|
|
|
|
3692
|
|
|
1
|
|
|
|
|
827
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $pusher_defaults = { |
18
|
|
|
|
|
|
|
host => 'http://api.pusherapp.com', |
19
|
|
|
|
|
|
|
port => 80 |
20
|
|
|
|
|
|
|
}; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 NAME |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
WWW::Pusher - Interface to the Pusher WebSockets API |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 VERSION |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
version 0.0701 |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=cut |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head1 SYNOPSIS |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
use WWW::Pusher; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my $pusher = WWW::Pusher->new( |
37
|
|
|
|
|
|
|
auth_key => 'YOUR API KEY', |
38
|
|
|
|
|
|
|
secret => 'YOUR SECRET', |
39
|
|
|
|
|
|
|
app_id => 'YOUR APP ID', |
40
|
|
|
|
|
|
|
channel => 'test_channel' ); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $response = $pusher->trigger(event => 'my_event', data => 'Hello, World!'); |
43
|
|
|
|
|
|
|
my $sock_auth = $pusher->socket_auth('socket_auth_key'); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=head1 METHODS |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head2 new(auth_key => $auth_key, secret => $secret, app_id => $app_id, channel => $channel_id) |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Creates a new WWW::Pusher object. All fields excluding the channel are mandatory, however if |
50
|
|
|
|
|
|
|
you do not set the channel name during construction you must specify it when calling any |
51
|
|
|
|
|
|
|
other method. |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
You can optionally specify the host and port keys and override using pusherapp.com's server if you |
54
|
|
|
|
|
|
|
wish. In addtion, setting debug to a true value will return an L response on any request. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=cut |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub new |
59
|
|
|
|
|
|
|
{ |
60
|
1
|
|
|
1
|
1
|
794
|
my ($class, %args) = @_; |
61
|
|
|
|
|
|
|
|
62
|
1
|
50
|
|
|
|
5
|
die 'Pusher auth key must be defined' unless $args{auth_key}; |
63
|
1
|
50
|
|
|
|
3
|
die 'Pusher secret must be defined' unless $args{secret}; |
64
|
1
|
50
|
|
|
|
3
|
die 'Pusher application ID must be defined' unless $args{app_id}; |
65
|
|
|
|
|
|
|
|
66
|
1
|
|
33
|
|
|
12
|
my $self = { |
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
67
|
|
|
|
|
|
|
uri => URI->new($args{host} || $pusher_defaults->{host}), |
68
|
|
|
|
|
|
|
lwp => LWP::UserAgent->new, |
69
|
|
|
|
|
|
|
debug => $args{debug} || undef, |
70
|
|
|
|
|
|
|
auth_key => $args{auth_key}, |
71
|
|
|
|
|
|
|
app_id => $args{app_id}, |
72
|
|
|
|
|
|
|
secret => $args{secret}, |
73
|
|
|
|
|
|
|
channel => $args{channel} || '', |
74
|
|
|
|
|
|
|
host => $args{host} || $pusher_defaults->{host}, |
75
|
|
|
|
|
|
|
port => $args{port} || $pusher_defaults->{port} |
76
|
|
|
|
|
|
|
}; |
77
|
|
|
|
|
|
|
|
78
|
1
|
|
|
|
|
11330
|
$self->{uri}->port($self->{port}); |
79
|
1
|
|
|
|
|
238
|
$self->{uri}->path('/apps/'.$self->{app_id}.'/channels/'.$self->{channel}.'/events'); |
80
|
|
|
|
|
|
|
|
81
|
1
|
|
|
|
|
43
|
return bless $self; |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=head2 trigger(event => $event_name, data => $data, [channel => $channel, socket_id => $socket_id, debug => 1]) |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
Send an event to the specified channel. The event name should be a scalar, but data can also be hash/arrayref. There |
89
|
|
|
|
|
|
|
should be no need to JSON encode your data. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
Returns true on success, or undef on failure. Setting "debug" to a true value will return an L |
92
|
|
|
|
|
|
|
response object. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=cut |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub trigger |
97
|
|
|
|
|
|
|
{ |
98
|
0
|
|
|
0
|
1
|
|
my ($self, %args) = @_; |
99
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
|
my $time = time; |
101
|
0
|
|
|
|
|
|
my $uri = $self->{uri}->clone; |
102
|
0
|
|
|
|
|
|
my $payload = to_json($args{data}, { allow_nonref => 1 }); |
103
|
|
|
|
|
|
|
|
104
|
0
|
0
|
0
|
|
|
|
if($args{channel} && $args{channel} ne '') |
105
|
|
|
|
|
|
|
{ |
106
|
0
|
|
|
|
|
|
$uri->path('/apps/'.$self->{app_id}.'/channels/'.$args{channel}.'/events'); |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# The signature needs to have args in an exact order |
110
|
0
|
|
0
|
|
|
|
my $params = [ |
111
|
|
|
|
|
|
|
'auth_key' => $self->{auth_key}, |
112
|
|
|
|
|
|
|
'auth_timestamp' => $time, |
113
|
|
|
|
|
|
|
'auth_version' => '1.0', |
114
|
|
|
|
|
|
|
'body_md5' => md5_hex($payload), |
115
|
|
|
|
|
|
|
'name' => $args{event}, |
116
|
|
|
|
|
|
|
'socket_id' => $args{socket_id} || undef |
117
|
|
|
|
|
|
|
]; |
118
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
|
$uri->query_form(@{$params}); |
|
0
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
|
my $signature = "POST\n".$uri->path."\n".$uri->query; |
121
|
0
|
|
|
|
|
|
my $auth_signature = hmac_sha256_hex($signature, $self->{secret}); |
122
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
my $request = HTTP::Request->new('POST', $uri->as_string."&auth_signature=".$auth_signature, ['Content-Type' => 'application/json'], $payload); |
124
|
0
|
|
|
|
|
|
my $response = $self->{lwp}->request($request); |
125
|
|
|
|
|
|
|
|
126
|
0
|
0
|
0
|
|
|
|
if($self->{debug} || $args{debug}) |
|
|
0
|
0
|
|
|
|
|
127
|
|
|
|
|
|
|
{ |
128
|
0
|
|
|
|
|
|
return $response; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
elsif($response->is_success && $response->content eq "202 ACCEPTED\n") |
131
|
|
|
|
|
|
|
{ |
132
|
0
|
|
|
|
|
|
return 1; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
else |
135
|
|
|
|
|
|
|
{ |
136
|
0
|
|
|
|
|
|
return undef; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head2 socket_auth(socket_id => $socket_id, channel => $channel) |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
In order to establish private channels, your end must hand back a checksummed bit of data that browsers will, |
144
|
|
|
|
|
|
|
in turn will pass onto the pusher servers. On success this will return a JSON encoded hashref for you to give |
145
|
|
|
|
|
|
|
back to the client. Specifying the channel is optional only if you did not specify it during construction. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=cut |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub socket_auth |
150
|
|
|
|
|
|
|
{ |
151
|
0
|
|
|
0
|
1
|
|
my($self, %args) = @_; |
152
|
|
|
|
|
|
|
|
153
|
0
|
0
|
|
|
|
|
return undef unless $args{socket_id}; |
154
|
|
|
|
|
|
|
|
155
|
0
|
0
|
0
|
|
|
|
my $use_channel = $args{channel} && $args{channel} ne '' ? $args{channel} : $self->{channel}; |
156
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
|
my $signature; |
158
|
0
|
0
|
|
|
|
|
if($args{custom_string}) |
159
|
|
|
|
|
|
|
{ |
160
|
0
|
|
|
|
|
|
$signature = hmac_sha256_hex($args{socket_id}.':'.$use_channel.':'.$args{custom_string}, $self->{secret}); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
else |
163
|
|
|
|
|
|
|
{ |
164
|
0
|
|
|
|
|
|
$signature = hmac_sha256_hex($args{socket_id}.':'.$use_channel, $self->{secret}); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
|
167
|
0
|
|
|
|
|
|
return encode_json({ |
168
|
|
|
|
|
|
|
auth => $self->{'auth_key'}.':'.$signature |
169
|
|
|
|
|
|
|
}); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head2 presence_auth(socket_id => $socket_id, user_id => $user_id, channel => $channel, user=_info => {name => $name, email => $email}) |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Presence signing is exactly like socket ID signing above, only we can include very user-specific data in |
175
|
|
|
|
|
|
|
addition, such as a user ID, name or email. This method generates the signed payload to pass back to Pusher. |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
The socket ID and user ID are mandatory, however both the channel and user info are not. Setting the channel |
178
|
|
|
|
|
|
|
to undef will default to using the channel defined in the WWW::Pusher object. |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=cut |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub presence_auth |
183
|
|
|
|
|
|
|
{ |
184
|
0
|
|
|
0
|
1
|
|
my ($self, %args) = @_; |
185
|
|
|
|
|
|
|
|
186
|
0
|
0
|
0
|
|
|
|
return undef unless $args{socket_id} and $args{user_id}; |
187
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
|
my $user_data = { user_id => $args{user_id}}; |
189
|
0
|
0
|
|
|
|
|
$user_data->{user_info} = { %{$args{user_info}} } if($args{user_info}); |
|
0
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
|
191
|
0
|
0
|
0
|
|
|
|
my $use_channel = $args{channel} && $args{channel} ne '' ? $args{channel} : $self->{channel}; |
192
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
return $self->socket_auth(socket_id => $args{socket_id}, channel => $use_channel, custom_string => encode_json($user_data)); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=head1 AUTHOR |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
Squeeks, C<< >> |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
JT Smith C<< >> |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=head1 BUGS |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
Please report bugs to the tracker on GitHub: L |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head1 SUPPORT |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
perldoc WWW::Pusher |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
More information at: L |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head1 SEE ALSO |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
Pusher - L |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Copyright 2010 Squeeks. |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
224
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
225
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=cut |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
1; # End of WWW::Pusher |