ably 1.0.6 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +14 -0
- data/.travis.yml +10 -8
- data/CHANGELOG.md +75 -3
- data/LICENSE +1 -3
- data/README.md +12 -7
- data/Rakefile +32 -0
- data/SPEC.md +1277 -835
- data/ably.gemspec +14 -9
- data/lib/ably/auth.rb +30 -4
- data/lib/ably/exceptions.rb +10 -4
- data/lib/ably/logger.rb +7 -1
- data/lib/ably/models/channel_state_change.rb +1 -1
- data/lib/ably/models/connection_state_change.rb +1 -1
- data/lib/ably/models/device_details.rb +87 -0
- data/lib/ably/models/device_push_details.rb +86 -0
- data/lib/ably/models/error_info.rb +23 -2
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -4
- data/lib/ably/models/protocol_message.rb +32 -2
- data/lib/ably/models/push_channel_subscription.rb +89 -0
- data/lib/ably/modules/conversions.rb +1 -1
- data/lib/ably/modules/encodeable.rb +1 -1
- data/lib/ably/modules/exception_codes.rb +128 -0
- data/lib/ably/modules/model_common.rb +15 -2
- data/lib/ably/modules/state_machine.rb +2 -2
- data/lib/ably/realtime.rb +1 -0
- data/lib/ably/realtime/auth.rb +1 -1
- data/lib/ably/realtime/channel.rb +24 -102
- data/lib/ably/realtime/channel/channel_manager.rb +2 -6
- data/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
- data/lib/ably/realtime/channel/publisher.rb +74 -0
- data/lib/ably/realtime/channel/push_channel.rb +62 -0
- data/lib/ably/realtime/client.rb +91 -3
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +6 -2
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/ably/realtime/connection.rb +34 -20
- data/lib/ably/realtime/connection/connection_manager.rb +25 -9
- data/lib/ably/realtime/connection/websocket_transport.rb +1 -1
- data/lib/ably/realtime/presence.rb +4 -4
- data/lib/ably/realtime/presence/members_map.rb +3 -3
- data/lib/ably/realtime/push.rb +40 -0
- data/lib/ably/realtime/push/admin.rb +61 -0
- data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
- data/lib/ably/realtime/push/device_registrations.rb +105 -0
- data/lib/ably/rest.rb +1 -0
- data/lib/ably/rest/channel.rb +53 -17
- data/lib/ably/rest/channel/push_channel.rb +62 -0
- data/lib/ably/rest/client.rb +154 -32
- data/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
- data/lib/ably/rest/presence.rb +1 -0
- data/lib/ably/rest/push.rb +42 -0
- data/lib/ably/rest/push/admin.rb +54 -0
- data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
- data/lib/ably/rest/push/device_registrations.rb +103 -0
- data/lib/ably/version.rb +7 -2
- data/spec/acceptance/realtime/auth_spec.rb +245 -17
- data/spec/acceptance/realtime/channel_history_spec.rb +26 -20
- data/spec/acceptance/realtime/channel_spec.rb +177 -59
- data/spec/acceptance/realtime/client_spec.rb +153 -0
- data/spec/acceptance/realtime/connection_failures_spec.rb +72 -6
- data/spec/acceptance/realtime/connection_spec.rb +129 -18
- data/spec/acceptance/realtime/message_spec.rb +36 -34
- data/spec/acceptance/realtime/presence_spec.rb +201 -167
- data/spec/acceptance/realtime/push_admin_spec.rb +736 -0
- data/spec/acceptance/realtime/push_spec.rb +27 -0
- data/spec/acceptance/rest/auth_spec.rb +41 -3
- data/spec/acceptance/rest/base_spec.rb +2 -2
- data/spec/acceptance/rest/channel_spec.rb +79 -4
- data/spec/acceptance/rest/channels_spec.rb +6 -0
- data/spec/acceptance/rest/client_spec.rb +129 -10
- data/spec/acceptance/rest/message_spec.rb +158 -6
- data/spec/acceptance/rest/push_admin_spec.rb +952 -0
- data/spec/acceptance/rest/push_spec.rb +25 -0
- data/spec/acceptance/rest/time_spec.rb +1 -1
- data/spec/run_parallel_tests +33 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/debug_failure_helper.rb +9 -5
- data/spec/support/test_app.rb +2 -2
- data/spec/unit/logger_spec.rb +10 -3
- data/spec/unit/models/device_details_spec.rb +102 -0
- data/spec/unit/models/device_push_details_spec.rb +101 -0
- data/spec/unit/models/error_info_spec.rb +51 -3
- data/spec/unit/models/message_spec.rb +17 -2
- data/spec/unit/models/presence_message_spec.rb +1 -1
- data/spec/unit/models/push_channel_subscription_spec.rb +86 -0
- data/spec/unit/modules/enum_spec.rb +1 -1
- data/spec/unit/realtime/client_spec.rb +13 -1
- data/spec/unit/realtime/connection_spec.rb +1 -1
- data/spec/unit/realtime/push_channel_spec.rb +36 -0
- data/spec/unit/rest/channel_spec.rb +8 -1
- data/spec/unit/rest/client_spec.rb +30 -0
- data/spec/unit/rest/push_channel_spec.rb +36 -0
- metadata +95 -26
data/ably.gemspec
CHANGED
@@ -21,32 +21,37 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_runtime_dependency 'eventmachine', '~> 1.2.6'
|
22
22
|
spec.add_runtime_dependency 'em-http-request', '~> 1.1'
|
23
23
|
spec.add_runtime_dependency 'statesman', '~> 1.0.0'
|
24
|
-
spec.add_runtime_dependency 'faraday', '
|
24
|
+
spec.add_runtime_dependency 'faraday', '>= 0.12', '< 2.0.0'
|
25
25
|
spec.add_runtime_dependency 'excon', '~> 0.55'
|
26
26
|
|
27
|
-
if RUBY_VERSION.match(/^1
|
27
|
+
if RUBY_VERSION.match(/^1\./)
|
28
28
|
spec.add_runtime_dependency 'json', '< 2.0'
|
29
29
|
else
|
30
30
|
spec.add_runtime_dependency 'json'
|
31
31
|
end
|
32
32
|
spec.add_runtime_dependency 'websocket-driver', '~> 0.7'
|
33
|
-
spec.add_runtime_dependency 'msgpack', '>=
|
33
|
+
spec.add_runtime_dependency 'msgpack', '>= 1.3.0'
|
34
34
|
spec.add_runtime_dependency 'addressable', '>= 2.0.0'
|
35
35
|
|
36
|
-
spec.add_development_dependency 'bundler', '~> 1.3'
|
37
36
|
spec.add_development_dependency 'rake', '~> 11.3'
|
38
37
|
spec.add_development_dependency 'redcarpet', '~> 3.3'
|
39
|
-
spec.add_development_dependency 'rspec', '~> 3.
|
40
|
-
spec.add_development_dependency 'rspec-retry', '~> 0.
|
38
|
+
spec.add_development_dependency 'rspec', '~> 3.3.0' # version lock, see config.around(:example, :event_machine) in event_machine_helper.rb
|
39
|
+
spec.add_development_dependency 'rspec-retry', '~> 0.6'
|
41
40
|
spec.add_development_dependency 'yard', '~> 0.9'
|
41
|
+
spec.add_development_dependency 'rspec-instafail', '~> 1.0'
|
42
|
+
spec.add_development_dependency 'bundler', '>= 1.3.0'
|
42
43
|
|
43
|
-
if RUBY_VERSION.match(/^1
|
44
|
+
if RUBY_VERSION.match(/^1\./)
|
44
45
|
spec.add_development_dependency 'public_suffix', '~> 1.4.6' # Later versions do not support Ruby 1.9
|
45
46
|
spec.add_development_dependency 'webmock', '2.2'
|
47
|
+
spec.add_development_dependency 'parallel_tests', '~> 2.9.0'
|
46
48
|
else
|
47
49
|
spec.add_development_dependency 'webmock', '~> 2.2'
|
48
50
|
spec.add_development_dependency 'coveralls'
|
49
|
-
spec.add_development_dependency '
|
50
|
-
|
51
|
+
spec.add_development_dependency 'parallel_tests', '~> 2.22'
|
52
|
+
if !RUBY_VERSION.match(/^2\.[0123]/)
|
53
|
+
spec.add_development_dependency 'pry'
|
54
|
+
spec.add_development_dependency 'pry-byebug'
|
55
|
+
end
|
51
56
|
end
|
52
57
|
end
|
data/lib/ably/auth.rb
CHANGED
@@ -35,6 +35,28 @@ module Ably
|
|
35
35
|
|
36
36
|
API_KEY_REGEX = /^[\w-]{2,}\.[\w-]{2,}:[\w-]{2,}$/
|
37
37
|
|
38
|
+
# Supported AuthOption keys, see https://www.ably.io/documentation/realtime/types#auth-options
|
39
|
+
# TODO: Review client_id usage embedded incorrectly within AuthOptions.
|
40
|
+
# This is legacy code to configure a client with a client_id from the ClientOptions
|
41
|
+
# TODO: Review inclusion of use_token_auth, ttl, token_params in auth options
|
42
|
+
AUTH_OPTIONS_KEYS = %w(
|
43
|
+
auth_callback
|
44
|
+
auth_url
|
45
|
+
auth_method
|
46
|
+
auth_headers
|
47
|
+
auth_params
|
48
|
+
client_id
|
49
|
+
key
|
50
|
+
key_name
|
51
|
+
key_secret
|
52
|
+
query_time
|
53
|
+
token
|
54
|
+
token_details
|
55
|
+
token_params
|
56
|
+
ttl
|
57
|
+
use_token_auth
|
58
|
+
)
|
59
|
+
|
38
60
|
attr_reader :options, :token_params, :current_token_details
|
39
61
|
alias_method :auth_options, :options
|
40
62
|
|
@@ -231,7 +253,7 @@ module Ably
|
|
231
253
|
auth_callback.call(token_params)
|
232
254
|
end
|
233
255
|
rescue StandardError => err
|
234
|
-
raise Ably::Exceptions::AuthenticationFailed.new("auth_callback failed: #{err.message}", nil, nil, err, fallback_status: 500, fallback_code:
|
256
|
+
raise Ably::Exceptions::AuthenticationFailed.new("auth_callback failed: #{err.message}", nil, nil, err, fallback_status: 500, fallback_code: Ably::Exceptions::Codes::CONNECTION_NOT_ESTABLISHED_NO_TRANSPORT_HANDLE)
|
235
257
|
end
|
236
258
|
elsif auth_url = auth_options.delete(:auth_url)
|
237
259
|
begin
|
@@ -239,7 +261,7 @@ module Ably
|
|
239
261
|
token_request_from_auth_url(auth_url, auth_options, token_params)
|
240
262
|
end
|
241
263
|
rescue StandardError => err
|
242
|
-
raise Ably::Exceptions::AuthenticationFailed.new("auth_url failed: #{err.message}", nil, nil, err, fallback_status: 500, fallback_code:
|
264
|
+
raise Ably::Exceptions::AuthenticationFailed.new("auth_url failed: #{err.message}", nil, nil, err, fallback_status: 500, fallback_code: Ably::Exceptions::Codes::CONNECTION_NOT_ESTABLISHED_NO_TRANSPORT_HANDLE)
|
243
265
|
end
|
244
266
|
else
|
245
267
|
create_token_request(token_params, auth_options)
|
@@ -504,6 +526,10 @@ module Ably
|
|
504
526
|
end
|
505
527
|
|
506
528
|
def ensure_valid_auth_attributes(attributes)
|
529
|
+
(attributes.keys.map(&:to_s) - AUTH_OPTIONS_KEYS).tap do |unsupported_keys|
|
530
|
+
raise ArgumentError, "The key(s) #{unsupported_keys.map { |k| ":#{k}" }.join(', ')} are not valid AuthOptions" unless unsupported_keys.empty?
|
531
|
+
end
|
532
|
+
|
507
533
|
if attributes[:timestamp]
|
508
534
|
unless attributes[:timestamp].kind_of?(Time) || attributes[:timestamp].kind_of?(Numeric)
|
509
535
|
raise ArgumentError, ':timestamp must be a Time or positive Integer value of seconds since epoch'
|
@@ -631,7 +657,7 @@ module Ably
|
|
631
657
|
uri = URI.parse(auth_url)
|
632
658
|
connection = Faraday.new("#{uri.scheme}://#{uri.host}", connection_options)
|
633
659
|
method = auth_options[:auth_method] || options[:auth_method] || :get
|
634
|
-
params = (auth_options[:auth_params] || options[:
|
660
|
+
params = (auth_options[:auth_params] || options[:auth_params] || {}).merge(token_params)
|
635
661
|
|
636
662
|
response = connection.public_send(method) do |request|
|
637
663
|
request.url uri.path
|
@@ -643,7 +669,7 @@ module Ably
|
|
643
669
|
end
|
644
670
|
end
|
645
671
|
|
646
|
-
if !response.body.kind_of?(Hash) && !response.headers['Content-Type'].to_s.match(%r{text/plain}i)
|
672
|
+
if !response.body.kind_of?(Hash) && !response.headers['Content-Type'].to_s.match(%r{text/plain|application/jwt}i)
|
647
673
|
raise Ably::Exceptions::InvalidResponseBody,
|
648
674
|
"Content Type #{response.headers['Content-Type']} is not supported by this client library"
|
649
675
|
end
|
data/lib/ably/exceptions.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
require 'ably/modules/exception_codes'
|
2
|
+
|
1
3
|
module Ably
|
2
4
|
module Exceptions
|
3
5
|
TOKEN_EXPIRED_CODE = 40140..40149
|
4
|
-
INVALID_CLIENT_ID = 40012
|
5
6
|
|
6
7
|
# Base Ably exception class that contains status and code values used by Ably
|
7
|
-
# Refer to https://github.com/ably/ably-common/blob/
|
8
|
+
# Refer to https://github.com/ably/ably-common/blob/main/protocol/errors.json
|
8
9
|
#
|
9
10
|
# @!attribute [r] message
|
10
11
|
# @return [String] Error message from Ably
|
@@ -37,6 +38,7 @@ module Ably
|
|
37
38
|
additional_info << "base exception: #{@base_exception.class}" if @base_exception
|
38
39
|
additional_info << "request_id: #{request_id}" if request_id
|
39
40
|
message << "(#{additional_info.join(', ')})"
|
41
|
+
message << "-> see https://help.ably.io/error/#{code} for help" if code
|
40
42
|
end
|
41
43
|
message.join(' ')
|
42
44
|
end
|
@@ -53,6 +55,8 @@ module Ably
|
|
53
55
|
# An invalid request was received by Ably
|
54
56
|
class InvalidRequest < BaseAblyException; end
|
55
57
|
|
58
|
+
class InvalidCredentials < BaseAblyException; end
|
59
|
+
|
56
60
|
# Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided
|
57
61
|
class UnauthorizedRequest < BaseAblyException; end
|
58
62
|
|
@@ -112,7 +116,7 @@ module Ably
|
|
112
116
|
class InvalidState < BaseAblyException; end
|
113
117
|
|
114
118
|
# A generic Ably exception taht supports a status & code.
|
115
|
-
# See https://github.com/ably/ably-common/blob/
|
119
|
+
# See https://github.com/ably/ably-common/blob/main/protocol/errors.json for a list of Ably errors
|
116
120
|
class Standard < BaseAblyException; end
|
117
121
|
|
118
122
|
# The HTTP request has returned a 500 error
|
@@ -146,12 +150,14 @@ module Ably
|
|
146
150
|
class ChannelInactive < BaseAblyException; end
|
147
151
|
|
148
152
|
class IncompatibleClientId < BaseAblyException
|
149
|
-
def initialize(messages, status = 400, code = INVALID_CLIENT_ID, *args)
|
153
|
+
def initialize(messages, status = 400, code = Ably::Exceptions::Codes::INVALID_CLIENT_ID, *args)
|
150
154
|
super(message, status, code, *args)
|
151
155
|
end
|
152
156
|
end
|
153
157
|
|
154
158
|
# Token request has missing or invalid attributes
|
155
159
|
class InvalidTokenRequest < BaseAblyException; end
|
160
|
+
|
161
|
+
class PushNotificationsNotSupported < BaseAblyException; end
|
156
162
|
end
|
157
163
|
end
|
data/lib/ably/logger.rb
CHANGED
@@ -20,6 +20,8 @@ module Ably
|
|
20
20
|
ensure_logger_interface_is_valid
|
21
21
|
|
22
22
|
@logger.level = log_level
|
23
|
+
|
24
|
+
@log_mutex = Mutex.new
|
23
25
|
end
|
24
26
|
|
25
27
|
# The logger used by this class, defaults to {http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html Ruby Logger}
|
@@ -38,7 +40,9 @@ module Ably
|
|
38
40
|
%w(fatal error warn info debug).each do |method_name|
|
39
41
|
define_method(method_name) do |*args, &block|
|
40
42
|
begin
|
41
|
-
|
43
|
+
log_mutex.synchronize do
|
44
|
+
logger.public_send(method_name, *args, &block)
|
45
|
+
end
|
42
46
|
rescue StandardError => e
|
43
47
|
logger.error "Logger: Failed to log #{method_name} block - #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
44
48
|
end
|
@@ -46,6 +50,8 @@ module Ably
|
|
46
50
|
end
|
47
51
|
|
48
52
|
private
|
53
|
+
attr_reader :log_mutex
|
54
|
+
|
49
55
|
def client
|
50
56
|
@client
|
51
57
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Ably::Modules
|
2
|
+
module Conversions
|
3
|
+
private
|
4
|
+
# Convert device_details argument to a {Ably::Models::DeviceDetails} object
|
5
|
+
#
|
6
|
+
# @param device_details [Ably::Models::DeviceDetails,Hash,nil] A device details object
|
7
|
+
#
|
8
|
+
# @return [Ably::Models::DeviceDetails]
|
9
|
+
def DeviceDetails(device_details)
|
10
|
+
case device_details
|
11
|
+
when Ably::Models::DeviceDetails
|
12
|
+
device_details
|
13
|
+
else
|
14
|
+
Ably::Models::DeviceDetails.new(device_details)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Ably::Models
|
21
|
+
# An object representing a devices details, used currently for push notifications
|
22
|
+
#
|
23
|
+
# @!attribute [r] id
|
24
|
+
# @return [String] Unique device identifier assigned randomly by the device
|
25
|
+
# @!attribute [r] platform
|
26
|
+
# @return [String] Device platform such as android, ios or browser
|
27
|
+
# @!attribute [r] form_factor
|
28
|
+
# @return [String] Device form factor such as phone, tablet, watch
|
29
|
+
# @!attribute [r] client_id
|
30
|
+
# @return [String] The authenticated client identifier for this device. See {https://www.ably.io/documentation/general/authentication#identified-clients auth documentation}.
|
31
|
+
# @!attribute [r] metadata
|
32
|
+
# @return [Hash] Arbitrary metadata that can be associated with a device
|
33
|
+
# @!attribute [r] device_secret
|
34
|
+
# @return [String] This secret is used internally by Ably client libraries to authenticate with Ably when push registration updates are required such as when the GCM token expires and needs renewing
|
35
|
+
# @!attribute [r] push
|
36
|
+
# @return [DevicePushDetails] The push notification specific properties for this device allowing push notifications to be delivered to the device
|
37
|
+
#
|
38
|
+
class DeviceDetails < Ably::Exceptions::BaseAblyException
|
39
|
+
include Ably::Modules::ModelCommon
|
40
|
+
|
41
|
+
# @param hash_object [Hash,nil] Device detail attributes
|
42
|
+
#a
|
43
|
+
def initialize(hash_object = {})
|
44
|
+
@raw_hash_object = hash_object || {}
|
45
|
+
@hash_object = IdiomaticRubyWrapper(hash_object)
|
46
|
+
end
|
47
|
+
|
48
|
+
%w(id platform form_factor client_id device_secret).each do |attribute|
|
49
|
+
define_method attribute do
|
50
|
+
attributes[attribute.to_sym]
|
51
|
+
end
|
52
|
+
|
53
|
+
define_method "#{attribute}=" do |val|
|
54
|
+
unless val.nil? || val.kind_of?(String)
|
55
|
+
raise ArgumentError, "#{attribute} must be nil or a string value"
|
56
|
+
end
|
57
|
+
attributes[attribute.to_sym] = val
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def metadata
|
62
|
+
attributes[:metadata] || {}
|
63
|
+
end
|
64
|
+
|
65
|
+
def metadata=(val)
|
66
|
+
unless val.nil? || val.kind_of?(Hash)
|
67
|
+
raise ArgumentError, "metadata must be nil or a Hash value"
|
68
|
+
end
|
69
|
+
attributes[:metadata] = val
|
70
|
+
end
|
71
|
+
|
72
|
+
def push
|
73
|
+
DevicePushDetails(attributes[:push] || {})
|
74
|
+
end
|
75
|
+
|
76
|
+
def push=(val)
|
77
|
+
unless val.nil? || val.kind_of?(Hash) || val.kind_of?(Ably::Models::DevicePushDetails)
|
78
|
+
raise ArgumentError, "push must be nil, a Hash value or a DevicePushDetails object"
|
79
|
+
end
|
80
|
+
attributes[:push] = DevicePushDetails(val)
|
81
|
+
end
|
82
|
+
|
83
|
+
def attributes
|
84
|
+
@hash_object
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Ably::Modules
|
2
|
+
module Conversions
|
3
|
+
private
|
4
|
+
# Convert device_push_details argument to a {Ably::Models::DevicePushDetails} object
|
5
|
+
#
|
6
|
+
# @param device_push_details [Ably::Models::DevicePushDetails,Hash,nil] A device push notification details object
|
7
|
+
#
|
8
|
+
# @return [Ably::Models::DevicePushDetails]
|
9
|
+
def DevicePushDetails(device_push_details)
|
10
|
+
case device_push_details
|
11
|
+
when Ably::Models::DevicePushDetails
|
12
|
+
device_push_details
|
13
|
+
else
|
14
|
+
Ably::Models::DevicePushDetails.new(device_push_details)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Ably::Models
|
21
|
+
# An object with the push notification details for {DeviceDetails} object
|
22
|
+
#
|
23
|
+
# @!attribute [r] transport_type
|
24
|
+
# @return [String] Transport type for push notifications such as gcm, apns, web
|
25
|
+
# @!attribute [r] state
|
26
|
+
# @return [String] The current state of this push target such as Active, Failing or Failed
|
27
|
+
# @!attribute [r] error_reason
|
28
|
+
# @return [ErrorInfo] If the state is Failing of Failed, this field may optionally contain a reason
|
29
|
+
# @!attribute [r] metadata
|
30
|
+
# @return [Hash] Arbitrary metadata that can be associated with this object
|
31
|
+
#
|
32
|
+
class DevicePushDetails < Ably::Exceptions::BaseAblyException
|
33
|
+
include Ably::Modules::ModelCommon
|
34
|
+
|
35
|
+
# @param hash_object [Hash,nil] Device push detail attributes
|
36
|
+
#a
|
37
|
+
def initialize(hash_object = {})
|
38
|
+
@raw_hash_object = hash_object || {}
|
39
|
+
@hash_object = IdiomaticRubyWrapper(@raw_hash_object)
|
40
|
+
end
|
41
|
+
|
42
|
+
%w(state).each do |attribute|
|
43
|
+
define_method attribute do
|
44
|
+
attributes[attribute.to_sym]
|
45
|
+
end
|
46
|
+
|
47
|
+
define_method "#{attribute}=" do |val|
|
48
|
+
unless val.nil? || val.kind_of?(String)
|
49
|
+
raise ArgumentError, "#{attribute} must be nil or a string value"
|
50
|
+
end
|
51
|
+
attributes[attribute.to_sym] = val
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def recipient
|
56
|
+
attributes[:recipient] || {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def recipient=(val)
|
60
|
+
unless val.nil? || val.kind_of?(Hash)
|
61
|
+
raise ArgumentError, "recipient must be nil or a Hash value"
|
62
|
+
end
|
63
|
+
attributes[:recipient] = val
|
64
|
+
end
|
65
|
+
|
66
|
+
def error_reason
|
67
|
+
attributes[:error_reason]
|
68
|
+
end
|
69
|
+
|
70
|
+
def error_reason=(val)
|
71
|
+
unless val.nil? || val.kind_of?(Hash) || val.kind_of?(Ably::Models::ErrorInfo)
|
72
|
+
raise ArgumentError, "error_reason must be nil, a Hash value or a ErrorInfo object"
|
73
|
+
end
|
74
|
+
|
75
|
+
attributes[:error_reason] = if val.nil?
|
76
|
+
nil
|
77
|
+
else
|
78
|
+
ErrorInfo(val)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def attributes
|
83
|
+
@hash_object
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -1,3 +1,22 @@
|
|
1
|
+
module Ably::Modules
|
2
|
+
module Conversions
|
3
|
+
private
|
4
|
+
# Convert error_details argument to a {ErrorInfo} object
|
5
|
+
#
|
6
|
+
# @param error_details [ErrorInfo,Hash] Error info attributes
|
7
|
+
#
|
8
|
+
# @return [ErrorInfo]
|
9
|
+
def ErrorInfo(error_details)
|
10
|
+
case error_details
|
11
|
+
when Ably::Models::ErrorInfo
|
12
|
+
error_details
|
13
|
+
else
|
14
|
+
Ably::Models::ErrorInfo.new(error_details)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
1
20
|
module Ably::Models
|
2
21
|
# An exception type encapsulating error information containing
|
3
22
|
# an Ably-specific error code and generic status code.
|
@@ -19,7 +38,7 @@ module Ably::Models
|
|
19
38
|
@hash_object = IdiomaticRubyWrapper(hash_object.clone.freeze)
|
20
39
|
end
|
21
40
|
|
22
|
-
%w(message code status_code).each do |attribute|
|
41
|
+
%w(message code href status_code).each do |attribute|
|
23
42
|
define_method attribute do
|
24
43
|
attributes[attribute.to_sym]
|
25
44
|
end
|
@@ -31,7 +50,9 @@ module Ably::Models
|
|
31
50
|
end
|
32
51
|
|
33
52
|
def to_s
|
34
|
-
|
53
|
+
error_href = href || (code ? "https://help.ably.io/error/#{code}" : '')
|
54
|
+
see_msg = " -> see #{error_href} for help" unless message.to_s.include?(error_href.to_s)
|
55
|
+
"<Error: #{message} (code: #{code}, http status: #{status})>#{see_msg}"
|
35
56
|
end
|
36
57
|
end
|
37
58
|
end
|
@@ -144,11 +144,11 @@ module Ably::Models
|
|
144
144
|
@attributes
|
145
145
|
end
|
146
146
|
|
147
|
-
# Takes the underlying Hash object and returns it in as a JSON ready Hash object using
|
147
|
+
# Takes the underlying Hash object and returns it in as a JSON ready Hash object using camelCase for compability with the Ably service.
|
148
148
|
# Note name clashes are ignored and will result in loss of one or more values
|
149
149
|
# @example
|
150
150
|
# wrapper = IdiomaticRubyWrapper({ 'mixedCase': true, mixed_case: false, 'snake_case': 1 })
|
151
|
-
# wrapper.as_json
|
151
|
+
# wrapper.as_json => { 'mixedCase': true, 'snakeCase': 1 }
|
152
152
|
def as_json(*args)
|
153
153
|
attributes.each_with_object({}) do |key_val, new_hash|
|
154
154
|
key = key_val[0]
|
@@ -161,7 +161,7 @@ module Ably::Models
|
|
161
161
|
end
|
162
162
|
|
163
163
|
# Converts the current wrapped mixedCase object to JSON
|
164
|
-
# using
|
164
|
+
# using snakedCase syntax as expected by the Realtime API
|
165
165
|
def to_json(*args)
|
166
166
|
as_json(args).to_json
|
167
167
|
end
|
@@ -170,7 +170,7 @@ module Ably::Models
|
|
170
170
|
# Note name clashes are ignored and will result in loss of one or more values
|
171
171
|
# @example
|
172
172
|
# wrapper = IdiomaticRubyWrapper({ 'mixedCase': true, mixed_case: false, 'snake_case': 1 })
|
173
|
-
# wrapper.to_hash
|
173
|
+
# wrapper.to_hash => { mixed_case: true, snake_case: 1 }
|
174
174
|
def to_hash(*args)
|
175
175
|
each_with_object({}) do |key_val, object|
|
176
176
|
key, val = key_val
|