pusher 0.9.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +0 -1
- data/.travis.yml +11 -0
- data/Gemfile.lock +50 -0
- data/README.md +2 -0
- data/lib/pusher.rb +2 -0
- data/lib/pusher/channel.rb +21 -17
- data/lib/pusher/client.rb +72 -4
- data/lib/pusher/request.rb +19 -8
- data/pusher.gemspec +3 -2
- data/spec/channel_spec.rb +71 -84
- data/spec/client_spec.rb +69 -2
- metadata +118 -73
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pusher (0.10.0)
|
5
|
+
multi_json (~> 1.0)
|
6
|
+
signature (~> 0.1.4)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
addressable (2.3.2)
|
12
|
+
cookiejar (0.3.0)
|
13
|
+
crack (0.3.1)
|
14
|
+
diff-lcs (1.1.3)
|
15
|
+
em-http-request (1.0.3)
|
16
|
+
addressable (>= 2.2.3)
|
17
|
+
cookiejar
|
18
|
+
em-socksify
|
19
|
+
eventmachine (>= 1.0.0.beta.4)
|
20
|
+
http_parser.rb (>= 0.5.3)
|
21
|
+
em-socksify (0.2.1)
|
22
|
+
eventmachine (>= 1.0.0.beta.4)
|
23
|
+
eventmachine (1.0.0)
|
24
|
+
http_parser.rb (0.5.3)
|
25
|
+
multi_json (1.3.6)
|
26
|
+
rack (1.4.1)
|
27
|
+
rake (0.9.2.2)
|
28
|
+
rspec (2.11.0)
|
29
|
+
rspec-core (~> 2.11.0)
|
30
|
+
rspec-expectations (~> 2.11.0)
|
31
|
+
rspec-mocks (~> 2.11.0)
|
32
|
+
rspec-core (2.11.1)
|
33
|
+
rspec-expectations (2.11.3)
|
34
|
+
diff-lcs (~> 1.1.3)
|
35
|
+
rspec-mocks (2.11.3)
|
36
|
+
signature (0.1.4)
|
37
|
+
webmock (1.8.10)
|
38
|
+
addressable (>= 2.2.7)
|
39
|
+
crack (>= 0.1.7)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
em-http-request (~> 1.0.0)
|
46
|
+
pusher!
|
47
|
+
rack
|
48
|
+
rake
|
49
|
+
rspec (~> 2.0)
|
50
|
+
webmock
|
data/README.md
CHANGED
data/lib/pusher.rb
CHANGED
@@ -30,6 +30,8 @@ module Pusher
|
|
30
30
|
def_delegators :default_client, :authentication_token, :url
|
31
31
|
def_delegators :default_client, :encrypted=, :url=
|
32
32
|
|
33
|
+
def_delegators :default_client, :channels, :channel_info, :trigger
|
34
|
+
|
33
35
|
attr_writer :logger
|
34
36
|
|
35
37
|
# Return a channel by name
|
data/lib/pusher/channel.rb
CHANGED
@@ -62,21 +62,21 @@ module Pusher
|
|
62
62
|
Pusher.logger.error("#{e.message} (#{e.class})")
|
63
63
|
Pusher.logger.debug(e.backtrace.join("\n"))
|
64
64
|
end
|
65
|
-
|
66
|
-
# Request channel
|
65
|
+
|
66
|
+
# Request info for a channel
|
67
67
|
#
|
68
|
-
# @
|
68
|
+
# @param info [Array] Array of attributes required (as lowercase strings)
|
69
|
+
# @return [Hash] Hash of requested attributes for this channel
|
69
70
|
# @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
|
70
71
|
# @raise [Pusher::HTTPError] on any error raised inside Net::HTTP - the original error is available in the original_error attribute
|
71
72
|
#
|
72
|
-
def
|
73
|
-
|
74
|
-
return request.send_sync
|
73
|
+
def info(attributes = [])
|
74
|
+
@client.channel_info(name, :info => attributes.join(','))
|
75
75
|
end
|
76
76
|
|
77
|
-
# Compute authentication string required
|
78
|
-
#
|
79
|
-
#
|
77
|
+
# Compute authentication string required as part of the authentication
|
78
|
+
# endpoint response. Generally the authenticate method should be used in
|
79
|
+
# preference to this one
|
80
80
|
#
|
81
81
|
# @param socket_id [String] Each Pusher socket connection receives a
|
82
82
|
# unique socket_id. This is sent from pusher.js to your server when
|
@@ -85,10 +85,16 @@ module Pusher
|
|
85
85
|
# @return [String]
|
86
86
|
#
|
87
87
|
def authentication_string(socket_id, custom_string = nil)
|
88
|
-
|
89
|
-
|
88
|
+
if socket_id.nil? || socket_id.empty?
|
89
|
+
raise Error, "Invalid socket_id #{socket_id}"
|
90
|
+
end
|
91
|
+
|
92
|
+
unless custom_string.nil? || custom_string.kind_of?(String)
|
93
|
+
raise Error, 'Custom argument must be a string'
|
94
|
+
end
|
90
95
|
|
91
|
-
string_to_sign = [socket_id, name, custom_string].
|
96
|
+
string_to_sign = [socket_id, name, custom_string].
|
97
|
+
compact.map(&:to_s).join(':')
|
92
98
|
Pusher.logger.debug "Signing #{string_to_sign}"
|
93
99
|
token = @client.authentication_token
|
94
100
|
digest = OpenSSL::Digest::SHA256.new
|
@@ -96,11 +102,9 @@ module Pusher
|
|
96
102
|
|
97
103
|
return "#{token.key}:#{signature}"
|
98
104
|
end
|
99
|
-
|
100
|
-
# Deprecated - for backward compatibility
|
101
|
-
alias :socket_auth :authentication_string
|
102
105
|
|
103
|
-
# Generate an authentication endpoint
|
106
|
+
# Generate the expected response for an authentication endpoint.
|
107
|
+
# See http://pusher.com/docs/authenticating_users for details.
|
104
108
|
#
|
105
109
|
# @example Private channels
|
106
110
|
# render :json => Pusher['private-my_channel'].authenticate(params[:socket_id])
|
@@ -123,7 +127,7 @@ module Pusher
|
|
123
127
|
#
|
124
128
|
def authenticate(socket_id, custom_data = nil)
|
125
129
|
custom_data = MultiJson.encode(custom_data) if custom_data
|
126
|
-
auth =
|
130
|
+
auth = authentication_string(socket_id, custom_data)
|
127
131
|
r = {:auth => auth}
|
128
132
|
r[:channel_data] = custom_data if custom_data
|
129
133
|
r
|
data/lib/pusher/client.rb
CHANGED
@@ -21,13 +21,13 @@ module Pusher
|
|
21
21
|
Signature::Token.new(@key, @secret)
|
22
22
|
end
|
23
23
|
|
24
|
-
# @private Builds a
|
25
|
-
def url
|
24
|
+
# @private Builds a url for this app, optionally appending a path
|
25
|
+
def url(path = nil)
|
26
26
|
URI::Generic.build({
|
27
27
|
:scheme => @scheme,
|
28
28
|
:host => @host,
|
29
29
|
:port => @port,
|
30
|
-
:path => "/apps/#{@app_id}"
|
30
|
+
:path => "/apps/#{@app_id}#{path}"
|
31
31
|
})
|
32
32
|
end
|
33
33
|
|
@@ -59,7 +59,7 @@ module Pusher
|
|
59
59
|
@port = boolean ? 443 : 80
|
60
60
|
end
|
61
61
|
|
62
|
-
# Return a channel by name
|
62
|
+
# Return a convenience channel object by name. No API request is made.
|
63
63
|
#
|
64
64
|
# @example
|
65
65
|
# Pusher['my-channel']
|
@@ -72,6 +72,74 @@ module Pusher
|
|
72
72
|
@channels[channel_name.to_s] ||= Channel.new(url, channel_name, self)
|
73
73
|
end
|
74
74
|
|
75
|
+
# Request a list of occupied channels from the API
|
76
|
+
#
|
77
|
+
# GET /apps/[id]/channels
|
78
|
+
#
|
79
|
+
# @param options [Hash] Hash of options for the API - see Pusher API docs
|
80
|
+
# @return [Hash] See Pusher API docs
|
81
|
+
# @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
|
82
|
+
# @raise [Pusher::HTTPError] on any error raised inside Net::HTTP - the original error is available in the original_error attribute
|
83
|
+
#
|
84
|
+
def channels(options = {})
|
85
|
+
@_channels_url ||= url('/channels')
|
86
|
+
request = Request.new(:get, @_channels_url, options, nil, nil, self)
|
87
|
+
return request.send_sync
|
88
|
+
end
|
89
|
+
|
90
|
+
# Request info for a specific channel
|
91
|
+
#
|
92
|
+
# GET /apps/[id]/channels/[channel_name]
|
93
|
+
#
|
94
|
+
# @param channel_name [String] Channel name
|
95
|
+
# @param options [Hash] Hash of options for the API - see Pusher API docs
|
96
|
+
# @return [Hash] See Pusher API docs
|
97
|
+
# @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
|
98
|
+
# @raise [Pusher::HTTPError] on any error raised inside Net::HTTP - the original error is available in the original_error attribute
|
99
|
+
#
|
100
|
+
def channel_info(channel_name, options = {})
|
101
|
+
request = Request.new(:get, url("/channels/#{channel_name}"), options, nil, nil, self)
|
102
|
+
return request.send_sync
|
103
|
+
end
|
104
|
+
|
105
|
+
# Trigger an event on one or more channels
|
106
|
+
#
|
107
|
+
# POST /apps/[app_id]/events
|
108
|
+
#
|
109
|
+
# @param channels [Array] One of more channel names
|
110
|
+
# @param event_name [String]
|
111
|
+
# @param data [Object] Event data to be triggered in javascript.
|
112
|
+
# Objects other than strings will be converted to JSON
|
113
|
+
# @param options [Hash] Additional options to send to api, e.g socket_id
|
114
|
+
# @return [Hash] See Pusher API docs
|
115
|
+
# @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
|
116
|
+
# @raise [Pusher::HTTPError] on any error raised inside Net::HTTP - the original error is available in the original_error attribute
|
117
|
+
#
|
118
|
+
def trigger(channels, event_name, data, options = {})
|
119
|
+
@_trigger_url ||= url('/events')
|
120
|
+
|
121
|
+
encoded_data = case data
|
122
|
+
when String
|
123
|
+
data
|
124
|
+
else
|
125
|
+
begin
|
126
|
+
MultiJson.encode(data)
|
127
|
+
rescue MultiJson::DecodeError => e
|
128
|
+
Pusher.logger.error("Could not convert #{data.inspect} into JSON")
|
129
|
+
raise e
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
options.merge!({
|
134
|
+
:name => event_name,
|
135
|
+
:channels => channels,
|
136
|
+
:data => encoded_data,
|
137
|
+
})
|
138
|
+
|
139
|
+
request = Request.new(:post, @_trigger_url, {}, MultiJson.encode(options), nil, self)
|
140
|
+
return request.send_sync
|
141
|
+
end
|
142
|
+
|
75
143
|
private
|
76
144
|
|
77
145
|
def configured?
|
data/lib/pusher/request.rb
CHANGED
@@ -57,7 +57,6 @@ module Pusher
|
|
57
57
|
def initialize(verb, uri, params, body = nil, token = nil, client = Pusher)
|
58
58
|
@verb = verb
|
59
59
|
@uri = uri
|
60
|
-
@client = client
|
61
60
|
|
62
61
|
if body
|
63
62
|
@body = body
|
@@ -65,13 +64,16 @@ module Pusher
|
|
65
64
|
end
|
66
65
|
|
67
66
|
request = Signature::Request.new(verb.to_s.upcase, uri.path, params)
|
68
|
-
|
69
|
-
@params =
|
67
|
+
request.sign(token || client.authentication_token)
|
68
|
+
@params = request.signed_params
|
70
69
|
end
|
71
70
|
|
72
71
|
def send_sync
|
73
|
-
|
74
|
-
|
72
|
+
if ssl?
|
73
|
+
require 'net/https' unless defined?(Net::HTTPS)
|
74
|
+
else
|
75
|
+
require 'net/http' unless defined?(Net::HTTP)
|
76
|
+
end
|
75
77
|
|
76
78
|
@http_sync ||= begin
|
77
79
|
http = Net::HTTP.new(@uri.host, @uri.port)
|
@@ -94,7 +96,7 @@ module Pusher
|
|
94
96
|
raise "Unknown verb"
|
95
97
|
end
|
96
98
|
rescue Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED,
|
97
|
-
Errno::ETIMEDOUT, Errno::EHOSTUNREACH,
|
99
|
+
Errno::ETIMEDOUT, Errno::EHOSTUNREACH,
|
98
100
|
Timeout::Error, EOFError,
|
99
101
|
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
|
100
102
|
Net::ProtocolError => e
|
@@ -103,7 +105,9 @@ module Pusher
|
|
103
105
|
raise error
|
104
106
|
end
|
105
107
|
|
106
|
-
|
108
|
+
body = response.body ? response.body.chomp : nil
|
109
|
+
|
110
|
+
return handle_response(response.code.to_i, body)
|
107
111
|
end
|
108
112
|
|
109
113
|
def send_async
|
@@ -139,7 +143,7 @@ module Pusher
|
|
139
143
|
def handle_response(status_code, body)
|
140
144
|
case status_code
|
141
145
|
when 200
|
142
|
-
return MultiJson.decode(body
|
146
|
+
return symbolize_first_level(MultiJson.decode(body))
|
143
147
|
when 202
|
144
148
|
return true
|
145
149
|
when 400
|
@@ -156,5 +160,12 @@ module Pusher
|
|
156
160
|
def ssl?
|
157
161
|
@uri.scheme == 'https'
|
158
162
|
end
|
163
|
+
|
164
|
+
def symbolize_first_level(hash)
|
165
|
+
hash.inject({}) do |result, (key, value)|
|
166
|
+
result[key.to_sym] = value
|
167
|
+
result
|
168
|
+
end
|
169
|
+
end
|
159
170
|
end
|
160
171
|
end
|
data/pusher.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "pusher"
|
6
|
-
s.version = "0.
|
6
|
+
s.version = "0.10.0"
|
7
7
|
s.platform = Gem::Platform::RUBY
|
8
8
|
s.authors = ["Pusher"]
|
9
9
|
s.email = ["support@pusher.com"]
|
@@ -12,7 +12,8 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.description = %q{Wrapper for pusher.com REST api}
|
13
13
|
|
14
14
|
s.add_dependency "multi_json", "~> 1.0"
|
15
|
-
s.add_dependency 'signature', "~> 0.1.
|
15
|
+
s.add_dependency 'signature', "~> 0.1.4"
|
16
|
+
s.add_dependency "jruby-openssl" if defined?(JRUBY_VERSION)
|
16
17
|
|
17
18
|
s.add_development_dependency "rspec", "~> 2.0"
|
18
19
|
s.add_development_dependency "webmock"
|
data/spec/channel_spec.rb
CHANGED
@@ -10,18 +10,28 @@ describe Pusher::Channel do
|
|
10
10
|
:port => 80,
|
11
11
|
})
|
12
12
|
@client.encrypted = false
|
13
|
+
@channel = @client['test_channel']
|
13
14
|
|
14
15
|
WebMock.reset!
|
15
16
|
WebMock.disable_net_connect!
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:pusher_url_regexp) { %r{/apps/20/channels/test_channel/events} }
|
16
20
|
|
17
|
-
|
21
|
+
def stub_post(status, body = nil)
|
22
|
+
options = {:status => status}
|
23
|
+
options.merge!({:body => body}) if body
|
24
|
+
|
25
|
+
WebMock.stub_request(:post, pusher_url_regexp).to_return(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def stub_post_to_raise(e)
|
29
|
+
WebMock.stub_request(:post, pusher_url_regexp).to_raise(e)
|
18
30
|
end
|
19
31
|
|
20
32
|
describe 'trigger!' do
|
21
33
|
before :each do
|
22
|
-
|
23
|
-
to_return(:status => 202)
|
24
|
-
@channel = @client['test_channel']
|
34
|
+
stub_post 202
|
25
35
|
end
|
26
36
|
|
27
37
|
it 'should configure HTTP library to talk to pusher API' do
|
@@ -41,7 +51,7 @@ describe Pusher::Channel do
|
|
41
51
|
:name => 'Pusher',
|
42
52
|
:last_name => 'App'
|
43
53
|
})
|
44
|
-
WebMock.should have_requested(:post,
|
54
|
+
WebMock.should have_requested(:post, pusher_url_regexp).with { |req|
|
45
55
|
query_hash = req.uri.query_values
|
46
56
|
query_hash["name"].should == 'new_event'
|
47
57
|
query_hash["auth_key"].should == @client.key
|
@@ -60,57 +70,54 @@ describe Pusher::Channel do
|
|
60
70
|
it "should POST string data unmodified in request body" do
|
61
71
|
string = "foo\nbar\""
|
62
72
|
@channel.trigger!('new_event', string)
|
63
|
-
WebMock.should have_requested(:post,
|
73
|
+
WebMock.should have_requested(:post, pusher_url_regexp).with { |req| req.body.should == "foo\nbar\"" }
|
64
74
|
end
|
65
75
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
).to_raise(Timeout::Error)
|
76
|
+
def trigger
|
77
|
+
lambda { @channel.trigger!('new_event', 'Some data') }
|
78
|
+
end
|
70
79
|
|
80
|
+
it "should catch all Net::HTTP exceptions and raise a Pusher::HTTPError, exposing the original error if required" do
|
81
|
+
stub_post_to_raise Timeout::Error
|
71
82
|
error_raised = nil
|
83
|
+
|
72
84
|
begin
|
73
|
-
|
85
|
+
trigger.call
|
74
86
|
rescue => e
|
75
87
|
error_raised = e
|
76
88
|
end
|
89
|
+
|
77
90
|
error_raised.class.should == Pusher::HTTPError
|
78
91
|
error_raised.message.should == 'Exception from WebMock (Timeout::Error)'
|
79
92
|
error_raised.original_error.class.should == Timeout::Error
|
80
93
|
end
|
81
94
|
|
95
|
+
|
96
|
+
it "should raise Pusher::Error if pusher returns 400" do
|
97
|
+
stub_post 400
|
98
|
+
trigger.should raise_error(Pusher::Error)
|
99
|
+
end
|
100
|
+
|
82
101
|
it "should raise AuthenticationError if pusher returns 401" do
|
83
|
-
|
84
|
-
|
85
|
-
%r{/apps/20/channels/test_channel/events}
|
86
|
-
).to_return(:status => 401)
|
87
|
-
lambda {
|
88
|
-
@client['test_channel'].trigger!('new_event', 'Some data')
|
89
|
-
}.should raise_error(Pusher::AuthenticationError)
|
102
|
+
stub_post 401
|
103
|
+
trigger.should raise_error(Pusher::AuthenticationError)
|
90
104
|
end
|
91
105
|
|
92
106
|
it "should raise Pusher::Error if pusher returns 404" do
|
93
|
-
|
94
|
-
|
95
|
-
).to_return(:status => 404)
|
96
|
-
lambda {
|
97
|
-
@client['test_channel'].trigger!('new_event', 'Some data')
|
98
|
-
}.should raise_error(Pusher::Error, 'Resource not found: app_id is probably invalid')
|
107
|
+
stub_post 404
|
108
|
+
trigger.should raise_error(Pusher::Error, 'Resource not found: app_id is probably invalid')
|
99
109
|
end
|
100
110
|
|
101
111
|
it "should raise Pusher::Error if pusher returns 500" do
|
102
|
-
|
103
|
-
|
104
|
-
).to_return(:status => 500, :body => "some error")
|
105
|
-
lambda {
|
106
|
-
@client['test_channel'].trigger!('new_event', 'Some data')
|
107
|
-
}.should raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
|
112
|
+
stub_post 500, "some error"
|
113
|
+
trigger.should raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
|
108
114
|
end
|
109
115
|
end
|
110
116
|
|
111
|
-
describe 'trigger' do
|
117
|
+
describe '#trigger' do
|
112
118
|
it "should log failure if error raised in Net::HTTP call" do
|
113
|
-
|
119
|
+
stub_post_to_raise(Net::HTTPBadResponse)
|
120
|
+
|
114
121
|
Pusher.logger.should_receive(:error).with("Exception from WebMock (Net::HTTPBadResponse) (Pusher::HTTPError)")
|
115
122
|
Pusher.logger.should_receive(:debug) #backtrace
|
116
123
|
channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
|
@@ -118,21 +125,19 @@ describe Pusher::Channel do
|
|
118
125
|
end
|
119
126
|
|
120
127
|
it "should log failure if Pusher returns an error response" do
|
121
|
-
|
122
|
-
|
123
|
-
Pusher.logger.should_receive(:error).with(" (Pusher::AuthenticationError)")
|
128
|
+
stub_post 401
|
129
|
+
Pusher.logger.should_receive(:error).with("Pusher::AuthenticationError (Pusher::AuthenticationError)")
|
124
130
|
Pusher.logger.should_receive(:debug) #backtrace
|
125
131
|
channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
|
126
132
|
channel.trigger('new_event', 'Some data')
|
127
133
|
end
|
128
134
|
end
|
129
135
|
|
130
|
-
describe "trigger_async" do
|
136
|
+
describe "#trigger_async" do
|
131
137
|
it "should by default POST to http api" do
|
132
138
|
EM.run {
|
133
|
-
|
134
|
-
channel
|
135
|
-
channel.trigger_async('new_event', 'Some data').callback {
|
139
|
+
stub_post 202
|
140
|
+
@channel.trigger_async('new_event', 'Some data').callback {
|
136
141
|
WebMock.should have_requested(:post, %r{http://api.pusherapp.com})
|
137
142
|
EM.stop
|
138
143
|
}
|
@@ -142,7 +147,7 @@ describe Pusher::Channel do
|
|
142
147
|
it "should POST to https api if ssl enabled" do
|
143
148
|
@client.encrypted = true
|
144
149
|
EM.run {
|
145
|
-
|
150
|
+
stub_post 202
|
146
151
|
channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
|
147
152
|
channel.trigger_async('new_event', 'Some data').callback {
|
148
153
|
WebMock.should have_requested(:post, %r{https://api.pusherapp.com})
|
@@ -152,12 +157,12 @@ describe Pusher::Channel do
|
|
152
157
|
end
|
153
158
|
|
154
159
|
it "should return a deferrable which succeeds in success case" do
|
155
|
-
|
160
|
+
stub_post 202
|
156
161
|
|
157
162
|
EM.run {
|
158
|
-
d = @
|
163
|
+
d = @channel.trigger_async('new_event', 'Some data')
|
159
164
|
d.callback {
|
160
|
-
WebMock.should have_requested(:post,
|
165
|
+
WebMock.should have_requested(:post, pusher_url_regexp)
|
161
166
|
EM.stop
|
162
167
|
}
|
163
168
|
d.errback {
|
@@ -168,15 +173,15 @@ describe Pusher::Channel do
|
|
168
173
|
end
|
169
174
|
|
170
175
|
it "should return a deferrable which fails (with exception) in fail case" do
|
171
|
-
|
176
|
+
stub_post 401
|
172
177
|
|
173
178
|
EM.run {
|
174
|
-
d = @
|
179
|
+
d = @channel.trigger_async('new_event', 'Some data')
|
175
180
|
d.callback {
|
176
181
|
fail
|
177
182
|
}
|
178
183
|
d.errback { |error|
|
179
|
-
WebMock.should have_requested(:post,
|
184
|
+
WebMock.should have_requested(:post, pusher_url_regexp)
|
180
185
|
error.should be_kind_of(Pusher::AuthenticationError)
|
181
186
|
EM.stop
|
182
187
|
}
|
@@ -184,76 +189,58 @@ describe Pusher::Channel do
|
|
184
189
|
end
|
185
190
|
end
|
186
191
|
|
187
|
-
describe
|
188
|
-
|
189
|
-
@
|
192
|
+
describe '#info' do
|
193
|
+
it "should call the Client#channel_info" do
|
194
|
+
@client.should_receive(:channel_info).with('mychannel', anything)
|
195
|
+
@channel = @client['mychannel']
|
196
|
+
@channel.info
|
190
197
|
end
|
191
198
|
|
192
|
-
it "should
|
193
|
-
|
194
|
-
:
|
195
|
-
:body => MultiJson.encode(:user_count => 1)
|
199
|
+
it "should assemble the requested attribes into the info option" do
|
200
|
+
@client.should_receive(:channel_info).with(anything, {
|
201
|
+
:info => "user_count,connection_count"
|
196
202
|
})
|
197
|
-
@channel = @client['presence-
|
198
|
-
|
199
|
-
@channel.stats.should == {
|
200
|
-
:user_count => 1
|
201
|
-
}
|
203
|
+
@channel = @client['presence-foo']
|
204
|
+
@channel.info(%w{user_count connection_count})
|
202
205
|
end
|
203
206
|
end
|
204
207
|
|
205
|
-
describe "
|
206
|
-
|
207
|
-
@channel
|
208
|
+
describe "#authentication_string" do
|
209
|
+
def authentication_string(*data)
|
210
|
+
lambda { @channel.authentication_string(*data) }
|
208
211
|
end
|
209
212
|
|
210
213
|
it "should return an authentication string given a socket id" do
|
211
|
-
auth = @channel.
|
214
|
+
auth = @channel.authentication_string('socketid')
|
212
215
|
|
213
216
|
auth.should == '12345678900000001:827076f551e22451357939e4c7bb1200de29f921d5bf80b40d71668f9cd61c40'
|
214
217
|
end
|
215
218
|
|
216
219
|
it "should raise error if authentication is invalid" do
|
217
220
|
[nil, ''].each do |invalid|
|
218
|
-
|
219
|
-
@channel.socket_auth(invalid)
|
220
|
-
}.should raise_error
|
221
|
+
authentication_string(invalid).should raise_error Pusher::Error
|
221
222
|
end
|
222
223
|
end
|
223
224
|
|
224
225
|
describe 'with extra string argument' do
|
225
|
-
|
226
226
|
it 'should be a string or nil' do
|
227
|
-
|
228
|
-
|
229
|
-
}.should_not raise_error
|
230
|
-
|
231
|
-
lambda {
|
232
|
-
@channel.socket_auth('socketid', 123)
|
233
|
-
}.should raise_error
|
227
|
+
authentication_string('socketid', 123).should raise_error Pusher::Error
|
228
|
+
authentication_string('socketid', {}).should raise_error Pusher::Error
|
234
229
|
|
235
|
-
|
236
|
-
|
237
|
-
}.should_not raise_error
|
238
|
-
|
239
|
-
lambda {
|
240
|
-
@channel.socket_auth('socketid', {})
|
241
|
-
}.should raise_error
|
230
|
+
authentication_string('socketid', 'boom').should_not raise_error
|
231
|
+
authentication_string('socketid', nil).should_not raise_error
|
242
232
|
end
|
243
233
|
|
244
234
|
it "should return an authentication string given a socket id and custom args" do
|
245
|
-
auth = @channel.
|
235
|
+
auth = @channel.authentication_string('socketid', 'foobar')
|
246
236
|
|
247
237
|
auth.should == "12345678900000001:#{hmac(@client.secret, "socketid:test_channel:foobar")}"
|
248
238
|
end
|
249
|
-
|
250
239
|
end
|
251
240
|
end
|
252
241
|
|
253
242
|
describe '#authenticate' do
|
254
|
-
|
255
243
|
before :each do
|
256
|
-
@channel = @client['test_channel']
|
257
244
|
@custom_data = {:uid => 123, :info => {:name => 'Foo'}}
|
258
245
|
end
|
259
246
|
|
data/spec/client_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
require 'em-http'
|
4
4
|
|
5
5
|
describe Pusher do
|
6
|
-
describe '
|
6
|
+
describe 'using multiple Client objects' do
|
7
7
|
before :each do
|
8
8
|
@client1 = Pusher::Client.new
|
9
9
|
@client2 = Pusher::Client.new
|
@@ -72,6 +72,8 @@ describe Pusher do
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
+
# The behaviour should be the same when using the Client object, or the
|
76
|
+
# 'global' client delegated through the Pusher class
|
75
77
|
[lambda { Pusher }, lambda { Pusher::Client.new }].each do |client_gen|
|
76
78
|
before :each do
|
77
79
|
@client = client_gen.call
|
@@ -130,7 +132,7 @@ describe Pusher do
|
|
130
132
|
@client.secret = '12345678900000001'
|
131
133
|
end
|
132
134
|
|
133
|
-
describe '
|
135
|
+
describe '#[]' do
|
134
136
|
before do
|
135
137
|
@channel = @client['test_channel']
|
136
138
|
end
|
@@ -154,6 +156,71 @@ describe Pusher do
|
|
154
156
|
end
|
155
157
|
end
|
156
158
|
end
|
159
|
+
|
160
|
+
describe '#channels' do
|
161
|
+
it "should call the correct URL and symbolise response correctly" do
|
162
|
+
api_path = %r{/apps/20/channels}
|
163
|
+
WebMock.stub_request(:get, api_path).to_return({
|
164
|
+
:status => 200,
|
165
|
+
:body => MultiJson.encode('channels' => {
|
166
|
+
"channel1" => {},
|
167
|
+
"channel2" => {}
|
168
|
+
})
|
169
|
+
})
|
170
|
+
@client.channels.should == {
|
171
|
+
:channels => {
|
172
|
+
"channel1" => {},
|
173
|
+
"channel2" => {}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe '#channel_info' do
|
180
|
+
it "should call correct URL and symbolise response" do
|
181
|
+
api_path = %r{/apps/20/channels/mychannel}
|
182
|
+
WebMock.stub_request(:get, api_path).to_return({
|
183
|
+
:status => 200,
|
184
|
+
:body => MultiJson.encode({
|
185
|
+
'occupied' => false,
|
186
|
+
})
|
187
|
+
})
|
188
|
+
@client.channel_info('mychannel').should == {
|
189
|
+
:occupied => false,
|
190
|
+
}
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe '#trigger' do
|
195
|
+
before :each do
|
196
|
+
@api_path = %r{/apps/20/events}
|
197
|
+
WebMock.stub_request(:post, @api_path).to_return({
|
198
|
+
:status => 200,
|
199
|
+
:body => MultiJson.encode({})
|
200
|
+
})
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should call correct URL" do
|
204
|
+
@client.trigger('mychannel', 'event', {'some' => 'data'}).
|
205
|
+
should == {}
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should pass any options in the body of the request" do
|
209
|
+
@client.trigger('mychannel', 'event', {'some' => 'data'}, {
|
210
|
+
:socket_id => "1234"
|
211
|
+
})
|
212
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
213
|
+
MultiJson.decode(req.body)["socket_id"].should == '1234'
|
214
|
+
}
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should convert non string data to JSON before posting" do
|
218
|
+
@client.trigger('mychannel', 'event', {'some' => 'data'})
|
219
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
220
|
+
MultiJson.decode(req.body)["data"].should == '{"some":"data"}'
|
221
|
+
}
|
222
|
+
end
|
223
|
+
end
|
157
224
|
end
|
158
225
|
end
|
159
226
|
end
|
metadata
CHANGED
@@ -1,105 +1,142 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: pusher
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 55
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 10
|
9
|
+
- 0
|
10
|
+
version: 0.10.0
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Pusher
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
|
18
|
+
date: 2012-09-28 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
15
21
|
name: multi_json
|
16
|
-
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
17
24
|
none: false
|
18
|
-
requirements:
|
25
|
+
requirements:
|
19
26
|
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 15
|
29
|
+
segments:
|
30
|
+
- 1
|
31
|
+
- 0
|
32
|
+
version: "1.0"
|
22
33
|
type: :runtime
|
23
|
-
|
24
|
-
|
25
|
-
- !ruby/object:Gem::Dependency
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
26
36
|
name: signature
|
27
|
-
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
39
|
none: false
|
29
|
-
requirements:
|
40
|
+
requirements:
|
30
41
|
- - ~>
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 19
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
- 1
|
47
|
+
- 4
|
48
|
+
version: 0.1.4
|
33
49
|
type: :runtime
|
34
|
-
|
35
|
-
|
36
|
-
- !ruby/object:Gem::Dependency
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
37
52
|
name: rspec
|
38
|
-
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
39
55
|
none: false
|
40
|
-
requirements:
|
56
|
+
requirements:
|
41
57
|
- - ~>
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 2
|
62
|
+
- 0
|
63
|
+
version: "2.0"
|
44
64
|
type: :development
|
45
|
-
|
46
|
-
|
47
|
-
- !ruby/object:Gem::Dependency
|
65
|
+
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
48
67
|
name: webmock
|
49
|
-
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
50
70
|
none: false
|
51
|
-
requirements:
|
52
|
-
- -
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
55
78
|
type: :development
|
56
|
-
|
57
|
-
|
58
|
-
- !ruby/object:Gem::Dependency
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
59
81
|
name: em-http-request
|
60
|
-
|
82
|
+
prerelease: false
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
61
84
|
none: false
|
62
|
-
requirements:
|
85
|
+
requirements:
|
63
86
|
- - ~>
|
64
|
-
- !ruby/object:Gem::Version
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 23
|
89
|
+
segments:
|
90
|
+
- 1
|
91
|
+
- 0
|
92
|
+
- 0
|
65
93
|
version: 1.0.0
|
66
94
|
type: :development
|
67
|
-
|
68
|
-
|
69
|
-
- !ruby/object:Gem::Dependency
|
95
|
+
version_requirements: *id005
|
96
|
+
- !ruby/object:Gem::Dependency
|
70
97
|
name: rake
|
71
|
-
|
98
|
+
prerelease: false
|
99
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
72
100
|
none: false
|
73
|
-
requirements:
|
74
|
-
- -
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
77
108
|
type: :development
|
78
|
-
|
79
|
-
|
80
|
-
- !ruby/object:Gem::Dependency
|
109
|
+
version_requirements: *id006
|
110
|
+
- !ruby/object:Gem::Dependency
|
81
111
|
name: rack
|
82
|
-
|
112
|
+
prerelease: false
|
113
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
83
114
|
none: false
|
84
|
-
requirements:
|
85
|
-
- -
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
88
122
|
type: :development
|
89
|
-
|
90
|
-
version_requirements: *70359107847900
|
123
|
+
version_requirements: *id007
|
91
124
|
description: Wrapper for pusher.com REST api
|
92
|
-
email:
|
125
|
+
email:
|
93
126
|
- support@pusher.com
|
94
127
|
executables: []
|
128
|
+
|
95
129
|
extensions: []
|
130
|
+
|
96
131
|
extra_rdoc_files: []
|
97
|
-
|
132
|
+
|
133
|
+
files:
|
98
134
|
- .document
|
99
135
|
- .gemtest
|
100
136
|
- .gitignore
|
101
137
|
- .travis.yml
|
102
138
|
- Gemfile
|
139
|
+
- Gemfile.lock
|
103
140
|
- LICENSE
|
104
141
|
- README.md
|
105
142
|
- Rakefile
|
@@ -116,31 +153,39 @@ files:
|
|
116
153
|
- spec/web_hook_spec.rb
|
117
154
|
homepage: http://github.com/pusher/pusher-gem
|
118
155
|
licenses: []
|
156
|
+
|
119
157
|
post_install_message:
|
120
158
|
rdoc_options: []
|
121
|
-
|
159
|
+
|
160
|
+
require_paths:
|
122
161
|
- lib
|
123
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
162
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
163
|
none: false
|
125
|
-
requirements:
|
126
|
-
- -
|
127
|
-
- !ruby/object:Gem::Version
|
128
|
-
|
129
|
-
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
hash: 3
|
168
|
+
segments:
|
169
|
+
- 0
|
170
|
+
version: "0"
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
172
|
none: false
|
131
|
-
requirements:
|
132
|
-
- -
|
133
|
-
- !ruby/object:Gem::Version
|
134
|
-
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
hash: 3
|
177
|
+
segments:
|
178
|
+
- 0
|
179
|
+
version: "0"
|
135
180
|
requirements: []
|
181
|
+
|
136
182
|
rubyforge_project:
|
137
|
-
rubygems_version: 1.8.
|
183
|
+
rubygems_version: 1.8.6
|
138
184
|
signing_key:
|
139
185
|
specification_version: 3
|
140
186
|
summary: Pusher API client
|
141
|
-
test_files:
|
187
|
+
test_files:
|
142
188
|
- spec/channel_spec.rb
|
143
189
|
- spec/client_spec.rb
|
144
190
|
- spec/spec_helper.rb
|
145
191
|
- spec/web_hook_spec.rb
|
146
|
-
has_rdoc:
|