ably-rest 1.0.0 → 1.0.5
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.
- checksums.yaml +4 -4
- data/README.md +12 -4
- data/lib/submodules/ably-ruby/.travis.yml +3 -0
- data/lib/submodules/ably-ruby/CHANGELOG.md +49 -4
- data/lib/submodules/ably-ruby/LICENSE +2 -2
- data/lib/submodules/ably-ruby/README.md +25 -6
- data/lib/submodules/ably-ruby/ably.gemspec +1 -1
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +4 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +18 -4
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +22 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +44 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +2 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +5 -2
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +27 -2
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +95 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +6 -3
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +26 -7
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0d3b8547bb94eb6d8efd1847fee0cc7231916da
|
4
|
+
data.tar.gz: 34e92947e49eb6ff09f3bc608277f09ef1e9b390
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 155934f7ef691a2248776199b86ab243aa8e872193b28c40afaa77f08dc939d24bb1cb7592cb0bda624f4418d4a2ce7e68f969ed57c7494d4c663a25fc90e9ec
|
7
|
+
data.tar.gz: d935e38fa7b0bbbbdafc071b63bfecedcfe5693160438f802a8a18a3db106c5aeada7845485b0d128037a09e3b69b84bf6f45ed3b7180a21bf0bd582e497d705
|
data/README.md
CHANGED
@@ -5,11 +5,15 @@
|
|
5
5
|
|
6
6
|
A Ruby REST client library for [www.ably.io](https://www.ably.io), the realtime messaging service.
|
7
7
|
|
8
|
-
Note: This library was created solely for developers who do not want EventMachine as a dependency of their application. If this is not a requirement for you, then we recommended you use the combined [REST & Realtime gem](https://rubygems.org/gems/ably).
|
9
|
-
|
10
8
|
## Documentation
|
11
9
|
|
12
|
-
Visit https://www.ably.io/documentation for a complete API reference and more examples. The examples and API below is not exhaustive.
|
10
|
+
Visit https://www.ably.io/documentation for a complete API reference and more examples. The examples and API below is not exhaustive, you should use the completely [Ably API documentation](https://www.ably.io/documentation).
|
11
|
+
|
12
|
+
## Realtime vs REST
|
13
|
+
|
14
|
+
This REST only library was created for developers who do not want EventMachine as a dependency of their application. Typically developers who are using Ably within their Rails or Sinatra apps would prefer to use the REST library as it has less dependencies and offers a synchronous API.
|
15
|
+
|
16
|
+
If however you need to use a realtime library that offers an asynchronous evented AP, then we recommended you [take a look at the combined REST & Realtime gem](https://rubygems.org/gems/ably).
|
13
17
|
|
14
18
|
## Installation
|
15
19
|
|
@@ -142,6 +146,10 @@ To see what has changed in recent versions of Bundler, see the [CHANGELOG](CHANG
|
|
142
146
|
4. Push to the branch (`git push origin my-new-feature`)
|
143
147
|
5. Create a new Pull Request
|
144
148
|
|
149
|
+
## Release Process
|
150
|
+
|
151
|
+
See the [Ably Ruby release process notes](https://github.com/ably/ably-ruby#release-process).
|
152
|
+
|
145
153
|
## License
|
146
154
|
|
147
|
-
Copyright (c)
|
155
|
+
Copyright (c) 2017 Ably Real-time Ltd, Licensed under the Apache License, Version 2.0. Refer to [LICENSE](LICENSE) for the license terms.
|
@@ -1,11 +1,56 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [
|
4
|
-
|
3
|
+
## [Unreleased](https://github.com/ably/ably-ruby/tree/v1.0.5)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v1.0.4...v1.0.5)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Add Ruby 2.1 and 2.3 to Travis tests [\#129](https://github.com/ably/ably-ruby/issues/129)
|
10
|
+
- Add supported platforms to README file [\#128](https://github.com/ably/ably-ruby/issues/128)
|
11
|
+
- Add Ruby 2.1 and 2.3 to Travis tests [\#130](https://github.com/ably/ably-ruby/pull/130) ([funkyboy](https://github.com/funkyboy))
|
12
|
+
|
13
|
+
**Closed issues:**
|
14
|
+
|
15
|
+
- Cannot get realtime to work [\#127](https://github.com/ably/ably-ruby/issues/127)
|
16
|
+
|
17
|
+
**Merged pull requests:**
|
18
|
+
|
19
|
+
- Improve pagination history test [\#138](https://github.com/ably/ably-ruby/pull/138) ([funkyboy](https://github.com/funkyboy))
|
20
|
+
- Fix failing auth test [\#135](https://github.com/ably/ably-ruby/pull/135) ([funkyboy](https://github.com/funkyboy))
|
21
|
+
- Add submodule instructions to Contributing section [\#134](https://github.com/ably/ably-ruby/pull/134) ([funkyboy](https://github.com/funkyboy))
|
22
|
+
- Add request\_id option to client [\#133](https://github.com/ably/ably-ruby/pull/133) ([funkyboy](https://github.com/funkyboy))
|
23
|
+
- Update README with supported platforms [\#131](https://github.com/ably/ably-ruby/pull/131) ([funkyboy](https://github.com/funkyboy))
|
24
|
+
|
25
|
+
## [v1.0.4](https://github.com/ably/ably-ruby/tree/v1.0.4) (2017-05-31)
|
26
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v1.0.3...v1.0.4)
|
5
27
|
|
6
|
-
|
28
|
+
## [v1.0.3](https://github.com/ably/ably-ruby/tree/v1.0.3) (2017-05-31)
|
29
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v1.0.2...v1.0.3)
|
30
|
+
|
31
|
+
## [v1.0.2](https://github.com/ably/ably-ruby/tree/v1.0.2) (2017-05-16)
|
32
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v1.0.1...v1.0.2)
|
33
|
+
|
34
|
+
**Fixed bugs:**
|
35
|
+
|
36
|
+
- Reconnect following disconnection is hitting a 403 error [\#117](https://github.com/ably/ably-ruby/issues/117)
|
37
|
+
|
38
|
+
**Merged pull requests:**
|
39
|
+
|
40
|
+
- Fallback fixes [\#120](https://github.com/ably/ably-ruby/pull/120) ([mattheworiordan](https://github.com/mattheworiordan))
|
41
|
+
- Channel name encoding error for REST requests [\#119](https://github.com/ably/ably-ruby/pull/119) ([mattheworiordan](https://github.com/mattheworiordan))
|
42
|
+
|
43
|
+
## [v1.0.1](https://github.com/ably/ably-ruby/tree/v1.0.1) (2017-05-11)
|
44
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v1.1.0-beta.push.1...v1.0.1)
|
45
|
+
|
46
|
+
## [v1.1.0-beta.push.1](https://github.com/ably/ably-ruby/tree/v1.1.0-beta.push.1) (2017-04-25)
|
47
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v1.0.0...v1.1.0-beta.push.1)
|
48
|
+
|
49
|
+
## [v1.0.0](https://github.com/ably/ably-ruby/tree/v1.0.0) (2017-03-07)
|
50
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.15...v1.0.0)
|
7
51
|
|
8
|
-
|
52
|
+
## [v0.8.15](https://github.com/ably/ably-ruby/tree/v0.8.15) (2017-03-07)
|
53
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v0.8.14...v0.8.15)
|
9
54
|
|
10
55
|
**Implemented enhancements:**
|
11
56
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2015-2017 Ably
|
2
2
|
|
3
|
-
Copyright
|
3
|
+
Copyright 2015-2017 Ably Real-time Ltd
|
4
4
|
|
5
5
|
Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
you may not use this file except in compliance with the License.
|
@@ -5,6 +5,14 @@
|
|
5
5
|
|
6
6
|
A Ruby client library for [ably.io](https://www.ably.io), the realtime messaging service.
|
7
7
|
|
8
|
+
## Supported platforms
|
9
|
+
|
10
|
+
This SDK supports Ruby 1.9.3+.
|
11
|
+
|
12
|
+
We regression-test the SDK against a selection of Ruby versions (which we update over time, but usually consists of mainstream and widely used versions). Please refer to [.travis.yml](./.travis.yml) for the set of versions that currently undergo CI testing.
|
13
|
+
|
14
|
+
If you find any compatibility issues, please [do raise an issue](https://github.com/ably/ably-ruby/issues/new) in this repository or [contact Ably customer support](https://support.ably.io/) for advice.
|
15
|
+
|
8
16
|
## Documentation
|
9
17
|
|
10
18
|
Visit https://www.ably.io/documentation for a complete API reference and more examples.
|
@@ -296,12 +304,23 @@ To see what has changed in recent versions of Bundler, see the [CHANGELOG](CHANG
|
|
296
304
|
## Contributing
|
297
305
|
|
298
306
|
1. Fork it
|
299
|
-
2.
|
300
|
-
3.
|
301
|
-
4.
|
302
|
-
|
303
|
-
|
307
|
+
2. When pulling to local, make sure to also pull the `ably-common` repo (`git submodule init && git submodule update`)
|
308
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
309
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
310
|
+
5. Ensure you have added suitable tests and the test suite is passing(`bundle exec rspec`)
|
311
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
312
|
+
7. Create a new Pull Request
|
313
|
+
|
314
|
+
## Release process
|
315
|
+
|
316
|
+
This library uses [semantic versioning](http://semver.org/). For each release, the following needs to be done:
|
317
|
+
|
318
|
+
* Update the version number in [version.rb](./lib/ably/version.rb) and commit the change.
|
319
|
+
* Run [`github_changelog_generator`](https://github.com/skywinder/Github-Changelog-Generator) to automate the update of the [CHANGELOG](./CHANGELOG.md). Once the `CHANGELOG` update has completed, manually change the `Unreleased` heading and link with the current version number such as `v1.0.0`. Also ensure that the `Full Changelog` link points to the new version tag instead of the `HEAD`. Commit this change.
|
320
|
+
* Add a tag and push to origin such as `git tag v1.0.0 && git push origin v1.0.0`
|
321
|
+
* Visit [https://github.com/ably/ably-ruby/tags](https://github.com/ably/ably-ruby/tags) and `Add release notes` for the release including links to the changelog entry.
|
322
|
+
* Run `rake release` to publish the gem to [Rubygems](http://www.rubydoc.info/gems/ably)
|
304
323
|
|
305
324
|
## License
|
306
325
|
|
307
|
-
Copyright (c)
|
326
|
+
Copyright (c) 2017 Ably Real-time Ltd, Licensed under the Apache License, Version 2.0. Refer to [LICENSE](LICENSE) for the license terms.
|
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.description = %q{A Ruby client library for ably.io realtime messaging}
|
12
12
|
spec.summary = %q{A Ruby client library for ably.io realtime messaging implemented using EventMachine}
|
13
13
|
spec.homepage = 'http://github.com/ably/ably-ruby'
|
14
|
-
spec.license = 'Apache
|
14
|
+
spec.license = 'Apache-2.0'
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
@@ -13,7 +13,7 @@ module Ably
|
|
13
13
|
# @!attribute [r] code
|
14
14
|
# @return [String] Ably specific error code
|
15
15
|
class BaseAblyException < StandardError
|
16
|
-
attr_reader :status, :code
|
16
|
+
attr_reader :status, :code, :request_id
|
17
17
|
|
18
18
|
def initialize(message, status = nil, code = nil, base_exception = nil, options = {})
|
19
19
|
super message
|
@@ -25,6 +25,7 @@ module Ably
|
|
25
25
|
@code = code
|
26
26
|
@code ||= base_exception.code if base_exception && base_exception.respond_to?(:code)
|
27
27
|
@code ||= options[:fallback_code]
|
28
|
+
@request_id ||= options[:request_id]
|
28
29
|
end
|
29
30
|
|
30
31
|
def to_s
|
@@ -34,12 +35,13 @@ module Ably
|
|
34
35
|
additional_info << "code: #{code}" if code
|
35
36
|
additional_info << "http status: #{status}" if status
|
36
37
|
additional_info << "base exception: #{@base_exception.class}" if @base_exception
|
38
|
+
additional_info << "request_id: #{request_id}" if request_id
|
37
39
|
message << "(#{additional_info.join(', ')})"
|
38
40
|
end
|
39
41
|
message.join(' ')
|
40
42
|
end
|
41
43
|
|
42
|
-
def as_json
|
44
|
+
def as_json(*args)
|
43
45
|
{
|
44
46
|
message: "#{self.class}: #{message}",
|
45
47
|
status: @status,
|
@@ -351,7 +351,7 @@ module Ably
|
|
351
351
|
def determine_host
|
352
352
|
raise ArgumentError, 'Block required' unless block_given?
|
353
353
|
|
354
|
-
if
|
354
|
+
if should_use_fallback_hosts?
|
355
355
|
internet_up? do |internet_is_up_result|
|
356
356
|
@current_host = if internet_is_up_result
|
357
357
|
client.fallback_endpoint.host
|
@@ -424,7 +424,8 @@ module Ably
|
|
424
424
|
)
|
425
425
|
|
426
426
|
# Use native websocket heartbeats if possible
|
427
|
-
|
427
|
+
# TODO: Fix once https://github.com/ably/ably-ruby/issues/116 is resolved
|
428
|
+
url_params['heartbeats'] = 'true' # unless defaults.fetch(:websocket_heartbeats_disabled)
|
428
429
|
|
429
430
|
url_params['clientId'] = client.auth.client_id if client.auth.has_client_id?
|
430
431
|
|
@@ -444,6 +445,10 @@ module Ably
|
|
444
445
|
end
|
445
446
|
|
446
447
|
determine_host do |host|
|
448
|
+
# Ensure the hostname matches the fallback host name
|
449
|
+
url.hostname = host
|
450
|
+
url.port = port
|
451
|
+
|
447
452
|
begin
|
448
453
|
logger.debug { "Connection: Opening socket connection to #{host}:#{port}/#{url.path}?#{url.query}" }
|
449
454
|
@transport = create_transport(host, port, url) do |websocket_transport|
|
@@ -509,6 +514,7 @@ module Ably
|
|
509
514
|
|
510
515
|
# @api private
|
511
516
|
def create_transport(host, port, url, &block)
|
517
|
+
logger.debug { "Connection: EventMachine connecting to #{host}:#{port} with URL: #{url}" }
|
512
518
|
EventMachine.connect(host, port, WebsocketTransport, self, url.to_s, &block)
|
513
519
|
end
|
514
520
|
|
@@ -641,14 +647,22 @@ module Ably
|
|
641
647
|
!!client.custom_realtime_host
|
642
648
|
end
|
643
649
|
|
644
|
-
def
|
650
|
+
def should_use_fallback_hosts?
|
645
651
|
if client.fallback_hosts && !client.fallback_hosts.empty?
|
646
|
-
if connecting? && previous_state
|
652
|
+
if connecting? && previous_state && !disconnected_from_connected_state?
|
647
653
|
use_fallback_if_disconnected? || use_fallback_if_suspended?
|
648
654
|
end
|
649
655
|
end
|
650
656
|
end
|
651
657
|
|
658
|
+
def disconnected_from_connected_state?
|
659
|
+
most_recent_state_changes = state_history.last(3).first(2) # Ignore current state
|
660
|
+
|
661
|
+
# A valid connection was disconnected
|
662
|
+
most_recent_state_changes.last.fetch(:state) == Connection::STATE.Disconnected &&
|
663
|
+
most_recent_state_changes.first.fetch(:state) == Connection::STATE.Connected
|
664
|
+
end
|
665
|
+
|
652
666
|
def use_fallback_if_disconnected?
|
653
667
|
second_reconnect_attempt_for(:disconnected, 1)
|
654
668
|
end
|
@@ -83,6 +83,10 @@ module Ably
|
|
83
83
|
# if empty or nil then fallback host functionality is disabled
|
84
84
|
attr_reader :fallback_hosts
|
85
85
|
|
86
|
+
# Whethere the {Client} has to add a random identifier to the path of a request
|
87
|
+
# @return [Boolean]
|
88
|
+
attr_reader :add_request_ids
|
89
|
+
|
86
90
|
# Creates a {Ably::Rest::Client Rest Client} and configures the {Ably::Auth} object for the connection.
|
87
91
|
#
|
88
92
|
# @param [Hash,String] options an options Hash used to configure the client and the authentication, or String with an API key or Token ID
|
@@ -146,6 +150,7 @@ module Ably
|
|
146
150
|
@custom_host = options.delete(:rest_host)
|
147
151
|
@custom_port = options.delete(:port)
|
148
152
|
@custom_tls_port = options.delete(:tls_port)
|
153
|
+
@add_request_ids = options.delete(:add_request_ids)
|
149
154
|
|
150
155
|
if options[:fallback_hosts_use_default] && options[:fallback_jhosts]
|
151
156
|
raise ArgumentError, "fallback_hosts_use_default cannot be set to trye when fallback_jhosts is also provided"
|
@@ -434,11 +439,25 @@ module Ably
|
|
434
439
|
max_retry_duration = http_defaults.fetch(:max_retry_duration)
|
435
440
|
requested_at = Time.now
|
436
441
|
retry_count = 0
|
442
|
+
request_id = nil
|
443
|
+
if add_request_ids
|
444
|
+
params = if params.nil?
|
445
|
+
{}
|
446
|
+
else
|
447
|
+
params.dup
|
448
|
+
end
|
449
|
+
request_id = SecureRandom.urlsafe_base64(10)
|
450
|
+
params[:request_id] = request_id
|
451
|
+
end
|
437
452
|
|
438
453
|
begin
|
439
454
|
use_fallback = can_fallback_to_alternate_ably_host? && retry_count > 0
|
440
455
|
|
441
456
|
connection(use_fallback: use_fallback).send(method, path, params) do |request|
|
457
|
+
if add_request_ids
|
458
|
+
request.options.context = {} if request.options.context.nil?
|
459
|
+
request.options.context[:request_id] = request_id
|
460
|
+
end
|
442
461
|
unless options[:send_auth_header] == false
|
443
462
|
request.headers[:authorization] = auth.auth_header
|
444
463
|
if options[:headers]
|
@@ -456,12 +475,12 @@ module Ably
|
|
456
475
|
logger.warn { "Ably::Rest::Client - Retry #{retry_count} for #{method} #{path} #{params} as initial attempt failed: #{error}" }
|
457
476
|
retry
|
458
477
|
end
|
459
|
-
|
460
478
|
case error
|
461
479
|
when Faraday::TimeoutError
|
462
|
-
raise Ably::Exceptions::ConnectionTimeout.new(error.message, nil, 80014, error)
|
480
|
+
raise Ably::Exceptions::ConnectionTimeout.new(error.message, nil, 80014, error, { request_id: request_id })
|
463
481
|
when Faraday::ClientError
|
464
|
-
|
482
|
+
# request_id is also available in the request context
|
483
|
+
raise Ably::Exceptions::ConnectionError.new(error.message, nil, 80000, error, { request_id: request_id })
|
465
484
|
else
|
466
485
|
raise error
|
467
486
|
end
|
@@ -27,8 +27,8 @@ module Ably
|
|
27
27
|
end
|
28
28
|
|
29
29
|
message = 'Unknown server error' if message.to_s.strip == ''
|
30
|
-
|
31
|
-
exception_args = [message, error_status_code, error_code]
|
30
|
+
request_id = env.request.context[:request_id] if env.request.context
|
31
|
+
exception_args = [message, error_status_code, error_code, nil, { request_id: request_id }]
|
32
32
|
|
33
33
|
if env.status >= 500
|
34
34
|
raise Ably::Exceptions::ServerError.new(*exception_args)
|
@@ -1178,6 +1178,27 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
1178
1178
|
stop_reactor
|
1179
1179
|
end
|
1180
1180
|
end
|
1181
|
+
|
1182
|
+
it 'does not use a fallback host if the connection connects on the default host and then later becomes disconnected', em_timeout: 25 do
|
1183
|
+
request = 0
|
1184
|
+
|
1185
|
+
allow(connection).to receive(:create_transport).and_wrap_original do |wrapped_proc, host, *args, &block|
|
1186
|
+
expect(host).to eql(expected_host)
|
1187
|
+
request += 1
|
1188
|
+
wrapped_proc.call(host, *args, &block)
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
connection.on(:connected) do
|
1192
|
+
if request <= 2
|
1193
|
+
EventMachine.add_timer(3) do
|
1194
|
+
# Force a disconnect
|
1195
|
+
connection.transport.unbind
|
1196
|
+
end
|
1197
|
+
else
|
1198
|
+
stop_reactor
|
1199
|
+
end
|
1200
|
+
end
|
1201
|
+
end
|
1181
1202
|
end
|
1182
1203
|
|
1183
1204
|
context ':fallback_hosts array is provided' do
|
@@ -1286,6 +1307,29 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
|
|
1286
1307
|
end
|
1287
1308
|
end
|
1288
1309
|
end
|
1310
|
+
|
1311
|
+
it 'uses the correct host name for the WebSocket requests to the fallback hosts' do
|
1312
|
+
request = 0
|
1313
|
+
expect(connection).to receive(:create_transport).at_least(:once) do |host, port, uri|
|
1314
|
+
if request == 0 || request == expected_retry_attempts + 1
|
1315
|
+
expect(uri.hostname).to eql(expected_host)
|
1316
|
+
else
|
1317
|
+
expect(custom_hosts + [expected_host]).to include(uri.hostname)
|
1318
|
+
fallback_hosts_used << host if @suspended > 0
|
1319
|
+
end
|
1320
|
+
request += 1
|
1321
|
+
raise EventMachine::ConnectionError
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
connection.on(:suspended) do
|
1325
|
+
@suspended += 1
|
1326
|
+
|
1327
|
+
if @suspended > 4
|
1328
|
+
expect(fallback_hosts_used.uniq).to match_array(custom_hosts + [expected_host])
|
1329
|
+
stop_reactor
|
1330
|
+
end
|
1331
|
+
end
|
1332
|
+
end
|
1289
1333
|
end
|
1290
1334
|
|
1291
1335
|
context ':fallback_hosts array is provided by an empty array' do
|
@@ -980,6 +980,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
980
980
|
|
981
981
|
context 'transport-level heartbeats are supported in the websocket transport' do
|
982
982
|
it 'provides the heartbeats argument in the websocket connection params (#RTN23b)' do
|
983
|
+
skip 'Native heartbeats not yet supported in the WS driver https://github.com/ably/ably-ruby/issues/116'
|
983
984
|
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
984
985
|
uri = URI.parse(url)
|
985
986
|
expect(CGI::parse(uri.query)['heartbeats'][0]).to eql('false')
|
@@ -1007,6 +1008,7 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1007
1008
|
let(:client_options) { default_options.merge(websocket_heartbeats_disabled: true) }
|
1008
1009
|
|
1009
1010
|
it 'does not provide the heartbeats argument in the websocket connection params (#RTN23b)' do
|
1011
|
+
skip 'Native heartbeats not yet supported in the WS driver https://github.com/ably/ably-ruby/issues/116'
|
1010
1012
|
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
1011
1013
|
uri = URI.parse(url)
|
1012
1014
|
expect(CGI::parse(uri.query)['heartbeats'][0]).to be_nil
|
@@ -76,6 +76,8 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
76
76
|
end
|
77
77
|
|
78
78
|
context 'with supported extra payload content type (#RTL6h, #RSL6a2)' do
|
79
|
+
let(:channel) { client.channel("pushenabled:#{random_str}") }
|
80
|
+
|
79
81
|
def publish_and_check_extras(extras)
|
80
82
|
channel.attach
|
81
83
|
channel.publish 'event', {}, extras: extras
|
@@ -86,7 +88,7 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
86
88
|
end
|
87
89
|
|
88
90
|
context 'JSON Object (Hash)' do
|
89
|
-
let(:data) { { 'push' => { 'title' => 'Testing' } } }
|
91
|
+
let(:data) { { 'push' => { 'notification' => { 'title' => 'Testing' } } } }
|
90
92
|
|
91
93
|
it 'is encoded and decoded to the same hash' do
|
92
94
|
publish_and_check_extras data
|
@@ -94,7 +96,8 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
94
96
|
end
|
95
97
|
|
96
98
|
context 'JSON Array' do
|
97
|
-
|
99
|
+
# TODO: Add nil type back in
|
100
|
+
let(:data) { { 'push' => { 'data' => { 'key' => [ true, false, 55, 'string', { 'Hash' => true }, ['array'] ] } } } }
|
98
101
|
|
99
102
|
it 'is encoded and decoded to the same Array' do
|
100
103
|
publish_and_check_extras data
|
@@ -1083,7 +1083,7 @@ describe Ably::Auth do
|
|
1083
1083
|
expect { auth.request_token(timestamp: Time.now - 180) }.to raise_error do |error|
|
1084
1084
|
expect(error).to be_a(Ably::Exceptions::UnauthorizedRequest)
|
1085
1085
|
expect(error.status).to eql(401)
|
1086
|
-
expect(error.code).to eql(
|
1086
|
+
expect(error.code).to eql(40104)
|
1087
1087
|
end
|
1088
1088
|
end
|
1089
1089
|
|
@@ -256,6 +256,25 @@ describe Ably::Rest::Channel do
|
|
256
256
|
end
|
257
257
|
end
|
258
258
|
end
|
259
|
+
|
260
|
+
context 'with a non ASCII channel name' do
|
261
|
+
let(:channel_name) { 'foo:¡€≤`☃' }
|
262
|
+
let(:channel_name_encoded) { 'foo%3A%C2%A1%E2%82%AC%E2%89%A4%60%E2%98%83' }
|
263
|
+
let(:endpoint) { client.endpoint }
|
264
|
+
let(:channel) { client.channels.get(channel_name) }
|
265
|
+
|
266
|
+
context 'stubbed', :webmock do
|
267
|
+
let!(:get_stub) {
|
268
|
+
stub_request(:post, "#{endpoint}/channels/#{channel_name_encoded}/publish").
|
269
|
+
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
270
|
+
}
|
271
|
+
|
272
|
+
it 'correctly encodes the channel name' do
|
273
|
+
channel.publish('foo')
|
274
|
+
expect(get_stub).to have_been_requested
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
259
278
|
end
|
260
279
|
|
261
280
|
describe '#history' do
|
@@ -324,7 +343,13 @@ describe Ably::Rest::Channel do
|
|
324
343
|
|
325
344
|
# Page 3
|
326
345
|
expect(page_3.items.size).to eql(1)
|
327
|
-
|
346
|
+
# This test should be deterministic but it's not.
|
347
|
+
# Sometimes the backend, to avoid too much work, returns a `next` link that contains empty reults.
|
348
|
+
if page_3.next
|
349
|
+
expect(page_3.next.items.length).to eql(0)
|
350
|
+
else
|
351
|
+
expect(page_3).to be_last
|
352
|
+
end
|
328
353
|
end
|
329
354
|
|
330
355
|
context 'direction' do
|
@@ -374,7 +399,7 @@ describe Ably::Rest::Channel do
|
|
374
399
|
let!(:history_stub) {
|
375
400
|
query_params = default_history_options
|
376
401
|
.merge(option => milliseconds).map { |k, v| "#{k}=#{v}" }.join('&')
|
377
|
-
stub_request(:get, "#{endpoint}/channels/#{
|
402
|
+
stub_request(:get, "#{endpoint}/channels/#{URI.encode_www_form_component(channel_name)}/messages?#{query_params}").
|
378
403
|
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
379
404
|
}
|
380
405
|
|
@@ -959,5 +959,100 @@ describe Ably::Rest::Client do
|
|
959
959
|
end
|
960
960
|
end
|
961
961
|
end
|
962
|
+
|
963
|
+
context 'request_id generation' do
|
964
|
+
context 'Timeout error' do
|
965
|
+
context 'with request_id', :webmock do
|
966
|
+
let(:custom_logger) do
|
967
|
+
Class.new do
|
968
|
+
def initialize
|
969
|
+
@messages = []
|
970
|
+
end
|
971
|
+
|
972
|
+
[:fatal, :error, :warn, :info, :debug].each do |severity|
|
973
|
+
define_method severity do |message, &block|
|
974
|
+
message_val = [message]
|
975
|
+
message_val << block.call if block
|
976
|
+
|
977
|
+
@messages << [severity, message_val.compact.join(' ')]
|
978
|
+
end
|
979
|
+
end
|
980
|
+
|
981
|
+
def logs
|
982
|
+
@messages
|
983
|
+
end
|
984
|
+
|
985
|
+
def level
|
986
|
+
1
|
987
|
+
end
|
988
|
+
|
989
|
+
def level=(new_level)
|
990
|
+
end
|
991
|
+
end
|
992
|
+
end
|
993
|
+
let(:custom_logger_object) { custom_logger.new }
|
994
|
+
let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object, add_request_ids: true) }
|
995
|
+
before do
|
996
|
+
@request_id = nil
|
997
|
+
stub_request(:get, Addressable::Template.new("#{client.endpoint}/time{?request_id}")).with do |request|
|
998
|
+
@request_id = request.uri.query_values['request_id']
|
999
|
+
end.to_return do
|
1000
|
+
raise Faraday::TimeoutError.new('timeout error message')
|
1001
|
+
end
|
1002
|
+
end
|
1003
|
+
it 'has an error with the same request_id of the request' do
|
1004
|
+
expect{ client.time }.to raise_error(Ably::Exceptions::ConnectionTimeout, /#{@request_id}/)
|
1005
|
+
expect(custom_logger_object.logs.find { |severity, message| message.match(/#{@request_id}/i)} ).to_not be_nil
|
1006
|
+
end
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
context 'when specifying fallback hosts', :webmock do
|
1010
|
+
let(:client_options) { { key: api_key, fallback_hosts_use_default: true, add_request_ids: true } }
|
1011
|
+
let(:requests) { [] }
|
1012
|
+
before do
|
1013
|
+
@request_id = nil
|
1014
|
+
hosts = Ably::FALLBACK_HOSTS + ['rest.ably.io']
|
1015
|
+
hosts.each do |host|
|
1016
|
+
stub_request(:get, Addressable::Template.new("https://#{host.downcase}/time{?request_id}")).with do |request|
|
1017
|
+
@request_id = request.uri.query_values['request_id']
|
1018
|
+
requests << @request_id
|
1019
|
+
end.to_return do
|
1020
|
+
raise Faraday::TimeoutError.new('timeout error message')
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
end
|
1024
|
+
it 'request_id is the same across retries' do
|
1025
|
+
expect{ client.time }.to raise_error(Ably::Exceptions::ConnectionTimeout, /#{@request_id}/)
|
1026
|
+
expect(requests.uniq.count).to eql(1)
|
1027
|
+
expect(requests.uniq.first).to eql(@request_id)
|
1028
|
+
end
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
context 'without request_id' do
|
1032
|
+
let(:client_options) { default_options.merge(key: api_key, http_request_timeout: 0) }
|
1033
|
+
it 'does not include request_id in ConnectionTimeout error' do
|
1034
|
+
begin
|
1035
|
+
client.stats
|
1036
|
+
rescue Ably::Exceptions::ConnectionTimeout => err
|
1037
|
+
expect(err.request_id).to eql(nil)
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
end
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
context 'UnauthorizedRequest nonce error' do
|
1044
|
+
let(:token_params) { { nonce: "samenonce_#{protocol}", timestamp: Time.now.to_i } }
|
1045
|
+
it 'includes request_id in UnauthorizedRequest error due to replayed nonce' do
|
1046
|
+
client1 = Ably::Rest::Client.new(default_options.merge(key: api_key))
|
1047
|
+
client2 = Ably::Rest::Client.new(default_options.merge(key: api_key, add_request_ids: true))
|
1048
|
+
expect { client1.auth.request_token(token_params) }.not_to raise_error
|
1049
|
+
begin
|
1050
|
+
client2.auth.request_token(token_params)
|
1051
|
+
rescue Ably::Exceptions::UnauthorizedRequest => err
|
1052
|
+
expect(err.request_id).to_not eql(nil)
|
1053
|
+
end
|
1054
|
+
end
|
1055
|
+
end
|
1056
|
+
end
|
962
1057
|
end
|
963
1058
|
end
|
@@ -62,8 +62,10 @@ describe Ably::Rest::Channel, 'messages' do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
context 'with supported extra payload content type (#RSL1h, #RSL6a2)' do
|
65
|
+
let(:channel) { client.channel("pushenabled:#{random_str}") }
|
66
|
+
|
65
67
|
context 'JSON Object (Hash)' do
|
66
|
-
let(:data) { { 'push' => { 'title' => 'Testing' } } }
|
68
|
+
let(:data) { { 'push' => { 'notification' => { 'title' => 'Testing' } } } }
|
67
69
|
|
68
70
|
it 'is encoded and decoded to the same hash' do
|
69
71
|
channel.publish 'event', {}, extras: data
|
@@ -72,9 +74,10 @@ describe Ably::Rest::Channel, 'messages' do
|
|
72
74
|
end
|
73
75
|
|
74
76
|
context 'JSON Array' do
|
75
|
-
|
77
|
+
# TODO: Add nil type back in
|
78
|
+
let(:data) { { 'push' => { 'data' => { 'key' => [ true, false, 55, 'string', { 'Hash' => true }, ['array'] ] } } } }
|
76
79
|
|
77
|
-
it 'is encoded and decoded to the same
|
80
|
+
it 'is encoded and decoded to the same deep multi-type object' do
|
78
81
|
channel.publish 'event', {}, extras: data
|
79
82
|
expect(channel.history.items.first.extras).to eql(data)
|
80
83
|
end
|
@@ -73,7 +73,7 @@ describe Ably::Rest::Presence do
|
|
73
73
|
end
|
74
74
|
let!(:get_stub) {
|
75
75
|
query_params = query_options.map { |k, v| "#{k}=#{v}" }.join('&')
|
76
|
-
stub_request(:get, "#{endpoint}/channels/#{
|
76
|
+
stub_request(:get, "#{endpoint}/channels/#{URI.encode_www_form_component(channel_name)}/presence?#{query_params}").
|
77
77
|
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
78
78
|
}
|
79
79
|
let(:channel_name) { random_str }
|
@@ -111,6 +111,25 @@ describe Ably::Rest::Presence do
|
|
111
111
|
expect(fixtures_channel.presence.get(connection_id: 'does.not.exist').items).to be_empty
|
112
112
|
end
|
113
113
|
end
|
114
|
+
|
115
|
+
context 'with a non ASCII channel name' do
|
116
|
+
let(:channel_name) { 'foo:¡€≤`☃' }
|
117
|
+
let(:channel_name_encoded) { 'foo%3A%C2%A1%E2%82%AC%E2%89%A4%60%E2%98%83' }
|
118
|
+
let(:endpoint) { client.endpoint }
|
119
|
+
let(:channel) { client.channels.get(channel_name) }
|
120
|
+
|
121
|
+
context 'stubbed', :webmock do
|
122
|
+
let!(:get_stub) {
|
123
|
+
stub_request(:get, "#{endpoint}/channels/#{channel_name_encoded}/presence?limit=100").
|
124
|
+
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
125
|
+
}
|
126
|
+
|
127
|
+
it 'correctly encodes the channel name' do
|
128
|
+
channel.presence.get
|
129
|
+
expect(get_stub).to have_been_requested
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
114
133
|
end
|
115
134
|
|
116
135
|
describe '#history' do
|
@@ -194,7 +213,7 @@ describe Ably::Rest::Presence do
|
|
194
213
|
context 'limit options', :webmock do
|
195
214
|
let!(:history_stub) {
|
196
215
|
query_params = history_options.map { |k, v| "#{k}=#{v}" }.join('&')
|
197
|
-
stub_request(:get, "#{endpoint}/channels/#{
|
216
|
+
stub_request(:get, "#{endpoint}/channels/#{URI.encode_www_form_component(channel_name)}/presence/history?#{query_params}").
|
198
217
|
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
199
218
|
}
|
200
219
|
|
@@ -234,7 +253,7 @@ describe Ably::Rest::Presence do
|
|
234
253
|
}
|
235
254
|
let!(:history_stub) {
|
236
255
|
query_params = history_options.map { |k, v| "#{k}=#{v}" }.join('&')
|
237
|
-
stub_request(:get, "#{endpoint}/channels/#{
|
256
|
+
stub_request(:get, "#{endpoint}/channels/#{URI.encode_www_form_component(channel_name)}/presence/history?#{query_params}").
|
238
257
|
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
239
258
|
}
|
240
259
|
|
@@ -338,7 +357,7 @@ describe Ably::Rest::Presence do
|
|
338
357
|
|
339
358
|
context '#get' do
|
340
359
|
let!(:get_stub) {
|
341
|
-
stub_request(:get, "#{endpoint}/channels/#{
|
360
|
+
stub_request(:get, "#{endpoint}/channels/#{URI.encode_www_form_component(channel_name)}/presence?limit=100").
|
342
361
|
to_return(:body => serialized_encoded_message, :headers => { 'Content-Type' => content_type })
|
343
362
|
}
|
344
363
|
|
@@ -355,7 +374,7 @@ describe Ably::Rest::Presence do
|
|
355
374
|
|
356
375
|
context '#history' do
|
357
376
|
let!(:history_stub) {
|
358
|
-
stub_request(:get, "#{endpoint}/channels/#{
|
377
|
+
stub_request(:get, "#{endpoint}/channels/#{URI.encode_www_form_component(channel_name)}/presence/history?direction=backwards&limit=100").
|
359
378
|
to_return(:body => serialized_encoded_message, :headers => { 'Content-Type' => content_type })
|
360
379
|
}
|
361
380
|
|
@@ -385,7 +404,7 @@ describe Ably::Rest::Presence do
|
|
385
404
|
context '#get' do
|
386
405
|
let(:client_options) { default_options.merge(log_level: :fatal) }
|
387
406
|
let!(:get_stub) {
|
388
|
-
stub_request(:get, "#{endpoint}/channels/#{
|
407
|
+
stub_request(:get, "#{endpoint}/channels/#{URI.encode_www_form_component(channel_name)}/presence?limit=100").
|
389
408
|
to_return(:body => serialized_encoded_message_with_invalid_encoding, :headers => { 'Content-Type' => content_type })
|
390
409
|
}
|
391
410
|
let(:presence_message) { presence.get.items.first }
|
@@ -409,7 +428,7 @@ describe Ably::Rest::Presence do
|
|
409
428
|
context '#history' do
|
410
429
|
let(:client_options) { default_options.merge(log_level: :fatal) }
|
411
430
|
let!(:history_stub) {
|
412
|
-
stub_request(:get, "#{endpoint}/channels/#{
|
431
|
+
stub_request(:get, "#{endpoint}/channels/#{URI.encode_www_form_component(channel_name)}/presence/history?direction=backwards&limit=100").
|
413
432
|
to_return(:body => serialized_encoded_message_with_invalid_encoding, :headers => { 'Content-Type' => content_type })
|
414
433
|
}
|
415
434
|
let(:presence_message) { presence.history.items.first }
|
@@ -50,4 +50,11 @@ describe Ably::Rest::Client do
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
53
|
+
|
54
|
+
context 'request_id generation' do
|
55
|
+
let(:client_options) { { key: 'appid.keyuid:keysecret', add_request_ids: true } }
|
56
|
+
it 'includes request_id in URL' do
|
57
|
+
expect(subject.add_request_ids).to eql(true)
|
58
|
+
end
|
59
|
+
end
|
53
60
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ably-rest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew O'Riordan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|