ably 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|