scout 5.7.1 → 5.7.2.pre
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/CHANGELOG.markdown +5 -0
- data/lib/scout/command/run.rb +1 -1
- data/lib/scout/server.rb +2 -1
- data/lib/scout/streamer.rb +3 -2
- data/lib/scout/streamer_daemon.rb +4 -4
- data/lib/scout/version.rb +1 -1
- data/test/scout_test.rb +7 -8
- data/vendor/httpclient/README.txt +759 -0
- data/vendor/httpclient/bin/httpclient +65 -0
- data/vendor/httpclient/lib/hexdump.rb +50 -0
- data/vendor/httpclient/lib/http-access2.rb +55 -0
- data/vendor/httpclient/lib/http-access2/cookie.rb +1 -0
- data/vendor/httpclient/lib/http-access2/http.rb +1 -0
- data/vendor/httpclient/lib/httpclient.rb +1156 -0
- data/vendor/httpclient/lib/httpclient/auth.rb +899 -0
- data/vendor/httpclient/lib/httpclient/cacert.p7s +1912 -0
- data/vendor/httpclient/lib/httpclient/connection.rb +88 -0
- data/vendor/httpclient/lib/httpclient/cookie.rb +438 -0
- data/vendor/httpclient/lib/httpclient/http.rb +1046 -0
- data/vendor/httpclient/lib/httpclient/include_client.rb +83 -0
- data/vendor/httpclient/lib/httpclient/session.rb +1025 -0
- data/vendor/httpclient/lib/httpclient/ssl_config.rb +403 -0
- data/vendor/httpclient/lib/httpclient/timeout.rb +140 -0
- data/vendor/httpclient/lib/httpclient/util.rb +178 -0
- data/vendor/httpclient/lib/httpclient/version.rb +3 -0
- data/vendor/httpclient/lib/oauthclient.rb +110 -0
- data/vendor/httpclient/sample/async.rb +8 -0
- data/vendor/httpclient/sample/auth.rb +11 -0
- data/vendor/httpclient/sample/cookie.rb +18 -0
- data/vendor/httpclient/sample/dav.rb +103 -0
- data/vendor/httpclient/sample/howto.rb +49 -0
- data/vendor/httpclient/sample/oauth_buzz.rb +57 -0
- data/vendor/httpclient/sample/oauth_friendfeed.rb +59 -0
- data/vendor/httpclient/sample/oauth_salesforce_10.rb +63 -0
- data/vendor/httpclient/sample/oauth_twitter.rb +61 -0
- data/vendor/httpclient/sample/ssl/0cert.pem +22 -0
- data/vendor/httpclient/sample/ssl/0key.pem +30 -0
- data/vendor/httpclient/sample/ssl/1000cert.pem +19 -0
- data/vendor/httpclient/sample/ssl/1000key.pem +18 -0
- data/vendor/httpclient/sample/ssl/htdocs/index.html +10 -0
- data/vendor/httpclient/sample/ssl/ssl_client.rb +22 -0
- data/vendor/httpclient/sample/ssl/webrick_httpsd.rb +29 -0
- data/vendor/httpclient/sample/stream.rb +21 -0
- data/vendor/httpclient/sample/thread.rb +27 -0
- data/vendor/httpclient/sample/wcat.rb +21 -0
- data/vendor/httpclient/test/ca-chain.cert +44 -0
- data/vendor/httpclient/test/ca.cert +23 -0
- data/vendor/httpclient/test/client.cert +19 -0
- data/vendor/httpclient/test/client.key +15 -0
- data/vendor/httpclient/test/helper.rb +129 -0
- data/vendor/httpclient/test/htdigest +1 -0
- data/vendor/httpclient/test/htpasswd +2 -0
- data/vendor/httpclient/test/runner.rb +2 -0
- data/vendor/httpclient/test/server.cert +19 -0
- data/vendor/httpclient/test/server.key +15 -0
- data/vendor/httpclient/test/sslsvr.rb +65 -0
- data/vendor/httpclient/test/subca.cert +21 -0
- data/vendor/httpclient/test/test_auth.rb +321 -0
- data/vendor/httpclient/test/test_cookie.rb +391 -0
- data/vendor/httpclient/test/test_hexdump.rb +14 -0
- data/vendor/httpclient/test/test_http-access2.rb +507 -0
- data/vendor/httpclient/test/test_httpclient.rb +1783 -0
- data/vendor/httpclient/test/test_include_client.rb +52 -0
- data/vendor/httpclient/test/test_ssl.rb +235 -0
- data/vendor/multi_json/.document +5 -0
- data/vendor/multi_json/.rspec +3 -0
- data/vendor/multi_json/.travis.yml +11 -0
- data/vendor/multi_json/.yardopts +6 -0
- data/vendor/multi_json/CHANGELOG.md +169 -0
- data/vendor/multi_json/CONTRIBUTING.md +46 -0
- data/vendor/multi_json/Gemfile +31 -0
- data/vendor/multi_json/LICENSE.md +20 -0
- data/vendor/multi_json/README.md +109 -0
- data/vendor/multi_json/Rakefile +12 -0
- data/vendor/multi_json/lib/multi_json.rb +157 -0
- data/vendor/multi_json/lib/multi_json/adapter.rb +48 -0
- data/vendor/multi_json/lib/multi_json/adapters/gson.rb +19 -0
- data/vendor/multi_json/lib/multi_json/adapters/jr_jackson.rb +19 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_common.rb +25 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_gem.rb +11 -0
- data/vendor/multi_json/lib/multi_json/adapters/json_pure.rb +11 -0
- data/vendor/multi_json/lib/multi_json/adapters/nsjsonserialization.rb +34 -0
- data/vendor/multi_json/lib/multi_json/adapters/oj.rb +24 -0
- data/vendor/multi_json/lib/multi_json/adapters/ok_json.rb +22 -0
- data/vendor/multi_json/lib/multi_json/adapters/yajl.rb +19 -0
- data/vendor/multi_json/lib/multi_json/convertible_hash_keys.rb +43 -0
- data/vendor/multi_json/lib/multi_json/load_error.rb +11 -0
- data/vendor/multi_json/lib/multi_json/options.rb +48 -0
- data/vendor/multi_json/lib/multi_json/vendor/okjson.rb +606 -0
- data/vendor/multi_json/lib/multi_json/version.rb +20 -0
- data/vendor/multi_json/multi_json.gemspec +22 -0
- data/vendor/multi_json/spec/adapter_shared_example.rb +235 -0
- data/vendor/multi_json/spec/has_options.rb +119 -0
- data/vendor/multi_json/spec/helper.rb +35 -0
- data/vendor/multi_json/spec/json_common_shared_example.rb +30 -0
- data/vendor/multi_json/spec/multi_json_spec.rb +226 -0
- data/vendor/{signature → pusher}/.document +0 -0
- data/vendor/{json_pure/diagrams/.keep → pusher/.gemtest} +0 -0
- data/vendor/pusher/.gitignore +23 -0
- data/vendor/pusher/.travis.yml +15 -0
- data/vendor/pusher/Gemfile +2 -0
- data/vendor/{pusher-gem → pusher}/LICENSE +1 -1
- data/vendor/pusher/README.md +186 -0
- data/vendor/{pusher-gem → pusher}/Rakefile +0 -0
- data/vendor/{pusher-gem → pusher}/examples/async_message.rb +0 -0
- data/vendor/pusher/lib/pusher.rb +60 -0
- data/vendor/{pusher-gem → pusher}/lib/pusher/channel.rb +47 -54
- data/vendor/pusher/lib/pusher/client.rb +306 -0
- data/vendor/pusher/lib/pusher/request.rb +107 -0
- data/vendor/pusher/lib/pusher/resource.rb +36 -0
- data/vendor/pusher/lib/pusher/webhook.rb +110 -0
- data/vendor/{pusher-gem → pusher}/pusher.gemspec +6 -5
- data/vendor/pusher/spec/channel_spec.rb +127 -0
- data/vendor/pusher/spec/client_spec.rb +464 -0
- data/vendor/{pusher-gem → pusher}/spec/spec_helper.rb +12 -0
- data/vendor/pusher/spec/web_hook_spec.rb +117 -0
- data/vendor/signature/.travis.yml +15 -0
- data/vendor/signature/Gemfile +1 -1
- data/vendor/signature/README.md +38 -28
- data/vendor/signature/lib/signature.rb +97 -15
- data/vendor/signature/lib/signature/query_encoder.rb +47 -0
- data/vendor/signature/lib/signature/version.rb +1 -1
- data/vendor/signature/signature.gemspec +3 -2
- data/vendor/signature/spec/signature_spec.rb +164 -55
- data/vendor/signature/spec/spec_helper.rb +2 -3
- metadata +120 -145
- data/vendor/json_pure/.gitignore +0 -12
- data/vendor/json_pure/.travis.yml +0 -20
- data/vendor/json_pure/CHANGES +0 -282
- data/vendor/json_pure/COPYING +0 -58
- data/vendor/json_pure/COPYING-json-jruby +0 -57
- data/vendor/json_pure/GPL +0 -340
- data/vendor/json_pure/Gemfile +0 -11
- data/vendor/json_pure/README-json-jruby.markdown +0 -33
- data/vendor/json_pure/README.rdoc +0 -358
- data/vendor/json_pure/Rakefile +0 -412
- data/vendor/json_pure/TODO +0 -1
- data/vendor/json_pure/VERSION +0 -1
- data/vendor/json_pure/data/example.json +0 -1
- data/vendor/json_pure/data/index.html +0 -38
- data/vendor/json_pure/data/prototype.js +0 -4184
- data/vendor/json_pure/ext/json/ext/fbuffer/fbuffer.h +0 -181
- data/vendor/json_pure/ext/json/ext/generator/depend +0 -1
- data/vendor/json_pure/ext/json/ext/generator/extconf.rb +0 -14
- data/vendor/json_pure/ext/json/ext/generator/generator.c +0 -1435
- data/vendor/json_pure/ext/json/ext/generator/generator.h +0 -148
- data/vendor/json_pure/ext/json/ext/parser/depend +0 -1
- data/vendor/json_pure/ext/json/ext/parser/extconf.rb +0 -13
- data/vendor/json_pure/ext/json/ext/parser/parser.c +0 -2204
- data/vendor/json_pure/ext/json/ext/parser/parser.h +0 -77
- data/vendor/json_pure/ext/json/ext/parser/parser.rl +0 -927
- data/vendor/json_pure/install.rb +0 -23
- data/vendor/json_pure/java/src/json/ext/ByteListTranscoder.java +0 -167
- data/vendor/json_pure/java/src/json/ext/Generator.java +0 -444
- data/vendor/json_pure/java/src/json/ext/GeneratorMethods.java +0 -232
- data/vendor/json_pure/java/src/json/ext/GeneratorService.java +0 -43
- data/vendor/json_pure/java/src/json/ext/GeneratorState.java +0 -543
- data/vendor/json_pure/java/src/json/ext/OptionsReader.java +0 -114
- data/vendor/json_pure/java/src/json/ext/Parser.java +0 -2644
- data/vendor/json_pure/java/src/json/ext/Parser.rl +0 -968
- data/vendor/json_pure/java/src/json/ext/ParserService.java +0 -35
- data/vendor/json_pure/java/src/json/ext/RuntimeInfo.java +0 -121
- data/vendor/json_pure/java/src/json/ext/StringDecoder.java +0 -167
- data/vendor/json_pure/java/src/json/ext/StringEncoder.java +0 -106
- data/vendor/json_pure/java/src/json/ext/Utils.java +0 -89
- data/vendor/json_pure/json-java.gemspec +0 -23
- data/vendor/json_pure/json.gemspec +0 -37
- data/vendor/json_pure/json_pure.gemspec +0 -39
- data/vendor/json_pure/lib/json.rb +0 -62
- data/vendor/json_pure/lib/json/add/bigdecimal.rb +0 -28
- data/vendor/json_pure/lib/json/add/complex.rb +0 -22
- data/vendor/json_pure/lib/json/add/core.rb +0 -11
- data/vendor/json_pure/lib/json/add/date.rb +0 -34
- data/vendor/json_pure/lib/json/add/date_time.rb +0 -50
- data/vendor/json_pure/lib/json/add/exception.rb +0 -31
- data/vendor/json_pure/lib/json/add/ostruct.rb +0 -31
- data/vendor/json_pure/lib/json/add/range.rb +0 -29
- data/vendor/json_pure/lib/json/add/rational.rb +0 -22
- data/vendor/json_pure/lib/json/add/regexp.rb +0 -30
- data/vendor/json_pure/lib/json/add/struct.rb +0 -30
- data/vendor/json_pure/lib/json/add/symbol.rb +0 -25
- data/vendor/json_pure/lib/json/add/time.rb +0 -38
- data/vendor/json_pure/lib/json/common.rb +0 -487
- data/vendor/json_pure/lib/json/ext.rb +0 -21
- data/vendor/json_pure/lib/json/ext/.keep +0 -0
- data/vendor/json_pure/lib/json/generic_object.rb +0 -70
- data/vendor/json_pure/lib/json/pure.rb +0 -21
- data/vendor/json_pure/lib/json/pure/generator.rb +0 -522
- data/vendor/json_pure/lib/json/pure/parser.rb +0 -359
- data/vendor/json_pure/lib/json/version.rb +0 -8
- data/vendor/json_pure/tests/fixtures/fail1.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail10.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail11.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail12.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail13.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail14.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail18.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail19.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail2.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail20.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail21.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail22.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail23.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail24.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail25.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail27.json +0 -2
- data/vendor/json_pure/tests/fixtures/fail28.json +0 -2
- data/vendor/json_pure/tests/fixtures/fail3.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail4.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail5.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail6.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail7.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail8.json +0 -1
- data/vendor/json_pure/tests/fixtures/fail9.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass1.json +0 -56
- data/vendor/json_pure/tests/fixtures/pass15.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass16.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass17.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass2.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass26.json +0 -1
- data/vendor/json_pure/tests/fixtures/pass3.json +0 -6
- data/vendor/json_pure/tests/setup_variant.rb +0 -11
- data/vendor/json_pure/tests/test_json.rb +0 -545
- data/vendor/json_pure/tests/test_json_addition.rb +0 -196
- data/vendor/json_pure/tests/test_json_encoding.rb +0 -65
- data/vendor/json_pure/tests/test_json_fixtures.rb +0 -35
- data/vendor/json_pure/tests/test_json_generate.rb +0 -322
- data/vendor/json_pure/tests/test_json_generic_object.rb +0 -75
- data/vendor/json_pure/tests/test_json_string_matching.rb +0 -39
- data/vendor/json_pure/tests/test_json_unicode.rb +0 -72
- data/vendor/json_pure/tools/fuzz.rb +0 -139
- data/vendor/json_pure/tools/server.rb +0 -62
- data/vendor/pusher-gem/Gemfile +0 -2
- data/vendor/pusher-gem/README.md +0 -80
- data/vendor/pusher-gem/lib/pusher.rb +0 -107
- data/vendor/pusher-gem/lib/pusher/request.rb +0 -107
- data/vendor/pusher-gem/spec/channel_spec.rb +0 -274
- data/vendor/pusher-gem/spec/pusher_spec.rb +0 -87
- data/vendor/ruby-hmac/History.txt +0 -15
- data/vendor/ruby-hmac/Manifest.txt +0 -11
- data/vendor/ruby-hmac/README.md +0 -41
- data/vendor/ruby-hmac/Rakefile +0 -23
- data/vendor/ruby-hmac/lib/hmac-md5.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-rmd160.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-sha1.rb +0 -11
- data/vendor/ruby-hmac/lib/hmac-sha2.rb +0 -25
- data/vendor/ruby-hmac/lib/hmac.rb +0 -118
- data/vendor/ruby-hmac/lib/ruby_hmac.rb +0 -2
- data/vendor/ruby-hmac/ruby-hmac.gemspec +0 -33
- data/vendor/ruby-hmac/test/test_hmac.rb +0 -89
- data/vendor/signature/VERSION +0 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
require 'signature'
|
|
2
|
+
require 'digest/md5'
|
|
3
|
+
require 'multi_json'
|
|
4
|
+
|
|
5
|
+
module Pusher
|
|
6
|
+
class Request
|
|
7
|
+
attr_reader :body, :params
|
|
8
|
+
|
|
9
|
+
def initialize(client, verb, uri, params, body = nil)
|
|
10
|
+
@client, @verb, @uri = client, verb, uri
|
|
11
|
+
@head = {}
|
|
12
|
+
|
|
13
|
+
@body = body
|
|
14
|
+
if body
|
|
15
|
+
params[:body_md5] = Digest::MD5.hexdigest(body)
|
|
16
|
+
@head['Content-Type'] = 'application/json'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
request = Signature::Request.new(verb.to_s.upcase, uri.path, params)
|
|
20
|
+
request.sign(client.authentication_token)
|
|
21
|
+
@params = request.signed_params
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def send_sync
|
|
25
|
+
http = @client.sync_http_client
|
|
26
|
+
|
|
27
|
+
begin
|
|
28
|
+
response = http.request(@verb, @uri, @params, @body, @head)
|
|
29
|
+
rescue HTTPClient::BadResponseError, HTTPClient::TimeoutError,
|
|
30
|
+
SocketError, Errno::ECONNREFUSED => e
|
|
31
|
+
error = Pusher::HTTPError.new("#{e.message} (#{e.class})")
|
|
32
|
+
error.original_error = e
|
|
33
|
+
raise error
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
body = response.body ? response.body.chomp : nil
|
|
37
|
+
|
|
38
|
+
return handle_response(response.code.to_i, body)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def send_async
|
|
42
|
+
if defined?(EventMachine) && EventMachine.reactor_running?
|
|
43
|
+
http_client = @client.em_http_client(@uri)
|
|
44
|
+
df = EM::DefaultDeferrable.new
|
|
45
|
+
|
|
46
|
+
http = case @verb
|
|
47
|
+
when :post
|
|
48
|
+
http_client.post({
|
|
49
|
+
:query => @params, :body => @body, :head => @head
|
|
50
|
+
})
|
|
51
|
+
when :get
|
|
52
|
+
http_client.get({
|
|
53
|
+
:query => @params, :head => @head
|
|
54
|
+
})
|
|
55
|
+
else
|
|
56
|
+
raise "Unsuported verb"
|
|
57
|
+
end
|
|
58
|
+
http.callback {
|
|
59
|
+
begin
|
|
60
|
+
df.succeed(handle_response(http.response_header.status, http.response.chomp))
|
|
61
|
+
rescue => e
|
|
62
|
+
df.fail(e)
|
|
63
|
+
end
|
|
64
|
+
}
|
|
65
|
+
http.errback { |e|
|
|
66
|
+
message = "Network error connecting to pusher (#{http.error})"
|
|
67
|
+
Pusher.logger.debug(message)
|
|
68
|
+
df.fail(Error.new(message))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return df
|
|
72
|
+
else
|
|
73
|
+
http = @client.sync_http_client
|
|
74
|
+
|
|
75
|
+
return http.request_async(@verb, @uri, @params, @body, @head)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def handle_response(status_code, body)
|
|
82
|
+
case status_code
|
|
83
|
+
when 200
|
|
84
|
+
return symbolize_first_level(MultiJson.decode(body))
|
|
85
|
+
when 202
|
|
86
|
+
return true
|
|
87
|
+
when 400
|
|
88
|
+
raise Error, "Bad request: #{body}"
|
|
89
|
+
when 401
|
|
90
|
+
raise AuthenticationError, body
|
|
91
|
+
when 404
|
|
92
|
+
raise Error, "404 Not found (#{@uri.path})"
|
|
93
|
+
when 407
|
|
94
|
+
raise Error, "Proxy Authentication Required"
|
|
95
|
+
else
|
|
96
|
+
raise Error, "Unknown error (status code #{status_code}): #{body}"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def symbolize_first_level(hash)
|
|
101
|
+
hash.inject({}) do |result, (key, value)|
|
|
102
|
+
result[key.to_sym] = value
|
|
103
|
+
result
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Pusher
|
|
2
|
+
class Resource
|
|
3
|
+
def initialize(client, path)
|
|
4
|
+
@client = client
|
|
5
|
+
@path = path
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def get(params)
|
|
9
|
+
create_request(:get, params).send_sync
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get_async(params)
|
|
13
|
+
create_request(:get, params).send_async
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def post(params)
|
|
17
|
+
body = MultiJson.encode(params)
|
|
18
|
+
create_request(:post, {}, body).send_sync
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def post_async(params)
|
|
22
|
+
body = MultiJson.encode(params)
|
|
23
|
+
create_request(:post, {}, body).send_async
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def create_request(verb, params, body = nil)
|
|
29
|
+
Request.new(@client, verb, url, params, body)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def url
|
|
33
|
+
@_url ||= @client.url(@path)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'multi_json'
|
|
2
|
+
require 'openssl'
|
|
3
|
+
|
|
4
|
+
module Pusher
|
|
5
|
+
# Used to parse and authenticate WebHooks
|
|
6
|
+
#
|
|
7
|
+
# @example Sinatra
|
|
8
|
+
# post '/webhooks' do
|
|
9
|
+
# webhook = Pusher::WebHook.new(request)
|
|
10
|
+
# if webhook.valid?
|
|
11
|
+
# webhook.events.each do |event|
|
|
12
|
+
# case event["name"]
|
|
13
|
+
# when 'channel_occupied'
|
|
14
|
+
# puts "Channel occupied: #{event["channel"]}"
|
|
15
|
+
# when 'channel_vacated'
|
|
16
|
+
# puts "Channel vacated: #{event["channel"]}"
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
# else
|
|
20
|
+
# status 401
|
|
21
|
+
# end
|
|
22
|
+
# return
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
class WebHook
|
|
26
|
+
attr_reader :key, :signature
|
|
27
|
+
|
|
28
|
+
# Provide either a Rack::Request or a Hash containing :key, :signature,
|
|
29
|
+
# :body, and :content_type (optional)
|
|
30
|
+
#
|
|
31
|
+
def initialize(request, client = Pusher)
|
|
32
|
+
@client = client
|
|
33
|
+
# Should work without Rack
|
|
34
|
+
if defined?(Rack::Request) && request.kind_of?(Rack::Request)
|
|
35
|
+
@key = request.env['HTTP_X_PUSHER_KEY']
|
|
36
|
+
@signature = request.env["HTTP_X_PUSHER_SIGNATURE"]
|
|
37
|
+
@content_type = request.content_type
|
|
38
|
+
|
|
39
|
+
request.body.rewind
|
|
40
|
+
@body = request.body.read
|
|
41
|
+
request.body.rewind
|
|
42
|
+
else
|
|
43
|
+
@key, @signature, @body = request.values_at(:key, :signature, :body)
|
|
44
|
+
@content_type = request[:content_type] || 'application/json'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns whether the WebHook is valid by checking that the signature
|
|
49
|
+
# matches the configured key & secret. In the case that the webhook is
|
|
50
|
+
# invalid, the reason is logged
|
|
51
|
+
#
|
|
52
|
+
# @param extra_tokens [Hash] If you have extra tokens for your Pusher app, you can specify them so that they're used to attempt validation.
|
|
53
|
+
#
|
|
54
|
+
def valid?(extra_tokens = nil)
|
|
55
|
+
extra_tokens = [extra_tokens] if extra_tokens.kind_of?(Hash)
|
|
56
|
+
if @key == @client.key
|
|
57
|
+
return check_signature(@client.secret)
|
|
58
|
+
elsif extra_tokens
|
|
59
|
+
extra_tokens.each do |token|
|
|
60
|
+
return check_signature(token[:secret]) if @key == token[:key]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
Pusher.logger.warn "Received webhook with unknown key: #{key}"
|
|
64
|
+
return false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Array of events (as Hashes) contained inside the webhook
|
|
68
|
+
#
|
|
69
|
+
def events
|
|
70
|
+
data["events"]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# The time at which the WebHook was initially triggered by Pusher, i.e.
|
|
74
|
+
# when the event occurred
|
|
75
|
+
#
|
|
76
|
+
# @return [Time]
|
|
77
|
+
#
|
|
78
|
+
def time
|
|
79
|
+
Time.at(data["time_ms"].to_f/1000)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Access the parsed WebHook body
|
|
83
|
+
#
|
|
84
|
+
def data
|
|
85
|
+
@data ||= begin
|
|
86
|
+
case @content_type
|
|
87
|
+
when 'application/json'
|
|
88
|
+
MultiJson.decode(@body)
|
|
89
|
+
else
|
|
90
|
+
raise "Unknown Content-Type (#{@content_type})"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
# Checks signature against secret and returns boolean
|
|
98
|
+
#
|
|
99
|
+
def check_signature(secret)
|
|
100
|
+
digest = OpenSSL::Digest::SHA256.new
|
|
101
|
+
expected = OpenSSL::HMAC.hexdigest(digest, secret, @body)
|
|
102
|
+
if @signature == expected
|
|
103
|
+
return true
|
|
104
|
+
else
|
|
105
|
+
Pusher.logger.warn "Received WebHook with invalid signature: got #{@signature}, expected #{expected}"
|
|
106
|
+
return false
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -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.12.0"
|
|
7
7
|
s.platform = Gem::Platform::RUBY
|
|
8
8
|
s.authors = ["Pusher"]
|
|
9
9
|
s.email = ["support@pusher.com"]
|
|
@@ -12,14 +12,15 @@ 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
|
|
16
|
-
s.add_dependency "
|
|
17
|
-
s.add_dependency
|
|
15
|
+
s.add_dependency 'signature', "~> 0.1.6"
|
|
16
|
+
s.add_dependency "httpclient", "~> 2.3.0"
|
|
17
|
+
s.add_dependency "jruby-openssl" if defined?(JRUBY_VERSION)
|
|
18
18
|
|
|
19
19
|
s.add_development_dependency "rspec", "~> 2.0"
|
|
20
20
|
s.add_development_dependency "webmock"
|
|
21
|
-
s.add_development_dependency "em-http-request", "~> 1.
|
|
21
|
+
s.add_development_dependency "em-http-request", "~> 1.1.0"
|
|
22
22
|
s.add_development_dependency "rake"
|
|
23
|
+
s.add_development_dependency "rack"
|
|
23
24
|
|
|
24
25
|
s.files = `git ls-files`.split("\n")
|
|
25
26
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Pusher::Channel do
|
|
4
|
+
before do
|
|
5
|
+
@client = Pusher::Client.new({
|
|
6
|
+
:app_id => '20',
|
|
7
|
+
:key => '12345678900000001',
|
|
8
|
+
:secret => '12345678900000001',
|
|
9
|
+
:host => 'api.pusherapp.com',
|
|
10
|
+
:port => 80,
|
|
11
|
+
})
|
|
12
|
+
@channel = @client['test_channel']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
let(:pusher_url_regexp) { %r{/apps/20/events} }
|
|
16
|
+
|
|
17
|
+
def stub_post(status, body = nil)
|
|
18
|
+
options = {:status => status}
|
|
19
|
+
options.merge!({:body => body}) if body
|
|
20
|
+
|
|
21
|
+
stub_request(:post, pusher_url_regexp).to_return(options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def stub_post_to_raise(e)
|
|
25
|
+
stub_request(:post, pusher_url_regexp).to_raise(e)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '#trigger!' do
|
|
29
|
+
it "should use @client.trigger internally" do
|
|
30
|
+
@client.should_receive(:trigger)
|
|
31
|
+
@channel.trigger('new_event', 'Some data')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe '#trigger' do
|
|
36
|
+
it "should log failure if error raised in http call" do
|
|
37
|
+
stub_post_to_raise(HTTPClient::BadResponseError)
|
|
38
|
+
|
|
39
|
+
Pusher.logger.should_receive(:error).with("Exception from WebMock (HTTPClient::BadResponseError) (Pusher::HTTPError)")
|
|
40
|
+
Pusher.logger.should_receive(:debug) #backtrace
|
|
41
|
+
channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
|
|
42
|
+
channel.trigger('new_event', 'Some data')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should log failure if Pusher returns an error response" do
|
|
46
|
+
stub_post 401, "some signature info"
|
|
47
|
+
Pusher.logger.should_receive(:error).with("some signature info (Pusher::AuthenticationError)")
|
|
48
|
+
Pusher.logger.should_receive(:debug) #backtrace
|
|
49
|
+
channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
|
|
50
|
+
channel.trigger('new_event', 'Some data')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "#trigger_async" do
|
|
55
|
+
it "should use @client.trigger_async internally" do
|
|
56
|
+
@client.should_receive(:trigger_async)
|
|
57
|
+
@channel.trigger_async('new_event', 'Some data')
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe '#info' do
|
|
62
|
+
it "should call the Client#channel_info" do
|
|
63
|
+
@client.should_receive(:get).with("/channels/mychannel", anything)
|
|
64
|
+
@channel = @client['mychannel']
|
|
65
|
+
@channel.info
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should assemble the requested attribes into the info option" do
|
|
69
|
+
@client.should_receive(:get).with(anything, {
|
|
70
|
+
:info => "user_count,connection_count"
|
|
71
|
+
})
|
|
72
|
+
@channel = @client['presence-foo']
|
|
73
|
+
@channel.info(%w{user_count connection_count})
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe "#authentication_string" do
|
|
78
|
+
def authentication_string(*data)
|
|
79
|
+
lambda { @channel.authentication_string(*data) }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "should return an authentication string given a socket id" do
|
|
83
|
+
auth = @channel.authentication_string('socketid')
|
|
84
|
+
|
|
85
|
+
auth.should == '12345678900000001:827076f551e22451357939e4c7bb1200de29f921d5bf80b40d71668f9cd61c40'
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should raise error if authentication is invalid" do
|
|
89
|
+
[nil, ''].each do |invalid|
|
|
90
|
+
authentication_string(invalid).should raise_error Pusher::Error
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe 'with extra string argument' do
|
|
95
|
+
it 'should be a string or nil' do
|
|
96
|
+
authentication_string('socketid', 123).should raise_error Pusher::Error
|
|
97
|
+
authentication_string('socketid', {}).should raise_error Pusher::Error
|
|
98
|
+
|
|
99
|
+
authentication_string('socketid', 'boom').should_not raise_error
|
|
100
|
+
authentication_string('socketid', nil).should_not raise_error
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "should return an authentication string given a socket id and custom args" do
|
|
104
|
+
auth = @channel.authentication_string('socketid', 'foobar')
|
|
105
|
+
|
|
106
|
+
auth.should == "12345678900000001:#{hmac(@client.secret, "socketid:test_channel:foobar")}"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
describe '#authenticate' do
|
|
112
|
+
before :each do
|
|
113
|
+
@custom_data = {:uid => 123, :info => {:name => 'Foo'}}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'should return a hash with signature including custom data and data as json string' do
|
|
117
|
+
MultiJson.stub(:encode).with(@custom_data).and_return 'a json string'
|
|
118
|
+
|
|
119
|
+
response = @channel.authenticate('socketid', @custom_data)
|
|
120
|
+
|
|
121
|
+
response.should == {
|
|
122
|
+
:auth => "12345678900000001:#{hmac(@client.secret, "socketid:test_channel:a json string")}",
|
|
123
|
+
:channel_data => 'a json string'
|
|
124
|
+
}
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
require 'em-http'
|
|
4
|
+
|
|
5
|
+
describe Pusher do
|
|
6
|
+
describe 'using multiple Client objects' do
|
|
7
|
+
before :each do
|
|
8
|
+
@client1 = Pusher::Client.new
|
|
9
|
+
@client2 = Pusher::Client.new
|
|
10
|
+
|
|
11
|
+
@client1.scheme = 'ws'
|
|
12
|
+
@client2.scheme = 'wss'
|
|
13
|
+
@client1.host = 'one'
|
|
14
|
+
@client2.host = 'two'
|
|
15
|
+
@client1.port = 81
|
|
16
|
+
@client2.port = 82
|
|
17
|
+
@client1.app_id = '1111'
|
|
18
|
+
@client2.app_id = '2222'
|
|
19
|
+
@client1.key = 'AAAA'
|
|
20
|
+
@client2.key = 'BBBB'
|
|
21
|
+
@client1.secret = 'aaaaaaaa'
|
|
22
|
+
@client2.secret = 'bbbbbbbb'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should send scheme messages to different objects" do
|
|
26
|
+
@client1.scheme.should_not == @client2.scheme
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should send host messages to different objects" do
|
|
30
|
+
@client1.host.should_not == @client2.host
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should send port messages to different objects" do
|
|
34
|
+
@client1.port.should_not == @client2.port
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should send app_id messages to different objects" do
|
|
38
|
+
@client1.app_id.should_not == @client2.app_id
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should send app_id messages to different objects" do
|
|
42
|
+
@client1.key.should_not == @client2.key
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should send app_id messages to different objects" do
|
|
46
|
+
@client1.secret.should_not == @client2.secret
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should send app_id messages to different objects" do
|
|
50
|
+
@client1.authentication_token.key.should_not == @client2.authentication_token.key
|
|
51
|
+
@client1.authentication_token.secret.should_not == @client2.authentication_token.secret
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should send url messages to different objects" do
|
|
55
|
+
@client1.url.to_s.should_not == @client2.url.to_s
|
|
56
|
+
@client1.url = 'ws://one/apps/111'
|
|
57
|
+
@client2.url = 'wss://two/apps/222'
|
|
58
|
+
@client1.scheme.should_not == @client2.scheme
|
|
59
|
+
@client1.host.should_not == @client2.host
|
|
60
|
+
@client1.app_id.should_not == @client2.app_id
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should send encrypted messages to different objects" do
|
|
64
|
+
@client1.encrypted = false
|
|
65
|
+
@client2.encrypted = true
|
|
66
|
+
@client1.scheme.should_not == @client2.scheme
|
|
67
|
+
@client1.port.should_not == @client2.port
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "should send [] messages to different objects" do
|
|
71
|
+
@client1['test'].should_not == @client2['test']
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should send http_proxy messages to different objects" do
|
|
75
|
+
@client1.http_proxy = 'http://oneuser:onepassword@onehost:8080'
|
|
76
|
+
@client2.http_proxy = 'http://twouser:twopassword@twohost:8880'
|
|
77
|
+
@client1.http_proxy.should_not == @client2.http_proxy
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# The behaviour should be the same when using the Client object, or the
|
|
82
|
+
# 'global' client delegated through the Pusher class
|
|
83
|
+
[lambda { Pusher }, lambda { Pusher::Client.new }].each do |client_gen|
|
|
84
|
+
before :each do
|
|
85
|
+
@client = client_gen.call
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe 'default configuration' do
|
|
89
|
+
it 'should be preconfigured for api host' do
|
|
90
|
+
@client.host.should == 'api.pusherapp.com'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'should be preconfigured for port 80' do
|
|
94
|
+
@client.port.should == 80
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'should use standard logger if no other logger if defined' do
|
|
98
|
+
Pusher.logger.debug('foo')
|
|
99
|
+
Pusher.logger.should be_kind_of(Logger)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe 'logging configuration' do
|
|
104
|
+
it "can be configured to use any logger" do
|
|
105
|
+
logger = double("ALogger")
|
|
106
|
+
logger.should_receive(:debug).with('foo')
|
|
107
|
+
Pusher.logger = logger
|
|
108
|
+
Pusher.logger.debug('foo')
|
|
109
|
+
Pusher.logger = nil
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe "configuration using url" do
|
|
114
|
+
it "should be possible to configure everything by setting the url" do
|
|
115
|
+
@client.url = "test://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
|
|
116
|
+
|
|
117
|
+
@client.scheme.should == 'test'
|
|
118
|
+
@client.host.should == 'api.staging.pusherapp.com'
|
|
119
|
+
@client.port.should == 8080
|
|
120
|
+
@client.key.should == 'somekey'
|
|
121
|
+
@client.secret.should == 'somesecret'
|
|
122
|
+
@client.app_id.should == '87'
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should override scheme and port when setting encrypted=true after url" do
|
|
126
|
+
@client.url = "http://somekey:somesecret@api.staging.pusherapp.com:8080/apps/87"
|
|
127
|
+
@client.encrypted = true
|
|
128
|
+
|
|
129
|
+
@client.scheme.should == 'https'
|
|
130
|
+
@client.port.should == 443
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe 'configuring a http proxy' do
|
|
135
|
+
it "should be possible to configure everything by setting the http_proxy" do
|
|
136
|
+
@client.http_proxy = 'http://someuser:somepassword@proxy.host.com:8080'
|
|
137
|
+
|
|
138
|
+
@client.proxy.should == {:scheme => 'http', :host => 'proxy.host.com', :port => 8080, :user => 'someuser', :password => 'somepassword'}
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe 'when configured' do
|
|
143
|
+
before :each do
|
|
144
|
+
@client.app_id = '20'
|
|
145
|
+
@client.key = '12345678900000001'
|
|
146
|
+
@client.secret = '12345678900000001'
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
describe '#[]' do
|
|
150
|
+
before do
|
|
151
|
+
@channel = @client['test_channel']
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it 'should return a channel' do
|
|
155
|
+
@channel.should be_kind_of(Pusher::Channel)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
%w{app_id key secret}.each do |config|
|
|
159
|
+
it "should raise exception if #{config} not configured" do
|
|
160
|
+
@client.send("#{config}=", nil)
|
|
161
|
+
lambda {
|
|
162
|
+
@client['test_channel']
|
|
163
|
+
}.should raise_error(Pusher::ConfigurationError)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe '#channels' do
|
|
169
|
+
it "should call the correct URL and symbolise response correctly" do
|
|
170
|
+
api_path = %r{/apps/20/channels}
|
|
171
|
+
stub_request(:get, api_path).to_return({
|
|
172
|
+
:status => 200,
|
|
173
|
+
:body => MultiJson.encode('channels' => {
|
|
174
|
+
"channel1" => {},
|
|
175
|
+
"channel2" => {}
|
|
176
|
+
})
|
|
177
|
+
})
|
|
178
|
+
@client.channels.should == {
|
|
179
|
+
:channels => {
|
|
180
|
+
"channel1" => {},
|
|
181
|
+
"channel2" => {}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
describe '#channel_info' do
|
|
188
|
+
it "should call correct URL and symbolise response" do
|
|
189
|
+
api_path = %r{/apps/20/channels/mychannel}
|
|
190
|
+
stub_request(:get, api_path).to_return({
|
|
191
|
+
:status => 200,
|
|
192
|
+
:body => MultiJson.encode({
|
|
193
|
+
'occupied' => false,
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
@client.channel_info('mychannel').should == {
|
|
197
|
+
:occupied => false,
|
|
198
|
+
}
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
describe '#trigger' do
|
|
203
|
+
before :each do
|
|
204
|
+
@api_path = %r{/apps/20/events}
|
|
205
|
+
stub_request(:post, @api_path).to_return({
|
|
206
|
+
:status => 200,
|
|
207
|
+
:body => MultiJson.encode({})
|
|
208
|
+
})
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "should call correct URL" do
|
|
212
|
+
@client.trigger(['mychannel'], 'event', {'some' => 'data'}).
|
|
213
|
+
should == {}
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it "should pass any parameters in the body of the request" do
|
|
217
|
+
@client.trigger(['mychannel', 'c2'], 'event', {'some' => 'data'}, {
|
|
218
|
+
:socket_id => "1234"
|
|
219
|
+
})
|
|
220
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
|
221
|
+
parsed = MultiJson.decode(req.body)
|
|
222
|
+
parsed["name"].should == 'event'
|
|
223
|
+
parsed["channels"].should == ["mychannel", "c2"]
|
|
224
|
+
parsed["socket_id"].should == '1234'
|
|
225
|
+
}
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it "should convert non string data to JSON before posting" do
|
|
229
|
+
@client.trigger(['mychannel'], 'event', {'some' => 'data'})
|
|
230
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
|
231
|
+
MultiJson.decode(req.body)["data"].should == '{"some":"data"}'
|
|
232
|
+
}
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it "should accept a single channel as well as an array" do
|
|
236
|
+
@client.trigger('mychannel', 'event', {'some' => 'data'})
|
|
237
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
|
238
|
+
MultiJson.decode(req.body)["channels"].should == ['mychannel']
|
|
239
|
+
}
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe '#trigger_async' do
|
|
244
|
+
before :each do
|
|
245
|
+
@api_path = %r{/apps/20/events}
|
|
246
|
+
stub_request(:post, @api_path).to_return({
|
|
247
|
+
:status => 200,
|
|
248
|
+
:body => MultiJson.encode({})
|
|
249
|
+
})
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it "should call correct URL" do
|
|
253
|
+
EM.run {
|
|
254
|
+
@client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback { |r|
|
|
255
|
+
r.should == {}
|
|
256
|
+
EM.stop
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
it "should pass any parameters in the body of the request" do
|
|
262
|
+
EM.run {
|
|
263
|
+
@client.trigger_async('mychannel', 'event', {'some' => 'data'}, {
|
|
264
|
+
:socket_id => "1234"
|
|
265
|
+
}).callback {
|
|
266
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
|
267
|
+
MultiJson.decode(req.body)["socket_id"].should == '1234'
|
|
268
|
+
}
|
|
269
|
+
EM.stop
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
it "should convert non string data to JSON before posting" do
|
|
275
|
+
EM.run {
|
|
276
|
+
@client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback {
|
|
277
|
+
WebMock.should have_requested(:post, @api_path).with { |req|
|
|
278
|
+
MultiJson.decode(req.body)["data"].should == '{"some":"data"}'
|
|
279
|
+
}
|
|
280
|
+
EM.stop
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
[:get, :post].each do |verb|
|
|
287
|
+
describe "##{verb}" do
|
|
288
|
+
before :each do
|
|
289
|
+
@url_regexp = %r{api.pusherapp.com}
|
|
290
|
+
stub_request(verb, @url_regexp).
|
|
291
|
+
to_return(:status => 200, :body => "{}")
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
let(:call_api) { @client.send(verb, '/path') }
|
|
295
|
+
|
|
296
|
+
it "should use http by default" do
|
|
297
|
+
call_api
|
|
298
|
+
WebMock.should have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
it "should use https if configured" do
|
|
302
|
+
@client.encrypted = true
|
|
303
|
+
call_api
|
|
304
|
+
WebMock.should have_requested(verb, %r{https://api.pusherapp.com})
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
it "should format the respose hash with symbols at first level" do
|
|
308
|
+
stub_request(verb, @url_regexp).to_return({
|
|
309
|
+
:status => 200,
|
|
310
|
+
:body => MultiJson.encode({'something' => {'a' => 'hash'}})
|
|
311
|
+
})
|
|
312
|
+
call_api.should == {
|
|
313
|
+
:something => {'a' => 'hash'}
|
|
314
|
+
}
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
it "should catch all http exceptions and raise a Pusher::HTTPError wrapping the original error" do
|
|
318
|
+
stub_request(verb, @url_regexp).to_raise(HTTPClient::TimeoutError)
|
|
319
|
+
|
|
320
|
+
error = nil
|
|
321
|
+
begin
|
|
322
|
+
call_api
|
|
323
|
+
rescue => e
|
|
324
|
+
error = e
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
error.class.should == Pusher::HTTPError
|
|
328
|
+
error.should be_kind_of(Pusher::Error)
|
|
329
|
+
error.message.should == 'Exception from WebMock (HTTPClient::TimeoutError)'
|
|
330
|
+
error.original_error.class.should == HTTPClient::TimeoutError
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it "should raise Pusher::Error if call returns 400" do
|
|
334
|
+
stub_request(verb, @url_regexp).to_return({:status => 400})
|
|
335
|
+
lambda { call_api }.should raise_error(Pusher::Error)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
it "should raise AuthenticationError if pusher returns 401" do
|
|
339
|
+
stub_request(verb, @url_regexp).to_return({:status => 401})
|
|
340
|
+
lambda { call_api }.should raise_error(Pusher::AuthenticationError)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it "should raise Pusher::Error if pusher returns 404" do
|
|
344
|
+
stub_request(verb, @url_regexp).to_return({:status => 404})
|
|
345
|
+
lambda { call_api }.should raise_error(Pusher::Error, '404 Not found (/apps/20/path)')
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
it "should raise Pusher::Error if pusher returns 407" do
|
|
349
|
+
stub_request(verb, @url_regexp).to_return({:status => 407})
|
|
350
|
+
lambda { call_api }.should raise_error(Pusher::Error, 'Proxy Authentication Required')
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
it "should raise Pusher::Error if pusher returns 500" do
|
|
354
|
+
stub_request(verb, @url_regexp).to_return({:status => 500, :body => "some error"})
|
|
355
|
+
lambda { call_api }.should raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
describe "async calling without eventmachine" do
|
|
361
|
+
[[:get, :get_async], [:post, :post_async]].each do |verb, method|
|
|
362
|
+
describe "##{method}" do
|
|
363
|
+
before :each do
|
|
364
|
+
@url_regexp = %r{api.pusherapp.com}
|
|
365
|
+
stub_request(verb, @url_regexp).
|
|
366
|
+
to_return(:status => 200, :body => "{}")
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
let(:call_api) {
|
|
370
|
+
@client.send(method, '/path').tap { |c|
|
|
371
|
+
# Allow the async thread (inside httpclient) to run
|
|
372
|
+
while !c.finished?
|
|
373
|
+
sleep 0.01
|
|
374
|
+
end
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
it "should use http by default" do
|
|
379
|
+
call_api
|
|
380
|
+
WebMock.should have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
it "should use https if configured" do
|
|
384
|
+
@client.encrypted = true
|
|
385
|
+
call_api
|
|
386
|
+
WebMock.should have_requested(verb, %r{https://api.pusherapp.com})
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# Note that the raw httpclient connection object is returned and
|
|
390
|
+
# the response isn't handled (by handle_response) in the normal way.
|
|
391
|
+
it "should return a httpclient connection object" do
|
|
392
|
+
connection = call_api
|
|
393
|
+
connection.finished?.should be_true
|
|
394
|
+
response = connection.pop
|
|
395
|
+
response.status.should == 200
|
|
396
|
+
response.body.read.should == "{}"
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
describe "async calling with eventmachine" do
|
|
403
|
+
[[:get, :get_async], [:post, :post_async]].each do |verb, method|
|
|
404
|
+
describe "##{method}" do
|
|
405
|
+
before :each do
|
|
406
|
+
@url_regexp = %r{api.pusherapp.com}
|
|
407
|
+
stub_request(verb, @url_regexp).
|
|
408
|
+
to_return(:status => 200, :body => "{}")
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
let(:call_api) { @client.send(method, '/path') }
|
|
412
|
+
|
|
413
|
+
it "should use http by default" do
|
|
414
|
+
EM.run {
|
|
415
|
+
call_api.callback {
|
|
416
|
+
WebMock.should have_requested(verb, %r{http://api.pusherapp.com/apps/20/path})
|
|
417
|
+
EM.stop
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
it "should use https if configured" do
|
|
423
|
+
EM.run {
|
|
424
|
+
@client.encrypted = true
|
|
425
|
+
call_api.callback {
|
|
426
|
+
WebMock.should have_requested(verb, %r{https://api.pusherapp.com})
|
|
427
|
+
EM.stop
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
it "should format the respose hash with symbols at first level" do
|
|
433
|
+
EM.run {
|
|
434
|
+
stub_request(verb, @url_regexp).to_return({
|
|
435
|
+
:status => 200,
|
|
436
|
+
:body => MultiJson.encode({'something' => {'a' => 'hash'}})
|
|
437
|
+
})
|
|
438
|
+
call_api.callback { |response|
|
|
439
|
+
response.should == {
|
|
440
|
+
:something => {'a' => 'hash'}
|
|
441
|
+
}
|
|
442
|
+
EM.stop
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
it "should errback with Pusher::Error on unsuccessful response" do
|
|
448
|
+
EM.run {
|
|
449
|
+
stub_request(verb, @url_regexp).to_return({:status => 400})
|
|
450
|
+
|
|
451
|
+
call_api.errback { |e|
|
|
452
|
+
e.class.should == Pusher::Error
|
|
453
|
+
EM.stop
|
|
454
|
+
}.callback {
|
|
455
|
+
fail
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
end
|