ably 0.6.2 → 0.7.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/.rspec +1 -0
- data/.ruby-version.old +1 -0
- data/.travis.yml +0 -2
- data/Rakefile +22 -4
- data/SPEC.md +1676 -0
- data/ably.gemspec +1 -1
- data/lib/ably.rb +0 -8
- data/lib/ably/auth.rb +54 -46
- data/lib/ably/exceptions.rb +19 -5
- data/lib/ably/logger.rb +1 -1
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +11 -9
- data/lib/ably/models/message.rb +15 -12
- data/lib/ably/models/message_encoders/base.rb +6 -5
- data/lib/ably/models/message_encoders/base64.rb +1 -0
- data/lib/ably/models/message_encoders/cipher.rb +6 -3
- data/lib/ably/models/message_encoders/json.rb +1 -0
- data/lib/ably/models/message_encoders/utf8.rb +2 -9
- data/lib/ably/models/nil_logger.rb +20 -0
- data/lib/ably/models/paginated_resource.rb +5 -2
- data/lib/ably/models/presence_message.rb +21 -12
- data/lib/ably/models/protocol_message.rb +22 -6
- data/lib/ably/modules/ably.rb +11 -0
- data/lib/ably/modules/async_wrapper.rb +2 -0
- data/lib/ably/modules/conversions.rb +23 -3
- data/lib/ably/modules/encodeable.rb +2 -1
- data/lib/ably/modules/enum.rb +2 -0
- data/lib/ably/modules/event_emitter.rb +7 -1
- data/lib/ably/modules/event_machine_helpers.rb +2 -0
- data/lib/ably/modules/http_helpers.rb +2 -0
- data/lib/ably/modules/model_common.rb +12 -2
- data/lib/ably/modules/state_emitter.rb +76 -0
- data/lib/ably/modules/state_machine.rb +53 -0
- data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/ably/realtime.rb +4 -2
- data/lib/ably/realtime/channel.rb +51 -58
- data/lib/ably/realtime/channel/channel_manager.rb +91 -0
- data/lib/ably/realtime/channel/channel_state_machine.rb +68 -0
- data/lib/ably/realtime/client.rb +70 -26
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +31 -13
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/ably/realtime/connection.rb +135 -92
- data/lib/ably/realtime/connection/connection_manager.rb +216 -33
- data/lib/ably/realtime/connection/connection_state_machine.rb +30 -73
- data/lib/ably/realtime/models/nil_channel.rb +10 -1
- data/lib/ably/realtime/presence.rb +336 -92
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +13 -4
- data/lib/ably/rest/client.rb +138 -38
- data/lib/ably/rest/middleware/logger.rb +24 -3
- data/lib/ably/rest/presence.rb +12 -7
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +101 -85
- data/spec/acceptance/realtime/channel_spec.rb +461 -120
- data/spec/acceptance/realtime/client_spec.rb +119 -0
- data/spec/acceptance/realtime/connection_failures_spec.rb +499 -0
- data/spec/acceptance/realtime/connection_spec.rb +571 -97
- data/spec/acceptance/realtime/message_spec.rb +347 -333
- data/spec/acceptance/realtime/presence_history_spec.rb +35 -40
- data/spec/acceptance/realtime/presence_spec.rb +769 -239
- data/spec/acceptance/realtime/stats_spec.rb +14 -22
- data/spec/acceptance/realtime/time_spec.rb +16 -20
- data/spec/acceptance/rest/auth_spec.rb +425 -364
- data/spec/acceptance/rest/base_spec.rb +108 -176
- data/spec/acceptance/rest/channel_spec.rb +89 -89
- data/spec/acceptance/rest/channels_spec.rb +30 -32
- data/spec/acceptance/rest/client_spec.rb +273 -0
- data/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/spec/acceptance/rest/message_spec.rb +186 -163
- data/spec/acceptance/rest/presence_spec.rb +150 -111
- data/spec/acceptance/rest/stats_spec.rb +45 -40
- data/spec/acceptance/rest/time_spec.rb +8 -10
- data/spec/rspec_config.rb +10 -1
- data/spec/shared/client_initializer_behaviour.rb +212 -0
- data/spec/{support/model_helper.rb → shared/model_behaviour.rb} +6 -6
- data/spec/{support/protocol_msgbus_helper.rb → shared/protocol_msgbus_behaviour.rb} +1 -1
- data/spec/spec_helper.rb +9 -0
- data/spec/support/api_helper.rb +11 -0
- data/spec/support/event_machine_helper.rb +101 -3
- data/spec/support/markdown_spec_formatter.rb +90 -0
- data/spec/support/private_api_formatter.rb +36 -0
- data/spec/support/protocol_helper.rb +32 -0
- data/spec/support/random_helper.rb +15 -0
- data/spec/support/test_app.rb +4 -0
- data/spec/unit/auth_spec.rb +68 -0
- data/spec/unit/logger_spec.rb +77 -66
- data/spec/unit/models/error_info_spec.rb +1 -1
- data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +2 -3
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -2
- data/spec/unit/models/message_encoders/cipher_spec.rb +2 -2
- data/spec/unit/models/message_encoders/utf8_spec.rb +2 -46
- data/spec/unit/models/message_spec.rb +160 -15
- data/spec/unit/models/paginated_resource_spec.rb +29 -27
- data/spec/unit/models/presence_message_spec.rb +163 -20
- data/spec/unit/models/protocol_message_spec.rb +43 -8
- data/spec/unit/modules/async_wrapper_spec.rb +2 -3
- data/spec/unit/modules/conversions_spec.rb +1 -1
- data/spec/unit/modules/enum_spec.rb +2 -3
- data/spec/unit/modules/event_emitter_spec.rb +62 -5
- data/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/spec/unit/realtime/channel_spec.rb +107 -2
- data/spec/unit/realtime/channels_spec.rb +1 -0
- data/spec/unit/realtime/client_spec.rb +8 -48
- data/spec/unit/realtime/connection_spec.rb +3 -3
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +2 -2
- data/spec/unit/realtime/presence_spec.rb +13 -4
- data/spec/unit/realtime/realtime_spec.rb +0 -11
- data/spec/unit/realtime/websocket_transport_spec.rb +2 -2
- data/spec/unit/rest/channel_spec.rb +109 -0
- data/spec/unit/rest/channels_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +30 -125
- data/spec/unit/rest/rest_spec.rb +10 -0
- data/spec/unit/util/crypto_spec.rb +10 -5
- data/spec/unit/util/pub_sub_spec.rb +5 -5
- metadata +44 -12
- data/spec/integration/modules/state_emitter_spec.rb +0 -80
- data/spec/integration/rest/auth.rb +0 -9
data/ably.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
29
29
|
spec.add_development_dependency 'rake'
|
30
30
|
spec.add_development_dependency 'redcarpet'
|
31
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
31
|
+
spec.add_development_dependency 'rspec', '~> 3.1.0' # version lock, see event_machine_helper.rb#patch_example_block_with_surrounding_eventmachine_reactor
|
32
32
|
spec.add_development_dependency 'yard'
|
33
33
|
spec.add_development_dependency 'webmock'
|
34
34
|
end
|
data/lib/ably.rb
CHANGED
@@ -10,11 +10,3 @@ require 'ably/logger'
|
|
10
10
|
require 'ably/realtime'
|
11
11
|
require 'ably/rest'
|
12
12
|
require 'ably/version'
|
13
|
-
|
14
|
-
# Ably is the base namespace for the Ably {Ably::Realtime Realtime} & {Ably::Rest Rest} client libraries.
|
15
|
-
#
|
16
|
-
# Please refer to the {file:README.md Readme} on getting started.
|
17
|
-
#
|
18
|
-
# @see file:README.md README
|
19
|
-
module Ably
|
20
|
-
end
|
data/lib/ably/auth.rb
CHANGED
@@ -34,14 +34,15 @@ module Ably
|
|
34
34
|
# Creates an Auth object
|
35
35
|
#
|
36
36
|
# @param [Ably::Rest::Client] client {Ably::Rest::Client} this Auth object uses
|
37
|
-
# @param
|
38
|
-
# @
|
39
|
-
|
40
|
-
|
37
|
+
# @param options (see Ably::Rest::Client#initialize)
|
38
|
+
# @option (see Ably::Rest::Client#initialize)
|
39
|
+
# @yield (see Ably::Rest::Client#initialize)
|
40
|
+
def initialize(client, options, &token_request_block)
|
41
|
+
auth_options = options.dup
|
41
42
|
|
42
|
-
@client
|
43
|
-
@options
|
44
|
-
@
|
43
|
+
@client = client
|
44
|
+
@options = auth_options
|
45
|
+
@default_token_block = token_request_block if block_given?
|
45
46
|
|
46
47
|
unless auth_options.kind_of?(Hash)
|
47
48
|
raise ArgumentError, 'Expected auth_options to be a Hash'
|
@@ -54,16 +55,17 @@ module Ably
|
|
54
55
|
if auth_options[:api_key]
|
55
56
|
api_key_parts = auth_options[:api_key].to_s.match(/(?<id>[\w_-]+\.[\w_-]+):(?<secret>[\w_-]+)/)
|
56
57
|
raise ArgumentError, 'api_key is invalid' unless api_key_parts
|
57
|
-
auth_options[:key_id] = api_key_parts[:id]
|
58
|
-
auth_options[:key_secret] = api_key_parts[:secret]
|
58
|
+
auth_options[:key_id] = api_key_parts[:id].encode(Encoding::UTF_8)
|
59
|
+
auth_options[:key_secret] = api_key_parts[:secret].encode(Encoding::UTF_8)
|
59
60
|
end
|
60
61
|
|
61
62
|
if using_basic_auth? && !api_key_present?
|
62
63
|
raise ArgumentError, 'api_key is missing. Either an API key, token, or token auth method must be provided'
|
63
64
|
end
|
64
65
|
|
65
|
-
if has_client_id?
|
66
|
-
raise ArgumentError, 'client_id cannot be provided without a complete API key. Key ID & Secret is needed to authenticate with Ably and obtain a token'
|
66
|
+
if has_client_id?
|
67
|
+
raise ArgumentError, 'client_id cannot be provided without a complete API key. Key ID & Secret is needed to authenticate with Ably and obtain a token' unless api_key_present?
|
68
|
+
ensure_utf_8 :client_id, client_id
|
67
69
|
end
|
68
70
|
|
69
71
|
@options.freeze
|
@@ -74,25 +76,14 @@ module Ably
|
|
74
76
|
# In the event that a new token request is made, the specified options are used.
|
75
77
|
#
|
76
78
|
# @param [Hash] options the options for the token request
|
77
|
-
# @option options
|
78
|
-
# @option options [
|
79
|
-
# @option options [String] :client_id client ID identifying this connection to other clients (defaults to client client_id if configured)
|
80
|
-
# @option options [String] :auth_url a URL to be used to GET or POST a set of token request params, to obtain a signed token request.
|
81
|
-
# @option options [Hash] :auth_headers a set of application-specific headers to be added to any request made to the authUrl
|
82
|
-
# @option options [Hash] :auth_params a set of application-specific query params to be added to any request made to the authUrl
|
83
|
-
# @option options [Symbol] :auth_method HTTP method to use with auth_url, must be either `:get` or `:post` (defaults to :get)
|
84
|
-
# @option options [Integer] :ttl validity time in seconds for the requested {Ably::Models::Token}. Limits may apply, see {http://docs.ably.io/other/authentication/}
|
85
|
-
# @option options [Hash] :capability canonicalised representation of the resource paths and associated operations
|
86
|
-
# @option options [Boolean] :query_time when true will query the {https://ably.io Ably} system for the current time instead of using the local time
|
87
|
-
# @option options [Time] :timestamp the time of the of the request
|
88
|
-
# @option options [String] :nonce an unquoted, unescaped random string of at least 16 characters
|
89
|
-
# @option options [Boolean] :force obtains a new token even if the current token is valid
|
79
|
+
# @option options (see #request_token)
|
80
|
+
# @option options [Boolean] :force obtains a new token even if the current token is valid
|
90
81
|
#
|
91
|
-
# @yield
|
92
|
-
# @yieldparam [Hash] options options passed to
|
93
|
-
# @yieldreturn
|
82
|
+
# @yield (see #request_token)
|
83
|
+
# @yieldparam [Hash] options options passed to {#authorise} will be in turn sent to the block in this argument
|
84
|
+
# @yieldreturn (see #request_token)
|
94
85
|
#
|
95
|
-
# @return
|
86
|
+
# @return (see #request_token)
|
96
87
|
#
|
97
88
|
# @example
|
98
89
|
# # will issue a simple token request using basic auth
|
@@ -105,12 +96,15 @@ module Ably
|
|
105
96
|
# token_request
|
106
97
|
# end
|
107
98
|
#
|
108
|
-
def authorise(options = {}, &
|
99
|
+
def authorise(options = {}, &token_request_block)
|
109
100
|
if !options[:force] && current_token
|
110
101
|
return current_token unless current_token.expired?
|
111
102
|
end
|
112
103
|
|
113
|
-
@
|
104
|
+
@options = @options.merge(options)
|
105
|
+
@default_token_block = token_request_block if block_given?
|
106
|
+
|
107
|
+
@current_token = request_token(options, &token_request_block)
|
114
108
|
end
|
115
109
|
|
116
110
|
# Request a {Ably::Models::Token} which can be used to make authenticated token based requests
|
@@ -129,9 +123,9 @@ module Ably
|
|
129
123
|
# @option options [Time] :timestamp the time of the of the request
|
130
124
|
# @option options [String] :nonce an unquoted, unescaped random string of at least 16 characters
|
131
125
|
#
|
132
|
-
# @yield [options] (optional) if
|
133
|
-
# @yieldparam [Hash] options options passed to request_token will be in turn sent to the block in this argument
|
134
|
-
# @yieldreturn [Hash] valid token request object, see {
|
126
|
+
# @yield [options] (optional) if a token request block is passed to this method, then this block will be called whenever a new token is required
|
127
|
+
# @yieldparam [Hash] options options passed to {#request_token} will be in turn sent to the block in this argument
|
128
|
+
# @yieldreturn [Hash] expects a valid token request object, see {#create_token_request}
|
135
129
|
#
|
136
130
|
# @return [Ably::Models::Token]
|
137
131
|
#
|
@@ -146,14 +140,14 @@ module Ably
|
|
146
140
|
# token_request
|
147
141
|
# end
|
148
142
|
#
|
149
|
-
def request_token(options = {}, &
|
143
|
+
def request_token(options = {}, &token_request_block)
|
150
144
|
token_options = self.auth_options.merge(options)
|
151
145
|
|
152
146
|
auth_url = token_options.delete(:auth_url)
|
153
147
|
token_request = if block_given?
|
154
|
-
|
155
|
-
elsif
|
156
|
-
|
148
|
+
token_request_block.call(token_options)
|
149
|
+
elsif default_token_block
|
150
|
+
default_token_block.call(token_options)
|
157
151
|
elsif auth_url
|
158
152
|
token_request_from_auth_url(auth_url, token_options)
|
159
153
|
else
|
@@ -162,7 +156,7 @@ module Ably
|
|
162
156
|
|
163
157
|
token_request = IdiomaticRubyWrapper(token_request)
|
164
158
|
|
165
|
-
response = client.post("/keys/#{token_request.fetch(:id)}/requestToken", token_request.hash, send_auth_header: false)
|
159
|
+
response = client.post("/keys/#{token_request.fetch(:id)}/requestToken", token_request.hash, send_auth_header: false, disable_automatic_reauthorise: true)
|
166
160
|
body = IdiomaticRubyWrapper(response.body)
|
167
161
|
|
168
162
|
Ably::Models::Token.new(body.fetch(:access_token))
|
@@ -220,8 +214,9 @@ module Ably
|
|
220
214
|
token_request[:capability] = token_request[:capability].to_json
|
221
215
|
end
|
222
216
|
|
223
|
-
token_request[:
|
217
|
+
ensure_utf_8 :nonce, token_request[:nonce], allow_nil: true
|
224
218
|
|
219
|
+
token_request[:mac] = sign_params(token_request, request_key_secret)
|
225
220
|
token_request
|
226
221
|
end
|
227
222
|
|
@@ -244,6 +239,7 @@ module Ably
|
|
244
239
|
|
245
240
|
# True when Token Auth is being used to authenticate with Ably
|
246
241
|
def using_token_auth?
|
242
|
+
return options[:use_token_auth] if options.has_key?(:use_token_auth)
|
247
243
|
token_id || current_token || has_client_id? || token_creatable_externally?
|
248
244
|
end
|
249
245
|
|
@@ -280,26 +276,38 @@ module Ably
|
|
280
276
|
# True if prerequisites for creating a new token request are present
|
281
277
|
#
|
282
278
|
# One of the following criterion must be met:
|
283
|
-
# * Valid key id and secret
|
279
|
+
# * Valid key id and secret and token_id option not provided as token options cannot be determined
|
284
280
|
# * Authentication callback for new token requests
|
285
281
|
# * Authentication URL for new token requests
|
286
282
|
#
|
287
283
|
# @return [Boolean]
|
288
284
|
def token_renewable?
|
289
|
-
token_creatable_externally? || api_key_present?
|
285
|
+
token_creatable_externally? || (api_key_present? && !token_id)
|
286
|
+
end
|
287
|
+
|
288
|
+
# Returns false when attempting to send an API Key over a non-secure connection
|
289
|
+
# Token auth must be used for non-secure connections
|
290
|
+
#
|
291
|
+
# @return [Boolean]
|
292
|
+
def authentication_security_requirements_met?
|
293
|
+
client.use_tls? || using_token_auth?
|
290
294
|
end
|
291
295
|
|
292
296
|
private
|
293
|
-
attr_reader :
|
297
|
+
attr_reader :default_token_block
|
298
|
+
|
299
|
+
def ensure_api_key_sent_over_secure_connection
|
300
|
+
raise Ably::Exceptions::InsecureRequestError, 'Cannot use Basic Auth over non-TLS connections' unless authentication_security_requirements_met?
|
301
|
+
end
|
294
302
|
|
295
303
|
# Basic Auth HTTP Authorization header value
|
296
304
|
def basic_auth_header
|
297
|
-
|
305
|
+
ensure_api_key_sent_over_secure_connection
|
298
306
|
"Basic #{encode64("#{api_key}")}"
|
299
307
|
end
|
300
308
|
|
301
309
|
def token_auth_id
|
302
|
-
|
310
|
+
if token_id
|
303
311
|
token_id
|
304
312
|
else
|
305
313
|
authorise.id
|
@@ -313,7 +321,7 @@ module Ably
|
|
313
321
|
|
314
322
|
# Basic Auth params to authenticate the Realtime connection
|
315
323
|
def basic_auth_params
|
316
|
-
|
324
|
+
ensure_api_key_sent_over_secure_connection
|
317
325
|
# TODO: Change to key_secret when API is updated
|
318
326
|
{
|
319
327
|
key_id: key_id,
|
@@ -403,7 +411,7 @@ module Ably
|
|
403
411
|
end
|
404
412
|
|
405
413
|
def token_callback_present?
|
406
|
-
!!
|
414
|
+
!!default_token_block
|
407
415
|
end
|
408
416
|
|
409
417
|
def token_url_present?
|
data/lib/ably/exceptions.rb
CHANGED
@@ -33,23 +33,37 @@ module Ably
|
|
33
33
|
# Encoding or decoding failure
|
34
34
|
class EncoderError < BaseAblyException; end
|
35
35
|
|
36
|
+
# Connection error from Realtime or REST service
|
37
|
+
class ConnectionError < BaseAblyException
|
38
|
+
def initialize(message, status = nil, code = nil, base_error = nil)
|
39
|
+
super message, status, code
|
40
|
+
@base_error = base_error
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Connection Timeout accessing Realtime or REST service
|
45
|
+
class ConnectionTimeoutError < ConnectionError; end
|
46
|
+
|
47
|
+
# Invalid State Change error on a {https://github.com/gocardless/statesman Statesman State Machine}
|
48
|
+
class StateChangeError < BaseAblyException; end
|
49
|
+
|
36
50
|
# A generic Ably exception taht supports a status & code.
|
37
51
|
# See https://github.com/ably/ably-common/blob/master/protocol/errors.json for a list of Ably errors
|
38
52
|
class Standard < BaseAblyException; end
|
39
53
|
|
40
54
|
# The HTTP request has returned a 500 error
|
41
|
-
class ServerError <
|
55
|
+
class ServerError < BaseAblyException; end
|
42
56
|
|
43
57
|
# PaginatedResource cannot retrieve the page
|
44
|
-
class InvalidPageError <
|
58
|
+
class InvalidPageError < BaseAblyException; end
|
45
59
|
|
46
60
|
# The expected response from the server was invalid
|
47
|
-
class InvalidResponseBody <
|
61
|
+
class InvalidResponseBody < BaseAblyException; end
|
48
62
|
|
49
63
|
# The request cannot be performed because it is insecure
|
50
|
-
class InsecureRequestError <
|
64
|
+
class InsecureRequestError < BaseAblyException; end
|
51
65
|
|
52
66
|
# The token request could not be created
|
53
|
-
class TokenRequestError <
|
67
|
+
class TokenRequestError < BaseAblyException; end
|
54
68
|
end
|
55
69
|
end
|
data/lib/ably/logger.rb
CHANGED
@@ -19,7 +19,7 @@ module Ably::Models
|
|
19
19
|
@hash_object = IdiomaticRubyWrapper(hash_object.clone.freeze)
|
20
20
|
end
|
21
21
|
|
22
|
-
%w(
|
22
|
+
%w(message code status_code).each do |attribute|
|
23
23
|
define_method attribute do
|
24
24
|
hash[attribute.to_sym]
|
25
25
|
end
|
@@ -50,7 +50,9 @@ module Ably::Models
|
|
50
50
|
# @attribute [Hash] mixedCaseHashObject mixed case Hash object
|
51
51
|
# @attribute [Array<Symbol,String>] stop_at array of keys that this wrapper should stop wrapping at to preserve the underlying Hash as is
|
52
52
|
#
|
53
|
-
def initialize(mixedCaseHashObject,
|
53
|
+
def initialize(mixedCaseHashObject, options = {})
|
54
|
+
stop_at = options.fetch(:stop_at, [])
|
55
|
+
|
54
56
|
if mixedCaseHashObject.kind_of?(IdiomaticRubyWrapper)
|
55
57
|
$stderr.puts "<IdiomaticRubyWrapper#initialize> WARNING: Wrapping a IdiomaticRubyWrapper with another IdiomaticRubyWrapper"
|
56
58
|
end
|
@@ -203,14 +205,14 @@ module Ably::Models
|
|
203
205
|
# key is not found in mixedCase.
|
204
206
|
def source_key_for(symbolized_key)
|
205
207
|
format_preferences = [
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
208
|
+
proc { |key_sym| convert_to_mixed_case(key_sym) },
|
209
|
+
proc { |key_sym| key_sym.to_sym },
|
210
|
+
proc { |key_sym| key_sym.to_s },
|
211
|
+
proc { |key_sym| convert_to_mixed_case(key_sym).to_sym },
|
212
|
+
proc { |key_sym| convert_to_lower_case(key_sym) },
|
213
|
+
proc { |key_sym| convert_to_lower_case(key_sym).to_sym },
|
214
|
+
proc { |key_sym| convert_to_mixed_case(key_sym, force_camel: true) },
|
215
|
+
proc { |key_sym| convert_to_mixed_case(key_sym, force_camel: true).to_sym }
|
214
216
|
]
|
215
217
|
|
216
218
|
preferred_format = format_preferences.detect do |format|
|
data/lib/ably/models/message.rb
CHANGED
@@ -32,12 +32,15 @@ module Ably::Models
|
|
32
32
|
# @return [Time] Timestamp when the message was received by the Ably the real-time service
|
33
33
|
# @!attribute [r] id
|
34
34
|
# @return [String] A globally unique message ID
|
35
|
+
# @!attribute [r] connection_id
|
36
|
+
# @return [String] The connection_id of the publisher of the message
|
35
37
|
# @!attribute [r] hash
|
36
38
|
# @return [Hash] Access the protocol message Hash object ruby'fied to use symbolized keys
|
37
39
|
#
|
38
40
|
class Message
|
39
|
-
include Ably::Modules::
|
41
|
+
include Ably::Modules::Conversions
|
40
42
|
include Ably::Modules::Encodeable
|
43
|
+
include Ably::Modules::ModelCommon
|
41
44
|
include EventMachine::Deferrable
|
42
45
|
|
43
46
|
# {Message} initializer
|
@@ -50,9 +53,13 @@ module Ably::Models
|
|
50
53
|
@raw_hash_object = hash_object
|
51
54
|
|
52
55
|
set_hash_object hash_object
|
56
|
+
|
57
|
+
ensure_utf_8 :name, name, allow_nil: true
|
58
|
+
ensure_utf_8 :client_id, client_id, allow_nil: true
|
59
|
+
ensure_utf_8 :encoding, encoding, allow_nil: true
|
53
60
|
end
|
54
61
|
|
55
|
-
%w( name client_id encoding ).each do |attribute|
|
62
|
+
%w( name client_id encoding connection_id ).each do |attribute|
|
56
63
|
define_method attribute do
|
57
64
|
hash[attribute.to_sym]
|
58
65
|
end
|
@@ -63,7 +70,11 @@ module Ably::Models
|
|
63
70
|
end
|
64
71
|
|
65
72
|
def id
|
66
|
-
hash
|
73
|
+
hash.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
|
74
|
+
end
|
75
|
+
|
76
|
+
def connection_id
|
77
|
+
hash.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
|
67
78
|
end
|
68
79
|
|
69
80
|
def timestamp
|
@@ -111,15 +122,7 @@ module Ably::Models
|
|
111
122
|
attr_reader :raw_hash_object
|
112
123
|
|
113
124
|
def protocol_message_index
|
114
|
-
protocol_message.messages.index(self)
|
115
|
-
end
|
116
|
-
|
117
|
-
def connection_id
|
118
|
-
protocol_message.connection_id
|
119
|
-
end
|
120
|
-
|
121
|
-
def message_serial
|
122
|
-
protocol_message.message_serial
|
125
|
+
protocol_message.messages.map(&:object_id).index(self.object_id)
|
123
126
|
end
|
124
127
|
|
125
128
|
def set_hash_object(hash)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ably/modules/conversions'
|
2
|
+
|
1
3
|
# MessageEncoders are registered with the Ably client library and are responsible
|
2
4
|
# for encoding & decoding messages.
|
3
5
|
#
|
@@ -93,11 +95,6 @@ module Ably::Models::MessageEncoders
|
|
93
95
|
end
|
94
96
|
|
95
97
|
def self.register_default_encoders(client)
|
96
|
-
Dir.glob(File.expand_path("*.rb", File.dirname(__FILE__))).each do |file|
|
97
|
-
next if __FILE__ == file
|
98
|
-
require file
|
99
|
-
end
|
100
|
-
|
101
98
|
client.register_encoder Ably::Models::MessageEncoders::Utf8
|
102
99
|
client.register_encoder Ably::Models::MessageEncoders::Json
|
103
100
|
client.register_encoder Ably::Models::MessageEncoders::Cipher
|
@@ -105,3 +102,7 @@ module Ably::Models::MessageEncoders
|
|
105
102
|
end
|
106
103
|
end
|
107
104
|
|
105
|
+
require 'ably/models/message_encoders/base64'
|
106
|
+
require 'ably/models/message_encoders/cipher'
|
107
|
+
require 'ably/models/message_encoders/json'
|
108
|
+
require 'ably/models/message_encoders/utf8'
|
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'ably/exceptions'
|
2
|
+
require 'ably/models/message_encoders/base'
|
3
|
+
require 'ably/util/crypto'
|
4
|
+
|
1
5
|
module Ably::Models::MessageEncoders
|
2
6
|
# Cipher Encoder & Decoder that automatically encrypts & decrypts messages using Ably::Util::Crypto
|
3
7
|
# when a channel has option encrypted: true.
|
@@ -41,7 +45,6 @@ module Ably::Models::MessageEncoders
|
|
41
45
|
end
|
42
46
|
|
43
47
|
message[:data] = crypto.decrypt(message[:data])
|
44
|
-
message[:data].force_encoding(Encoding::ASCII_8BIT) if is_binary?(message)
|
45
48
|
strip_current_encoding_part message
|
46
49
|
end
|
47
50
|
rescue OpenSSL::Cipher::CipherError => e
|
@@ -70,11 +73,11 @@ module Ably::Models::MessageEncoders
|
|
70
73
|
end
|
71
74
|
|
72
75
|
def cipher_algorithm(message)
|
73
|
-
current_encoding_part(message).to_s[/^#{ENCODING_ID}\+([\
|
76
|
+
current_encoding_part(message).to_s[/^#{ENCODING_ID}\+([\w_-]+)$/, 1]
|
74
77
|
end
|
75
78
|
|
76
79
|
def already_encrypted?(message)
|
77
|
-
message.fetch(:encoding, '').to_s.match(%r{(^|/)#{ENCODING_ID}\+([\
|
80
|
+
message.fetch(:encoding, '').to_s.match(%r{(^|/)#{ENCODING_ID}\+([\w_-]+)($|/)})
|
78
81
|
end
|
79
82
|
end
|
80
83
|
end
|