ably 0.8.15 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +6 -4
- data/CHANGELOG.md +6 -2
- data/README.md +5 -1
- data/SPEC.md +1473 -852
- data/ably.gemspec +11 -8
- data/lib/ably/auth.rb +90 -53
- data/lib/ably/exceptions.rb +37 -8
- data/lib/ably/logger.rb +10 -1
- data/lib/ably/models/auth_details.rb +42 -0
- data/lib/ably/models/channel_state_change.rb +18 -4
- data/lib/ably/models/connection_details.rb +6 -3
- data/lib/ably/models/connection_state_change.rb +4 -3
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/message.rb +17 -1
- data/lib/ably/models/message_encoders/base.rb +103 -82
- data/lib/ably/models/message_encoders/base64.rb +1 -1
- data/lib/ably/models/presence_message.rb +16 -1
- data/lib/ably/models/protocol_message.rb +20 -3
- data/lib/ably/models/token_details.rb +11 -1
- data/lib/ably/models/token_request.rb +16 -6
- data/lib/ably/modules/async_wrapper.rb +7 -3
- data/lib/ably/modules/encodeable.rb +51 -12
- data/lib/ably/modules/enum.rb +17 -7
- data/lib/ably/modules/event_emitter.rb +29 -14
- data/lib/ably/modules/model_common.rb +13 -21
- data/lib/ably/modules/state_emitter.rb +7 -4
- data/lib/ably/modules/state_machine.rb +2 -4
- data/lib/ably/modules/uses_state_machine.rb +7 -3
- data/lib/ably/realtime.rb +2 -0
- data/lib/ably/realtime/auth.rb +102 -42
- data/lib/ably/realtime/channel.rb +68 -26
- data/lib/ably/realtime/channel/channel_manager.rb +154 -65
- data/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
- data/lib/ably/realtime/client.rb +18 -3
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
- data/lib/ably/realtime/connection.rb +108 -49
- data/lib/ably/realtime/connection/connection_manager.rb +167 -61
- data/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
- data/lib/ably/realtime/connection/websocket_transport.rb +19 -10
- data/lib/ably/realtime/presence.rb +70 -45
- data/lib/ably/realtime/presence/members_map.rb +201 -36
- data/lib/ably/realtime/presence/presence_manager.rb +30 -6
- data/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +5 -5
- data/lib/ably/rest/client.rb +31 -27
- data/lib/ably/rest/middleware/exceptions.rb +1 -3
- data/lib/ably/rest/middleware/logger.rb +2 -2
- data/lib/ably/rest/presence.rb +2 -2
- data/lib/ably/util/pub_sub.rb +1 -1
- data/lib/ably/util/safe_deferrable.rb +26 -0
- data/lib/ably/version.rb +2 -2
- data/spec/acceptance/realtime/auth_spec.rb +470 -111
- data/spec/acceptance/realtime/channel_history_spec.rb +5 -3
- data/spec/acceptance/realtime/channel_spec.rb +1017 -168
- data/spec/acceptance/realtime/client_spec.rb +6 -6
- data/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
- data/spec/acceptance/realtime/connection_spec.rb +424 -105
- data/spec/acceptance/realtime/message_spec.rb +52 -23
- data/spec/acceptance/realtime/presence_history_spec.rb +5 -3
- data/spec/acceptance/realtime/presence_spec.rb +1110 -96
- data/spec/acceptance/rest/auth_spec.rb +222 -59
- data/spec/acceptance/rest/base_spec.rb +1 -1
- data/spec/acceptance/rest/channel_spec.rb +1 -2
- data/spec/acceptance/rest/client_spec.rb +104 -48
- data/spec/acceptance/rest/message_spec.rb +42 -15
- data/spec/acceptance/rest/presence_spec.rb +4 -11
- data/spec/rspec_config.rb +2 -1
- data/spec/shared/client_initializer_behaviour.rb +2 -2
- data/spec/shared/safe_deferrable_behaviour.rb +6 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/support/debug_failure_helper.rb +20 -4
- data/spec/support/event_machine_helper.rb +32 -1
- data/spec/unit/auth_spec.rb +4 -11
- data/spec/unit/logger_spec.rb +28 -2
- data/spec/unit/models/auth_details_spec.rb +49 -0
- data/spec/unit/models/channel_state_change_spec.rb +23 -3
- data/spec/unit/models/connection_details_spec.rb +12 -1
- data/spec/unit/models/connection_state_change_spec.rb +15 -4
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -1
- data/spec/unit/models/message_spec.rb +153 -0
- data/spec/unit/models/presence_message_spec.rb +192 -0
- data/spec/unit/models/protocol_message_spec.rb +64 -6
- data/spec/unit/models/token_details_spec.rb +75 -0
- data/spec/unit/models/token_request_spec.rb +74 -0
- data/spec/unit/modules/async_wrapper_spec.rb +2 -1
- data/spec/unit/modules/enum_spec.rb +69 -0
- data/spec/unit/modules/event_emitter_spec.rb +149 -22
- data/spec/unit/modules/state_emitter_spec.rb +9 -3
- data/spec/unit/realtime/client_spec.rb +1 -1
- data/spec/unit/realtime/connection_spec.rb +8 -5
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
- data/spec/unit/realtime/presence_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +1 -1
- data/spec/unit/util/crypto_spec.rb +3 -3
- metadata +22 -19
@@ -8,6 +8,8 @@ module Ably::Models
|
|
8
8
|
#
|
9
9
|
# @!attribute [r] action
|
10
10
|
# @return [ACTION] Protocol Message action {Ably::Modules::Enum} from list of {ACTION}. Returns nil if action is unsupported by protocol
|
11
|
+
# @!attribute [r] auth
|
12
|
+
# @return [Ably::Models::AuthDetails] Authentication details used to perform authentication upgrades over an existing transport
|
11
13
|
# @!attribute [r] count
|
12
14
|
# @return [Integer] The count field is used for ACK and NACK actions. See {http://docs.ably.io/client-lib-development-guide/protocol/#message-acknowledgement message acknowledgement protocol}
|
13
15
|
# @!attribute [r] error
|
@@ -15,7 +17,7 @@ module Ably::Models
|
|
15
17
|
# @!attribute [r] channel
|
16
18
|
# @return [String] Channel name for messages
|
17
19
|
# @!attribute [r] channel_serial
|
18
|
-
# @return [String] Contains a serial number for a message on the current
|
20
|
+
# @return [String] Contains a serial number for a message on the current channel
|
19
21
|
# @!attribute [r] connection_id
|
20
22
|
# @return [String] Contains a string public identifier for the connection
|
21
23
|
# @!attribute [r] connection_key
|
@@ -62,13 +64,14 @@ module Ably::Models
|
|
62
64
|
detached: 13,
|
63
65
|
presence: 14,
|
64
66
|
message: 15,
|
65
|
-
sync: 16
|
67
|
+
sync: 16,
|
68
|
+
auth: 17
|
66
69
|
)
|
67
70
|
|
68
71
|
# Indicates this protocol message action will generate an ACK response such as :message or :presence
|
69
72
|
# @api private
|
70
73
|
def self.ack_required?(for_action)
|
71
|
-
|
74
|
+
ACTION(for_action).match_any?(ACTION.Presence, ACTION.Message)
|
72
75
|
end
|
73
76
|
|
74
77
|
# {ProtocolMessage} initializer
|
@@ -193,10 +196,24 @@ module Ably::Models
|
|
193
196
|
flags & 1 == 1
|
194
197
|
end
|
195
198
|
|
199
|
+
# @api private
|
200
|
+
def has_backlog_flag?
|
201
|
+
flags & 2 == 2
|
202
|
+
end
|
203
|
+
|
204
|
+
# @api private
|
205
|
+
def has_channel_resumed_flag?
|
206
|
+
flags & 4 == 4
|
207
|
+
end
|
208
|
+
|
196
209
|
def connection_details
|
197
210
|
@connection_details ||= Ably::Models::ConnectionDetails(attributes[:connection_details])
|
198
211
|
end
|
199
212
|
|
213
|
+
def auth
|
214
|
+
@auth ||= Ably::Models::AuthDetails(attributes[:auth])
|
215
|
+
end
|
216
|
+
|
200
217
|
# Indicates this protocol message will generate an ACK response when sent
|
201
218
|
# Examples of protocol messages required ACK include :message and :presence
|
202
219
|
# @api private
|
@@ -73,7 +73,17 @@ module Ably::Models
|
|
73
73
|
# @!attribute [r] capability
|
74
74
|
# @return [Hash] Capabilities assigned to this token
|
75
75
|
def capability
|
76
|
-
|
76
|
+
if attributes.has_key?(:capability)
|
77
|
+
capability_val = attributes.fetch(:capability)
|
78
|
+
case capability_val
|
79
|
+
when Hash
|
80
|
+
capability_val
|
81
|
+
when Ably::Models::IdiomaticRubyWrapper
|
82
|
+
capability_val.as_json
|
83
|
+
else
|
84
|
+
JSON.parse(attributes.fetch(:capability))
|
85
|
+
end
|
86
|
+
end
|
77
87
|
end
|
78
88
|
|
79
89
|
# @!attribute [r] client_id
|
@@ -42,7 +42,7 @@ module Ably::Models
|
|
42
42
|
# @!attribute [r] key_name
|
43
43
|
# @return [String] API key name of the key against which this request is made. An API key is made up of an API key name and secret delimited by a +:+
|
44
44
|
def key_name
|
45
|
-
attributes.fetch(:key_name)
|
45
|
+
attributes.fetch(:key_name) { raise Ably::Exceptions::InvalidTokenRequest, 'Key name is missing' }
|
46
46
|
end
|
47
47
|
|
48
48
|
# @!attribute [r] ttl
|
@@ -59,7 +59,16 @@ module Ably::Models
|
|
59
59
|
# the capability of the returned token will be the intersection of
|
60
60
|
# this capability with the capability of the issuing key.
|
61
61
|
def capability
|
62
|
-
|
62
|
+
capability_val = attributes.fetch(:capability) { raise Ably::Exceptions::InvalidTokenRequest, 'Capability is missing' }
|
63
|
+
|
64
|
+
case capability_val
|
65
|
+
when Hash
|
66
|
+
capability_val
|
67
|
+
when Ably::Models::IdiomaticRubyWrapper
|
68
|
+
capability_val.as_json
|
69
|
+
else
|
70
|
+
JSON.parse(attributes.fetch(:capability))
|
71
|
+
end
|
63
72
|
end
|
64
73
|
|
65
74
|
# @!attribute [r] client_id
|
@@ -75,7 +84,8 @@ module Ably::Models
|
|
75
84
|
# token requests from being replayed.
|
76
85
|
# Timestamp when sent to Ably is in milliseconds.
|
77
86
|
def timestamp
|
78
|
-
|
87
|
+
timestamp_val = attributes.fetch(:timestamp) { raise Ably::Exceptions::InvalidTokenRequest, 'Timestamp is missing' }
|
88
|
+
as_time_from_epoch(timestamp_val, granularity: :ms)
|
79
89
|
end
|
80
90
|
|
81
91
|
# @!attribute [r] nonce
|
@@ -83,21 +93,21 @@ module Ably::Models
|
|
83
93
|
# uniqueness of this request. Any subsequent request using the
|
84
94
|
# same nonce will be rejected.
|
85
95
|
def nonce
|
86
|
-
attributes.fetch(:nonce)
|
96
|
+
attributes.fetch(:nonce) { raise Ably::Exceptions::InvalidTokenRequest, 'Nonce is missing' }
|
87
97
|
end
|
88
98
|
|
89
99
|
# @!attribute [r] mac
|
90
100
|
# @return [String] the Message Authentication Code for this request. See the
|
91
101
|
# {https://www.ably.io/documentation Ably Authentication documentation} for more details.
|
92
102
|
def mac
|
93
|
-
attributes.fetch(:mac)
|
103
|
+
attributes.fetch(:mac) { raise Ably::Exceptions::InvalidTokenRequest, 'MAC is missing' }
|
94
104
|
end
|
95
105
|
|
96
106
|
# Requests that the token is always persisted
|
97
107
|
# @api private
|
98
108
|
#
|
99
109
|
def persisted
|
100
|
-
attributes
|
110
|
+
attributes[:persisted]
|
101
111
|
end
|
102
112
|
|
103
113
|
# @!attribute [r] attributes
|
@@ -38,7 +38,7 @@ module Ably::Modules
|
|
38
38
|
# @yield [Object] operation block that is run in a thread
|
39
39
|
# @return [Ably::Util::SafeDeferrable]
|
40
40
|
#
|
41
|
-
def async_wrap(success_callback = nil)
|
41
|
+
def async_wrap(success_callback = nil, custom_error_handling = nil)
|
42
42
|
raise ArgumentError, 'Block required' unless block_given?
|
43
43
|
|
44
44
|
Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
|
@@ -48,8 +48,12 @@ module Ably::Modules
|
|
48
48
|
begin
|
49
49
|
yield
|
50
50
|
rescue StandardError => err
|
51
|
-
|
52
|
-
|
51
|
+
if custom_error_handling
|
52
|
+
custom_error_handling.call err, deferrable
|
53
|
+
else
|
54
|
+
logger.error { "An exception in an AsyncWrapper block was caught. #{err.class}: #{err.message}\n#{err.backtrace.join("\n")}" }
|
55
|
+
deferrable.fail err
|
56
|
+
end
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
@@ -10,20 +10,60 @@ module Ably::Modules
|
|
10
10
|
# - A #raw_hash_object attribute that returns the original hash object used to create this object
|
11
11
|
#
|
12
12
|
module Encodeable
|
13
|
+
def self.included(base)
|
14
|
+
base.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
# Return a Message or Presence object from the encoded JSON-like object, using the optional channel options
|
19
|
+
# @param message_object [Hash] JSON-like object representation of an encoded message
|
20
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
21
|
+
# @yield [Ably::Exceptions::BaseAblyException] yields an Ably exception if decoding fails
|
22
|
+
# @return [Message,Presence]
|
23
|
+
def from_encoded(message_object, channel_options = {}, &error_block)
|
24
|
+
new(message_object).tap do |message|
|
25
|
+
message.decode(encoders, channel_options, &error_block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return an Array of Message or Presence objects from the encoded Array of JSON-like objects, using the optional channel options
|
30
|
+
# @param message_objects [Array<Hash>] Array of JSON-like objects with encoded messages
|
31
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
32
|
+
# @return [Array<Message,Presence>]
|
33
|
+
def from_encoded_array(message_object_array, channel_options = {})
|
34
|
+
Array(message_object_array).map do |message_object|
|
35
|
+
from_encoded(message_object, channel_options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Register an encoder for this object
|
40
|
+
# @api private
|
41
|
+
def register_encoder(encoder, options = {})
|
42
|
+
encoders << Ably::Models::MessageEncoders.encoder_from(encoder, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def encoders
|
47
|
+
@encoders ||= []
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
13
51
|
# Encode a message using the channel options and register encoders for the client
|
14
|
-
# @param
|
52
|
+
# @param encoders [Array<Ably::Models::MessageEncoders::Base>] List of encoders to apply to the message
|
53
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
15
54
|
# @return [void]
|
16
55
|
# @api private
|
17
|
-
def encode(
|
18
|
-
apply_encoders :encode,
|
56
|
+
def encode(encoders, channel_options, &error_block)
|
57
|
+
apply_encoders :encode, encoders, channel_options, &error_block
|
19
58
|
end
|
20
59
|
|
21
60
|
# Decode a message using the channel options and registered encoders for the client
|
22
|
-
# @param
|
61
|
+
# @param encoders [Array<Ably::Models::MessageEncoders::Base>] List of encoders to apply to the message
|
62
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
23
63
|
# @return [void]
|
24
64
|
# @api private
|
25
|
-
def decode(
|
26
|
-
apply_encoders :decode,
|
65
|
+
def decode(encoders, channel_options, &error_block)
|
66
|
+
apply_encoders :decode, encoders, channel_options, &error_block
|
27
67
|
end
|
28
68
|
|
29
69
|
# The original encoding of this message when it was received as a raw message from the Ably service
|
@@ -44,7 +84,7 @@ module Ably::Modules
|
|
44
84
|
end
|
45
85
|
end
|
46
86
|
|
47
|
-
def apply_encoders(method,
|
87
|
+
def apply_encoders(method, encoders, channel_options, &error_callback)
|
48
88
|
max_encoding_length = 512
|
49
89
|
message_attributes = attributes.dup
|
50
90
|
|
@@ -54,16 +94,15 @@ module Ably::Modules
|
|
54
94
|
end
|
55
95
|
|
56
96
|
previous_encoding = message_attributes[:encoding]
|
57
|
-
|
58
|
-
encoder.send method, message_attributes,
|
97
|
+
encoders.each do |encoder|
|
98
|
+
encoder.send method, message_attributes, channel_options
|
59
99
|
end
|
60
100
|
end until previous_encoding == message_attributes[:encoding]
|
61
101
|
|
62
102
|
set_attributes_object message_attributes
|
63
103
|
rescue Ably::Exceptions::CipherError => cipher_error
|
64
|
-
if
|
65
|
-
|
66
|
-
channel.emit :error, cipher_error
|
104
|
+
if block_given?
|
105
|
+
yield cipher_error, "Encoder error #{cipher_error.code} trying to #{method} message: #{cipher_error.message}"
|
67
106
|
else
|
68
107
|
raise cipher_error
|
69
108
|
end
|
data/lib/ably/modules/enum.rb
CHANGED
@@ -49,11 +49,11 @@ module Ably::Modules
|
|
49
49
|
def get(identifier)
|
50
50
|
case identifier
|
51
51
|
when Symbol
|
52
|
-
by_symbol.fetch(identifier)
|
52
|
+
by_symbol.fetch(identifier) { raise KeyError, "#{name} key not found: :#{identifier}" }
|
53
53
|
when String
|
54
|
-
by_symbol.fetch(convert_to_snake_case_symbol(identifier))
|
54
|
+
by_symbol.fetch(convert_to_snake_case_symbol(identifier)) { raise KeyError, "#{name} key not found: '#{identifier}'" }
|
55
55
|
when Numeric
|
56
|
-
by_index.fetch(identifier)
|
56
|
+
by_index.fetch(identifier) { raise KeyError, "#{name} key not found: #{identifier}" }
|
57
57
|
when ancestors.first
|
58
58
|
identifier
|
59
59
|
else
|
@@ -89,6 +89,12 @@ module Ably::Modules
|
|
89
89
|
@enum_name
|
90
90
|
end
|
91
91
|
|
92
|
+
# Array of Enum values as symbols
|
93
|
+
# @return [Array<Symbol>]
|
94
|
+
def to_sym_arr
|
95
|
+
@by_symbol.keys
|
96
|
+
end
|
97
|
+
|
92
98
|
private
|
93
99
|
def by_index
|
94
100
|
@by_index
|
@@ -158,7 +164,7 @@ module Ably::Modules
|
|
158
164
|
|
159
165
|
# Allow comparison of Enum objects based on:
|
160
166
|
#
|
161
|
-
# * Other equivalent Enum objects
|
167
|
+
# * Other equivalent Enum objects compared by Symbol (not Integer value)
|
162
168
|
# * Symbol
|
163
169
|
# * String
|
164
170
|
# * Integer index of Enum
|
@@ -171,13 +177,17 @@ module Ably::Modules
|
|
171
177
|
self.to_sym == convert_to_snake_case_symbol(other)
|
172
178
|
when Numeric
|
173
179
|
self.to_i == other.to_i
|
174
|
-
when self.class
|
175
|
-
self.to_i == other.to_i
|
176
180
|
else
|
177
|
-
|
181
|
+
if other.kind_of?(Ably::Modules::Enum::Base)
|
182
|
+
self.to_sym == other.to_sym
|
183
|
+
end
|
178
184
|
end
|
179
185
|
end
|
180
186
|
|
187
|
+
def match_any?(*enums)
|
188
|
+
enums.any? { |enum| self.==(enum) }
|
189
|
+
end
|
190
|
+
|
181
191
|
private
|
182
192
|
def name
|
183
193
|
@name
|
@@ -54,7 +54,7 @@ module Ably
|
|
54
54
|
end
|
55
55
|
|
56
56
|
# Equivalent of {#on} but any exception raised in a block will bubble up and cause this client library to fail.
|
57
|
-
# This method
|
57
|
+
# This method is designed to be used internally by the client library.
|
58
58
|
# @api private
|
59
59
|
def unsafe_on(*event_names, &block)
|
60
60
|
add_callback event_names, proc_for_block(block, unsafe: true)
|
@@ -70,7 +70,7 @@ module Ably
|
|
70
70
|
end
|
71
71
|
|
72
72
|
# Equivalent of {#once} but any exception raised in a block will bubble up and cause this client library to fail.
|
73
|
-
# This method
|
73
|
+
# This method is designed to be used internally by the client library.
|
74
74
|
# @api private
|
75
75
|
def unsafe_once(*event_names, &block)
|
76
76
|
add_callback event_names, proc_for_block(block, delete_once_run: true, unsafe: true)
|
@@ -101,30 +101,45 @@ module Ably
|
|
101
101
|
#
|
102
102
|
# @return [void]
|
103
103
|
def off(*event_names, &block)
|
104
|
+
off_internal(false, *event_names, &block)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Equivalent of {#off} but only unsafe listeners are removed.
|
108
|
+
# This method is designed to be used internally by the client library.
|
109
|
+
# @api private
|
110
|
+
def unsafe_off(*event_names, &block)
|
111
|
+
off_internal(true, *event_names, &block)
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def off_internal(unsafe, *event_names, &block)
|
104
116
|
keys = if event_names.empty?
|
105
117
|
callbacks.keys
|
106
118
|
else
|
107
119
|
event_names
|
108
120
|
end
|
109
121
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
122
|
+
if event_names.empty?
|
123
|
+
callbacks_any.delete_if do |proc_hash|
|
124
|
+
if block_given?
|
125
|
+
(proc_hash[:unsafe] == unsafe) && (proc_hash[:block] == block)
|
126
|
+
else
|
127
|
+
proc_hash[:unsafe] == unsafe
|
128
|
+
end
|
115
129
|
end
|
116
130
|
end
|
117
131
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
132
|
+
keys.each do |event_name|
|
133
|
+
callbacks[callbacks_event_coerced(event_name)].delete_if do |proc_hash|
|
134
|
+
if block_given?
|
135
|
+
(proc_hash[:unsafe] == unsafe) && (proc_hash[:block] == block)
|
136
|
+
else
|
137
|
+
proc_hash[:unsafe] == unsafe
|
138
|
+
end
|
123
139
|
end
|
124
140
|
end
|
125
141
|
end
|
126
142
|
|
127
|
-
private
|
128
143
|
def self.included(klass)
|
129
144
|
klass.extend ClassMethods
|
130
145
|
end
|
@@ -148,7 +163,7 @@ module Ably
|
|
148
163
|
true if options[:delete_once_run]
|
149
164
|
end,
|
150
165
|
block: block,
|
151
|
-
unsafe: options[:unsafe]
|
166
|
+
unsafe: options[:unsafe] || false
|
152
167
|
}
|
153
168
|
end
|
154
169
|
|
@@ -8,6 +8,10 @@ module Ably::Modules
|
|
8
8
|
include Conversions
|
9
9
|
include MessagePack
|
10
10
|
|
11
|
+
def self.included(base)
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
|
11
15
|
# Provide a normal Hash accessor to the underlying raw message object
|
12
16
|
#
|
13
17
|
# @return [Object]
|
@@ -32,38 +36,26 @@ module Ably::Modules
|
|
32
36
|
as_json.to_json(*args)
|
33
37
|
end
|
34
38
|
|
35
|
-
# Like to_json but encodes all binary fields to hex
|
36
|
-
def to_safe_json(*args)
|
37
|
-
as_json.
|
38
|
-
each_with_object({}) do |(key, val), obj|
|
39
|
-
obj[key] = to_safe_jsonable_val(val)
|
40
|
-
end.to_json(*args)
|
41
|
-
end
|
42
|
-
|
43
39
|
# @!attribute [r] hash
|
44
40
|
# @return [Integer] Compute a hash-code for this hash. Two hashes with the same content will have the same hash code
|
45
41
|
def hash
|
46
42
|
attributes.hash
|
47
43
|
end
|
48
44
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
when String
|
57
|
-
if val.encoding == Encoding::ASCII_8BIT
|
58
|
-
val.unpack("H*").first
|
45
|
+
module ClassMethods
|
46
|
+
# Return a new instance of this object using the provided JSON-like object or JSON string
|
47
|
+
# @param [Hash, String] JSON-like object or JSON string
|
48
|
+
# @return a new instance o this object
|
49
|
+
def from_json(json_like_object)
|
50
|
+
if json_like_object.kind_of?(String)
|
51
|
+
new(JSON.parse(json_like_object))
|
59
52
|
else
|
60
|
-
|
53
|
+
new(json_like_object)
|
61
54
|
end
|
62
|
-
else
|
63
|
-
val
|
64
55
|
end
|
65
56
|
end
|
66
57
|
|
58
|
+
private
|
67
59
|
def ensure_utf8_string_for(attribute, value)
|
68
60
|
if value
|
69
61
|
raise ArgumentError, "#{attribute} must be a String" unless value.kind_of?(String)
|