pusher 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/Gemfile.lock +12 -18
- data/README.md +13 -6
- data/lib/pusher.rb +33 -3
- data/lib/pusher/channel.rb +61 -16
- data/pusher.gemspec +1 -1
- data/spec/channel_spec.rb +2 -2
- metadata +14 -4
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
script: "rspec spec/*_spec.rb"
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pusher (0.
|
4
|
+
pusher (0.7.0)
|
5
5
|
crack (~> 0.1.0)
|
6
6
|
json (~> 1.4.0)
|
7
7
|
ruby-hmac (~> 0.4.0)
|
@@ -10,28 +10,26 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: http://rubygems.org/
|
12
12
|
specs:
|
13
|
-
addressable (2.2.
|
13
|
+
addressable (2.2.4)
|
14
14
|
crack (0.1.8)
|
15
15
|
diff-lcs (1.1.2)
|
16
|
-
em-http-request (0.2.
|
16
|
+
em-http-request (0.2.15)
|
17
17
|
addressable (>= 2.0.0)
|
18
18
|
eventmachine (>= 0.12.9)
|
19
19
|
eventmachine (0.12.10)
|
20
20
|
json (1.4.6)
|
21
|
-
rspec (2.0
|
22
|
-
rspec-core (~> 2.0
|
23
|
-
rspec-expectations (~> 2.0
|
24
|
-
rspec-mocks (~> 2.0
|
25
|
-
rspec-core (2.
|
26
|
-
rspec-expectations (2.0
|
27
|
-
diff-lcs (
|
28
|
-
rspec-mocks (2.0
|
29
|
-
rspec-core (~> 2.0.1)
|
30
|
-
rspec-expectations (~> 2.0.1)
|
21
|
+
rspec (2.5.0)
|
22
|
+
rspec-core (~> 2.5.0)
|
23
|
+
rspec-expectations (~> 2.5.0)
|
24
|
+
rspec-mocks (~> 2.5.0)
|
25
|
+
rspec-core (2.5.1)
|
26
|
+
rspec-expectations (2.5.0)
|
27
|
+
diff-lcs (~> 1.1.2)
|
28
|
+
rspec-mocks (2.5.0)
|
31
29
|
ruby-hmac (0.4.0)
|
32
30
|
signature (0.1.2)
|
33
31
|
ruby-hmac
|
34
|
-
webmock (1.
|
32
|
+
webmock (1.6.2)
|
35
33
|
addressable (>= 2.2.2)
|
36
34
|
crack (>= 0.1.7)
|
37
35
|
|
@@ -39,11 +37,7 @@ PLATFORMS
|
|
39
37
|
ruby
|
40
38
|
|
41
39
|
DEPENDENCIES
|
42
|
-
crack (~> 0.1.0)
|
43
40
|
em-http-request (~> 0.2.7)
|
44
|
-
json (~> 1.4.0)
|
45
41
|
pusher!
|
46
42
|
rspec (~> 2.0)
|
47
|
-
ruby-hmac (~> 0.4.0)
|
48
|
-
signature (~> 0.1.2)
|
49
43
|
webmock
|
data/README.md
CHANGED
@@ -28,18 +28,25 @@ Errors are logged to `Pusher.logger`. It will by default use `Logger` from stdli
|
|
28
28
|
Asynchronous triggering
|
29
29
|
-----------------------
|
30
30
|
|
31
|
-
To avoid blocking in a typical web application,
|
31
|
+
To avoid blocking in a typical web application, you may wish to use the `trigger_async` method which uses the makes asynchronous API requests to Pusher. `trigger_async` returns a deferrable which you can optionally bind to with success and failure callbacks.
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
You need to be running eventmachine to make use of this functionality. This is already the case if, for example, you're deploying to Heroku or using the Thin web server. You will also need to add `em-http-request` to your Gemfile.
|
34
|
+
|
35
|
+
$ gem install em-http-request
|
36
|
+
|
37
|
+
deferrable = Pusher['a_channel'].trigger_async('an_event', {
|
38
|
+
:some => 'data'
|
39
|
+
}, socket_id)
|
40
|
+
deferrable.callback {
|
35
41
|
# Do something on success
|
36
42
|
}
|
37
|
-
|
38
|
-
# error is a
|
43
|
+
deferrable.errback { |error|
|
44
|
+
# error is a instance of Pusher::Error
|
39
45
|
}
|
40
46
|
|
41
47
|
Private channels
|
42
|
-
|
48
|
+
----------------
|
49
|
+
|
43
50
|
The Pusher Gem also deals with signing requests for authenticated private channels. A quick Rails controller example:
|
44
51
|
|
45
52
|
reponse = Pusher['private-my_channel'].authenticate(params[:socket_id])
|
data/lib/pusher.rb
CHANGED
@@ -1,7 +1,18 @@
|
|
1
1
|
autoload 'Logger', 'logger'
|
2
2
|
require 'uri'
|
3
3
|
|
4
|
+
# Used for configuring API credentials and creating Channel objects
|
5
|
+
#
|
4
6
|
module Pusher
|
7
|
+
# All Pusher errors descend from this class so you can easily rescue Pusher
|
8
|
+
# errors
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# begin
|
12
|
+
# Pusher['a_channel'].trigger!('an_event', {:some => 'data'})
|
13
|
+
# rescue Pusher::Error => e
|
14
|
+
# # Do something on error
|
15
|
+
# end
|
5
16
|
class Error < RuntimeError; end
|
6
17
|
class AuthenticationError < Error; end
|
7
18
|
class ConfigurationError < Error; end
|
@@ -11,6 +22,7 @@ module Pusher
|
|
11
22
|
attr_writer :logger
|
12
23
|
attr_accessor :app_id, :key, :secret
|
13
24
|
|
25
|
+
# @private
|
14
26
|
def logger
|
15
27
|
@logger ||= begin
|
16
28
|
log = Logger.new(STDOUT)
|
@@ -19,11 +31,12 @@ module Pusher
|
|
19
31
|
end
|
20
32
|
end
|
21
33
|
|
34
|
+
# @private
|
22
35
|
def authentication_token
|
23
36
|
Signature::Token.new(@key, @secret)
|
24
37
|
end
|
25
38
|
|
26
|
-
# Builds a connection url for Pusherapp
|
39
|
+
# @private Builds a connection url for Pusherapp
|
27
40
|
def url
|
28
41
|
URI::Generic.build({
|
29
42
|
:scheme => self.scheme,
|
@@ -33,7 +46,12 @@ module Pusher
|
|
33
46
|
})
|
34
47
|
end
|
35
48
|
|
36
|
-
#
|
49
|
+
# Configure Pusher connection by providing a url rather than specifying
|
50
|
+
# scheme, key, secret, and app_id separately.
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# Pusher.url = http://KEY:SECRET@api.pusherapp.com/apps/APP_ID
|
54
|
+
#
|
37
55
|
def url=(url)
|
38
56
|
uri = URI.parse(url)
|
39
57
|
self.app_id = uri.path.split('/').last
|
@@ -43,7 +61,12 @@ module Pusher
|
|
43
61
|
self.port = uri.port
|
44
62
|
end
|
45
63
|
|
46
|
-
# Configure
|
64
|
+
# Configure whether Pusher API calls should be made over SSL
|
65
|
+
# (default false)
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# Pusher.encrypted = true
|
69
|
+
#
|
47
70
|
def encrypted=(boolean)
|
48
71
|
Pusher.scheme = boolean ? 'https' : 'http'
|
49
72
|
# Configure port if it hasn't already been configured
|
@@ -65,6 +88,13 @@ module Pusher
|
|
65
88
|
self.url = ENV['PUSHER_URL']
|
66
89
|
end
|
67
90
|
|
91
|
+
# Return a channel by name
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# Pusher['my-channel']
|
95
|
+
# @return [Channel]
|
96
|
+
# @raise [ConfigurationError] unless key, secret and app_id have been
|
97
|
+
# configured
|
68
98
|
def self.[](channel_name)
|
69
99
|
raise ConfigurationError, 'Missing configuration: please check that Pusher.url is configured' unless configured?
|
70
100
|
@channels ||= {}
|
data/lib/pusher/channel.rb
CHANGED
@@ -2,6 +2,7 @@ require 'crack/core_extensions' # Used for Hash#to_params
|
|
2
2
|
require 'hmac-sha2'
|
3
3
|
|
4
4
|
module Pusher
|
5
|
+
# Trigger events on Channels
|
5
6
|
class Channel
|
6
7
|
attr_reader :name
|
7
8
|
|
@@ -11,6 +12,17 @@ module Pusher
|
|
11
12
|
@name = name
|
12
13
|
end
|
13
14
|
|
15
|
+
# Trigger event asynchronously using EventMachine::HttpRequest
|
16
|
+
#
|
17
|
+
# @param (see #trigger!)
|
18
|
+
# @return [EM::DefaultDeferrable]
|
19
|
+
# Attach a callback to be notified of success (with no parameters).
|
20
|
+
# Attach an errback to be notified of failure (with an error parameter
|
21
|
+
# which includes the HTTP status code returned)
|
22
|
+
# @raise [LoadError] unless em-http-request gem is available
|
23
|
+
# @raise [Pusher::Error] unless the eventmachine reactor is running. You
|
24
|
+
# probably want to run your application inside a server such as thin
|
25
|
+
#
|
14
26
|
def trigger_async(event_name, data, socket_id = nil, &block)
|
15
27
|
unless defined?(EventMachine) && EventMachine.reactor_running?
|
16
28
|
raise Error, "In order to use trigger_async you must be running inside an eventmachine loop"
|
@@ -24,7 +36,7 @@ module Pusher
|
|
24
36
|
deferrable = EM::DefaultDeferrable.new
|
25
37
|
|
26
38
|
http = @http_async.post({
|
27
|
-
:query => request.query, :timeout =>
|
39
|
+
:query => request.query, :timeout => 5, :body => request.body,
|
28
40
|
:head => {'Content-Type'=> 'application/json'}
|
29
41
|
})
|
30
42
|
http.callback {
|
@@ -43,6 +55,23 @@ module Pusher
|
|
43
55
|
deferrable
|
44
56
|
end
|
45
57
|
|
58
|
+
# Trigger event
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# begin
|
62
|
+
# Pusher['my-channel'].trigger!('an_event', {:some => 'data'})
|
63
|
+
# rescue Pusher::Error => e
|
64
|
+
# # Do something on error
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# @param data [Object] Event data to be triggered in javascript.
|
68
|
+
# Objects other than strings will be converted to JSON
|
69
|
+
# @param socket_id Allows excluding a given socket_id from receiving the
|
70
|
+
# event - see http://pusherapp.com/docs/duplicates for more info
|
71
|
+
#
|
72
|
+
# @raise [Pusher::Error] on invalid Pusher response
|
73
|
+
# @raise any Net::HTTP related errors
|
74
|
+
#
|
46
75
|
def trigger!(event_name, data, socket_id = nil)
|
47
76
|
require 'net/http' unless defined?(Net::HTTP)
|
48
77
|
require 'net/https' if (ssl? && !defined?(Net::HTTPS))
|
@@ -62,18 +91,29 @@ module Pusher
|
|
62
91
|
handle_response(response.code.to_i, response.body.chomp)
|
63
92
|
end
|
64
93
|
|
94
|
+
# Trigger event, catching and logging any errors.
|
95
|
+
#
|
96
|
+
# @note CAUTION! No exceptions will be raised on failure
|
97
|
+
# @param (see #trigger!)
|
98
|
+
#
|
65
99
|
def trigger(event_name, data, socket_id = nil)
|
66
100
|
trigger!(event_name, data, socket_id)
|
67
101
|
rescue StandardError => e
|
68
|
-
|
102
|
+
Pusher.logger.error("#{e.message} (#{e.class})")
|
103
|
+
Pusher.logger.debug(e.backtrace.join("\n"))
|
69
104
|
end
|
70
105
|
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
# socket_id
|
76
|
-
|
106
|
+
# Compute authentication string required to subscribe to this channel.
|
107
|
+
#
|
108
|
+
# See http://pusherapp.com/docs/auth_signatures for more details.
|
109
|
+
#
|
110
|
+
# @param socket_id [String] Each Pusher socket connection receives a
|
111
|
+
# unique socket_id. This is sent from pusher.js to your server when
|
112
|
+
# channel authentication is required.
|
113
|
+
# @param custom_string [String] Allows signing additional data
|
114
|
+
# @return [String]
|
115
|
+
#
|
116
|
+
def authentication_string(socket_id, custom_string = nil)
|
77
117
|
raise "Invalid socket_id" if socket_id.nil? || socket_id.empty?
|
78
118
|
raise 'Custom argument must be a string' unless custom_string.nil? || custom_string.kind_of?(String)
|
79
119
|
|
@@ -85,8 +125,18 @@ module Pusher
|
|
85
125
|
return "#{token.key}:#{signature}"
|
86
126
|
end
|
87
127
|
|
88
|
-
#
|
89
|
-
|
128
|
+
# Deprecated - for backward compatibility
|
129
|
+
alias :socket_auth :authentication_string
|
130
|
+
|
131
|
+
# Generate an authentication endpoint response
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
# render :json => Pusher['private-my_channel'].authenticate(params[:socket_id])
|
135
|
+
#
|
136
|
+
# @return [Hash]
|
137
|
+
#
|
138
|
+
# @private Custom data is sent to server as JSON-encoded string
|
139
|
+
#
|
90
140
|
def authenticate(socket_id, custom_data = nil)
|
91
141
|
custom_data = Pusher::JSON.generate(custom_data) if custom_data
|
92
142
|
auth = socket_auth(socket_id, custom_data)
|
@@ -97,11 +147,6 @@ module Pusher
|
|
97
147
|
|
98
148
|
private
|
99
149
|
|
100
|
-
def handle_error(e)
|
101
|
-
Pusher.logger.error("#{e.message} (#{e.class})")
|
102
|
-
Pusher.logger.debug(e.backtrace.join("\n"))
|
103
|
-
end
|
104
|
-
|
105
150
|
def handle_response(status_code, body)
|
106
151
|
case status_code
|
107
152
|
when 202
|
@@ -113,7 +158,7 @@ module Pusher
|
|
113
158
|
when 404
|
114
159
|
raise Error, "Resource not found: app_id is probably invalid"
|
115
160
|
else
|
116
|
-
raise Error, "Unknown error
|
161
|
+
raise Error, "Unknown error (status code #{status_code}): #{body}"
|
117
162
|
end
|
118
163
|
end
|
119
164
|
|
data/pusher.gemspec
CHANGED
data/spec/channel_spec.rb
CHANGED
@@ -105,7 +105,7 @@ describe Pusher::Channel do
|
|
105
105
|
).to_return(:status => 500, :body => "some error")
|
106
106
|
lambda {
|
107
107
|
Pusher['test_channel'].trigger!('new_event', 'Some data')
|
108
|
-
}.should raise_error(Pusher::Error, 'Unknown error
|
108
|
+
}.should raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
@@ -132,7 +132,7 @@ describe Pusher::Channel do
|
|
132
132
|
|
133
133
|
describe "trigger_async" do
|
134
134
|
before :each do
|
135
|
-
WebMock.
|
135
|
+
WebMock.reset!
|
136
136
|
WebMock.disable_net_connect!
|
137
137
|
|
138
138
|
@pusher_url_regexp = %r{/apps/20/channels/test_channel/events}
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 7
|
8
|
-
-
|
9
|
-
version: 0.7.
|
8
|
+
- 1
|
9
|
+
version: 0.7.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- New Bamboo
|
@@ -14,13 +14,14 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-02-17 00:00:00 +00:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: json
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
24
25
|
requirements:
|
25
26
|
- - ~>
|
26
27
|
- !ruby/object:Gem::Version
|
@@ -35,6 +36,7 @@ dependencies:
|
|
35
36
|
name: crack
|
36
37
|
prerelease: false
|
37
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
38
40
|
requirements:
|
39
41
|
- - ~>
|
40
42
|
- !ruby/object:Gem::Version
|
@@ -49,6 +51,7 @@ dependencies:
|
|
49
51
|
name: ruby-hmac
|
50
52
|
prerelease: false
|
51
53
|
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
52
55
|
requirements:
|
53
56
|
- - ~>
|
54
57
|
- !ruby/object:Gem::Version
|
@@ -63,6 +66,7 @@ dependencies:
|
|
63
66
|
name: signature
|
64
67
|
prerelease: false
|
65
68
|
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
66
70
|
requirements:
|
67
71
|
- - ~>
|
68
72
|
- !ruby/object:Gem::Version
|
@@ -77,6 +81,7 @@ dependencies:
|
|
77
81
|
name: rspec
|
78
82
|
prerelease: false
|
79
83
|
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
80
85
|
requirements:
|
81
86
|
- - ~>
|
82
87
|
- !ruby/object:Gem::Version
|
@@ -90,6 +95,7 @@ dependencies:
|
|
90
95
|
name: webmock
|
91
96
|
prerelease: false
|
92
97
|
requirement: &id006 !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
93
99
|
requirements:
|
94
100
|
- - ">="
|
95
101
|
- !ruby/object:Gem::Version
|
@@ -102,6 +108,7 @@ dependencies:
|
|
102
108
|
name: em-http-request
|
103
109
|
prerelease: false
|
104
110
|
requirement: &id007 !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
105
112
|
requirements:
|
106
113
|
- - ~>
|
107
114
|
- !ruby/object:Gem::Version
|
@@ -124,6 +131,7 @@ extra_rdoc_files: []
|
|
124
131
|
files:
|
125
132
|
- .document
|
126
133
|
- .gitignore
|
134
|
+
- .travis.yml
|
127
135
|
- Gemfile
|
128
136
|
- Gemfile.lock
|
129
137
|
- LICENSE
|
@@ -147,6 +155,7 @@ rdoc_options: []
|
|
147
155
|
require_paths:
|
148
156
|
- lib
|
149
157
|
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
150
159
|
requirements:
|
151
160
|
- - ">="
|
152
161
|
- !ruby/object:Gem::Version
|
@@ -154,6 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
154
163
|
- 0
|
155
164
|
version: "0"
|
156
165
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
+
none: false
|
157
167
|
requirements:
|
158
168
|
- - ">="
|
159
169
|
- !ruby/object:Gem::Version
|
@@ -163,7 +173,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
163
173
|
requirements: []
|
164
174
|
|
165
175
|
rubyforge_project:
|
166
|
-
rubygems_version: 1.3.
|
176
|
+
rubygems_version: 1.3.7
|
167
177
|
signing_key:
|
168
178
|
specification_version: 3
|
169
179
|
summary: Pusherapp client
|