ably 1.1.6 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +15 -1
  3. data/CHANGELOG.md +131 -0
  4. data/COPYRIGHT +1 -1
  5. data/README.md +14 -2
  6. data/SPEC.md +0 -7
  7. data/UPDATING.md +30 -0
  8. data/ably.gemspec +12 -7
  9. data/lib/ably/agent.rb +3 -0
  10. data/lib/ably/auth.rb +3 -3
  11. data/lib/ably/exceptions.rb +6 -0
  12. data/lib/ably/models/channel_options.rb +97 -0
  13. data/lib/ably/models/connection_details.rb +8 -0
  14. data/lib/ably/models/delta_extras.rb +29 -0
  15. data/lib/ably/models/error_info.rb +6 -2
  16. data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
  17. data/lib/ably/models/message.rb +28 -3
  18. data/lib/ably/models/presence_message.rb +14 -0
  19. data/lib/ably/models/protocol_message.rb +29 -12
  20. data/lib/ably/models/token_details.rb +7 -2
  21. data/lib/ably/modules/channels_collection.rb +22 -2
  22. data/lib/ably/modules/conversions.rb +34 -0
  23. data/lib/ably/realtime/channel/channel_manager.rb +18 -6
  24. data/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
  25. data/lib/ably/realtime/channel/publisher.rb +6 -0
  26. data/lib/ably/realtime/channel.rb +54 -22
  27. data/lib/ably/realtime/channels.rb +1 -1
  28. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
  29. data/lib/ably/realtime/connection/connection_manager.rb +13 -4
  30. data/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
  31. data/lib/ably/realtime/connection.rb +2 -2
  32. data/lib/ably/rest/channel.rb +31 -31
  33. data/lib/ably/rest/client.rb +27 -12
  34. data/lib/ably/util/crypto.rb +1 -1
  35. data/lib/ably/version.rb +2 -14
  36. data/lib/ably.rb +1 -0
  37. data/spec/acceptance/realtime/auth_spec.rb +1 -1
  38. data/spec/acceptance/realtime/channel_history_spec.rb +25 -0
  39. data/spec/acceptance/realtime/channel_spec.rb +466 -21
  40. data/spec/acceptance/realtime/channels_spec.rb +59 -7
  41. data/spec/acceptance/realtime/connection_failures_spec.rb +59 -2
  42. data/spec/acceptance/realtime/connection_spec.rb +256 -28
  43. data/spec/acceptance/realtime/message_spec.rb +77 -0
  44. data/spec/acceptance/realtime/presence_history_spec.rb +3 -1
  45. data/spec/acceptance/realtime/presence_spec.rb +31 -159
  46. data/spec/acceptance/rest/auth_spec.rb +18 -0
  47. data/spec/acceptance/rest/channel_spec.rb +84 -9
  48. data/spec/acceptance/rest/channels_spec.rb +23 -6
  49. data/spec/acceptance/rest/client_spec.rb +25 -21
  50. data/spec/acceptance/rest/message_spec.rb +61 -3
  51. data/spec/lib/unit/models/channel_options_spec.rb +52 -0
  52. data/spec/shared/model_behaviour.rb +1 -1
  53. data/spec/spec_helper.rb +11 -2
  54. data/spec/support/test_app.rb +1 -1
  55. data/spec/unit/models/delta_extras_spec.rb +14 -0
  56. data/spec/unit/models/error_info_spec.rb +17 -1
  57. data/spec/unit/models/message_spec.rb +97 -0
  58. data/spec/unit/models/presence_message_spec.rb +49 -0
  59. data/spec/unit/models/protocol_message_spec.rb +125 -27
  60. data/spec/unit/models/token_details_spec.rb +14 -0
  61. data/spec/unit/realtime/channel_spec.rb +3 -2
  62. data/spec/unit/realtime/channels_spec.rb +53 -15
  63. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
  64. data/spec/unit/rest/channel_spec.rb +44 -1
  65. data/spec/unit/rest/channels_spec.rb +81 -14
  66. data/spec/unit/rest/client_spec.rb +47 -0
  67. metadata +60 -24
@@ -19,8 +19,6 @@ module Ably::Models
19
19
  # @!attribute [r] channel_serial
20
20
  # @return [String] Contains a serial number for a message on the current channel
21
21
  # @!attribute [r] connection_id
22
- # @return [String] Contains a string public identifier for the connection
23
- # @!attribute [r] connection_key
24
22
  # @return [String] Contains a string private connection key used to recover this connection
25
23
  # @!attribute [r] connection_serial
26
24
  # @return [Bignum] Contains a serial number for a message sent from the server to the client
@@ -68,6 +66,14 @@ module Ably::Models
68
66
  auth: 17
69
67
  )
70
68
 
69
+ ATTACH_FLAGS_MAPPING = {
70
+ resume: 32, # 2^5
71
+ presence: 65536, # 2^16
72
+ publish: 131072, # 2^17
73
+ subscribe: 262144, # 2^18
74
+ presence_subscribe: 524288, # 2^19
75
+ }
76
+
71
77
  # Indicates this protocol message action will generate an ACK response such as :message or :presence
72
78
  # @api private
73
79
  def self.ack_required?(for_action)
@@ -98,12 +104,6 @@ module Ably::Models
98
104
  end
99
105
  end
100
106
 
101
- def connection_key
102
- # connection_key in connection details takes precedence over connection_key on the ProtocolMessage
103
- # connection_key in the ProtocolMessage will be deprecated in future protocol versions > 0.8
104
- connection_details.connection_key || attributes[:connection_key]
105
- end
106
-
107
107
  def id!
108
108
  raise RuntimeError, 'ProtocolMessage #id is nil' unless id
109
109
  id
@@ -185,6 +185,18 @@ module Ably::Models
185
185
  end
186
186
  end
187
187
 
188
+ def message_size
189
+ presence.map(&:size).sum + messages.map(&:size).sum
190
+ end
191
+
192
+ def has_correct_message_size?
193
+ message_size <= connection_details.max_message_size
194
+ end
195
+
196
+ def params
197
+ @params ||= attributes[:params].to_h
198
+ end
199
+
188
200
  def flags
189
201
  Integer(attributes[:flags])
190
202
  rescue TypeError
@@ -216,24 +228,29 @@ module Ably::Models
216
228
  flags & 16 == 16 # 2^4
217
229
  end
218
230
 
231
+ # @api private
232
+ def has_attach_resume_flag?
233
+ flags & ATTACH_FLAGS_MAPPING[:resume] == ATTACH_FLAGS_MAPPING[:resume] # 2^5
234
+ end
235
+
219
236
  # @api private
220
237
  def has_attach_presence_flag?
221
- flags & 65536 == 65536 # 2^16
238
+ flags & ATTACH_FLAGS_MAPPING[:presence] == ATTACH_FLAGS_MAPPING[:presence] # 2^16
222
239
  end
223
240
 
224
241
  # @api private
225
242
  def has_attach_publish_flag?
226
- flags & 131072 == 131072 # 2^17
243
+ flags & ATTACH_FLAGS_MAPPING[:publish] == ATTACH_FLAGS_MAPPING[:publish] # 2^17
227
244
  end
228
245
 
229
246
  # @api private
230
247
  def has_attach_subscribe_flag?
231
- flags & 262144 == 262144 # 2^18
248
+ flags & ATTACH_FLAGS_MAPPING[:subscribe] == ATTACH_FLAGS_MAPPING[:subscribe] # 2^18
232
249
  end
233
250
 
234
251
  # @api private
235
252
  def has_attach_presence_subscribe_flag?
236
- flags & 524288 == 524288 # 2^19
253
+ flags & ATTACH_FLAGS_MAPPING[:presence_subscribe] == ATTACH_FLAGS_MAPPING[:presence_subscribe] # 2^19
237
254
  end
238
255
 
239
256
  def connection_details
@@ -95,10 +95,15 @@ module Ably::Models
95
95
  # Returns true if token is expired or about to expire
96
96
  # For tokens that have not got an explicit expires attribute expired? will always return true
97
97
  #
98
+ # @param attributes [Hash]
99
+ # @option attributes [Time] :from Sets a current time from which token expires
100
+ #
98
101
  # @return [Boolean]
99
- def expired?
102
+ def expired?(attributes = {})
100
103
  return false if !expires
101
- expires < Time.now + TOKEN_EXPIRY_BUFFER
104
+
105
+ from = attributes[:from] || Time.now
106
+ expires < from + TOKEN_EXPIRY_BUFFER
102
107
  end
103
108
 
104
109
  # True if the TokenDetails was created from an opaque string i.e. no metadata exists for this token
@@ -13,14 +13,21 @@ module Ably::Modules
13
13
  # Return a Channel for the given name
14
14
  #
15
15
  # @param name [String] The name of the channel
16
- # @param channel_options [Hash] Channel options including the encryption options
16
+ # @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
17
17
  #
18
18
  # @return [Channel]
19
19
  #
20
20
  def get(name, channel_options = {})
21
21
  if channels.has_key?(name)
22
22
  channels[name].tap do |channel|
23
- channel.update_options channel_options if channel_options && !channel_options.empty?
23
+ if channel_options && !channel_options.empty?
24
+ if channel.respond_to?(:need_reattach?) && channel.need_reattach?
25
+ raise_implicit_options_update
26
+ else
27
+ warn_implicit_options_update
28
+ channel.options = channel_options
29
+ end
30
+ end
24
31
  end
25
32
  else
26
33
  channels[name] ||= channel_klass.new(client, name, channel_options)
@@ -70,6 +77,19 @@ module Ably::Modules
70
77
  end
71
78
 
72
79
  private
80
+
81
+ def raise_implicit_options_update
82
+ raise ArgumentError, "You are trying to indirectly update channel options which will trigger reattachment of the channel. Please use Channel#set_options directly if you wish to continue"
83
+ end
84
+
85
+ def warn_implicit_options_update
86
+ logger.warn { "Channels#get: Using this method to update channel options is deprecated and may be removed in a future version of ably-ruby. Please use Channel#setOptions instead" }
87
+ end
88
+
89
+ def logger
90
+ client.logger
91
+ end
92
+
73
93
  def client
74
94
  @client
75
95
  end
@@ -115,5 +115,39 @@ module Ably::Modules
115
115
 
116
116
  raise Ably::Exceptions::UnsupportedDataType.new('Invalid data payload', 400, Ably::Exceptions::Codes::INVALID_MESSAGE_DATA_OR_ENCODING)
117
117
  end
118
+
119
+ # Converts the name, data, attributes into the array of Message objects
120
+ #
121
+ # @return [Array<Ably::Models::Message>]
122
+ #
123
+ def build_messages(name, data = nil, attributes = {})
124
+ return [Ably::Models::Message(ensure_supported_name_and_payload(nil, data, attributes))] if name.nil?
125
+
126
+ Array(name).map do |item|
127
+ Ably::Models::Message(ensure_supported_name_and_payload(item, data, attributes))
128
+ end
129
+ end
130
+
131
+ # Ensures if the first argument (name) is a String, Hash or Ably::Models::Message object,
132
+ # second argument (data) should be a String, Hash, Array or nil (see ensure_supported_payload() method).
133
+ #
134
+ # @return [Hash] Contains :name, :data and other attributes
135
+ #
136
+ # (RSL1a, RSL1b)
137
+ #
138
+ def ensure_supported_name_and_payload(name, data = nil, attributes = {})
139
+ return name.attributes.dup if name.kind_of?(Ably::Models::Message)
140
+
141
+ payload = data
142
+ if (hash = name).kind_of?(Hash)
143
+ name, payload = hash[:name], (hash[:data] || payload)
144
+ attributes.merge!(hash)
145
+ end
146
+
147
+ name = ensure_utf_8(:name, name, allow_nil: true)
148
+ ensure_supported_payload payload
149
+
150
+ attributes.merge({ name: name, data: payload })
151
+ end
118
152
  end
119
153
  end
@@ -38,6 +38,8 @@ module Ably::Realtime
38
38
  if attached_protocol_message
39
39
  update_presence_sync_state_following_attached attached_protocol_message
40
40
  channel.properties.set_attach_serial(attached_protocol_message.channel_serial)
41
+ channel.options.set_modes_from_flags(attached_protocol_message.flags)
42
+ channel.options.set_params(attached_protocol_message.params)
41
43
  end
42
44
  end
43
45
 
@@ -63,6 +65,9 @@ module Ably::Realtime
63
65
  log_channel_error protocol_message.error
64
66
  end
65
67
 
68
+ channel.properties.set_attach_serial(protocol_message.channel_serial)
69
+ channel.options.set_modes_from_flags(protocol_message.flags)
70
+
66
71
  if protocol_message.has_channel_resumed_flag?
67
72
  logger.debug { "ChannelManager: Additional resumed ATTACHED message received for #{channel.state} channel '#{channel.name}'" }
68
73
  else
@@ -75,8 +80,6 @@ module Ably::Realtime
75
80
  )
76
81
  update_presence_sync_state_following_attached protocol_message
77
82
  end
78
-
79
- channel.properties.set_attach_serial(protocol_message.channel_serial)
80
83
  end
81
84
 
82
85
  # Handle DETACED messages, see #RTL13 for server-initated detaches
@@ -199,14 +202,21 @@ module Ably::Realtime
199
202
  end
200
203
 
201
204
  def send_attach_protocol_message
202
- send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Attach, :suspended # move to suspended
205
+ message_options = {}
206
+ message_options[:params] = channel.options.params if channel.options.params.any?
207
+ message_options[:flags] = channel.options.modes_to_flags if channel.options.modes
208
+ if channel.attach_resume
209
+ message_options[:flags] = message_options[:flags].to_i | Ably::Models::ProtocolMessage::ATTACH_FLAGS_MAPPING[:resume]
210
+ end
211
+
212
+ send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Attach, :suspended, message_options
203
213
  end
204
214
 
205
215
  def send_detach_protocol_message(previous_state)
206
216
  send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Detach, previous_state # return to previous state if failed
207
217
  end
208
218
 
209
- def send_state_change_protocol_message(new_state, state_if_failed)
219
+ def send_state_change_protocol_message(new_state, state_if_failed, message_options = {})
210
220
  state_at_time_of_request = channel.state
211
221
  @pending_state_change_timer = EventMachine::Timer.new(realtime_request_timeout) do
212
222
  if channel.state == state_at_time_of_request
@@ -227,7 +237,8 @@ module Ably::Realtime
227
237
  next unless pending_state_change_timer
228
238
  connection.send_protocol_message(
229
239
  action: new_state.to_i,
230
- channel: channel.name
240
+ channel: channel.name,
241
+ **message_options.to_h
231
242
  )
232
243
  resend_if_disconnected_and_connected.call
233
244
  end
@@ -237,7 +248,8 @@ module Ably::Realtime
237
248
 
238
249
  connection.send_protocol_message(
239
250
  action: new_state.to_i,
240
- channel: channel.name
251
+ channel: channel.name,
252
+ **message_options.to_h
241
253
  )
242
254
  end
243
255
 
@@ -26,18 +26,27 @@ module Ably::Realtime
26
26
  transition :from => :detaching, :to => [:detached, :attaching, :attached, :failed, :suspended]
27
27
  transition :from => :detached, :to => [:attaching, :attached, :failed]
28
28
  transition :from => :suspended, :to => [:attaching, :attached, :detached, :failed]
29
- transition :from => :failed, :to => [:attaching]
29
+ transition :from => :failed, :to => [:attaching, :initialized]
30
30
 
31
31
  after_transition do |channel, transition|
32
32
  channel.synchronize_state_with_statemachine
33
33
  end
34
34
 
35
+ after_transition(to: [:initialized]) do |channel|
36
+ channel.clear_error_reason
37
+ end
38
+
35
39
  after_transition(to: [:attaching]) do |channel|
36
40
  channel.manager.attach
37
41
  end
38
42
 
39
43
  before_transition(to: [:attached]) do |channel, current_transition|
40
44
  channel.manager.attached current_transition.metadata.protocol_message
45
+ channel.attach_resume!
46
+ end
47
+
48
+ before_transition(to: [:detaching, :failed]) do |channel, _current_transition|
49
+ channel.reset_attach_resume!
41
50
  end
42
51
 
43
52
  after_transition(to: [:detaching]) do |channel, current_transition|
@@ -22,6 +22,12 @@ module Ably::Realtime
22
22
  end
23
23
  end
24
24
 
25
+ max_message_size = connection.details && connection.details.max_message_size || Ably::Models::ConnectionDetails::MAX_MESSAGE_SIZE
26
+ if messages.sum(&:size) > max_message_size
27
+ error = Ably::Exceptions::MaxMessageSizeExceeded.new("Message size exceeded #{max_message_size} bytes.")
28
+ return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
29
+ end
30
+
25
31
  connection.send_protocol_message(
26
32
  action: Ably::Models::ProtocolMessage::ACTION.Message.to_i,
27
33
  channel: channel_name,
@@ -36,6 +36,7 @@ module Ably
36
36
  include Ably::Modules::MessageEmitter
37
37
  include Ably::Realtime::Channel::Publisher
38
38
  extend Ably::Modules::Enum
39
+ extend Forwardable
39
40
 
40
41
  # ChannelState
41
42
  # The permited states for this channel
@@ -92,17 +93,25 @@ module Ably
92
93
  # @api private
93
94
  attr_reader :manager
94
95
 
96
+ # Flag that specifies whether channel is resuming attachment(reattach) or is doing a 'clean attach' RTL4j1
97
+ # @return [Bolean]
98
+ # @api private
99
+ attr_reader :attach_resume
100
+
101
+ # ChannelOptions params attrribute (#RTL4k)
102
+ # return [Hash]
103
+ def_delegators :options, :params
104
+
95
105
  # Initialize a new Channel object
96
106
  #
97
107
  # @param client [Ably::Rest::Client]
98
108
  # @param name [String] The name of the channel
99
- # @param channel_options [Hash] Channel options, currently reserved for Encryption options
100
- # @option channel_options [Hash,Ably::Models::CipherParams] :cipher A hash of options or a {Ably::Models::CipherParams} to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of +:cipher+ options
109
+ # @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
101
110
  #
102
111
  def initialize(client, name, channel_options = {})
103
112
  name = ensure_utf_8(:name, name)
104
113
 
105
- update_options channel_options
114
+ @options = Ably::Models::ChannelOptions(channel_options)
106
115
  @client = client
107
116
  @name = name
108
117
  @queue = []
@@ -112,6 +121,7 @@ module Ably
112
121
  @manager = ChannelManager.new(self, client.connection)
113
122
  @push = PushChannel.new(self)
114
123
  @properties = ChannelProperties.new(self)
124
+ @attach_resume = false
115
125
 
116
126
  setup_event_handlers
117
127
  setup_presence
@@ -129,23 +139,31 @@ module Ably
129
139
  # @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callbacks
130
140
  #
131
141
  # @example
132
- # # Publish a single message
142
+ # # Publish a single message form
133
143
  # channel.publish 'click', { x: 1, y: 2 }
134
144
  #
135
- # # Publish an array of message Hashes
145
+ # # Publish a single message with single Hash form
146
+ # message = { name: 'click', data: { x: 1, y: 2 } }
147
+ # channel.publish message
148
+ #
149
+ # # Publish an array of message Hashes form
136
150
  # messages = [
137
- # { name: 'click', { x: 1, y: 2 } },
138
- # { name: 'click', { x: 2, y: 3 } }
151
+ # { name: 'click', data: { x: 1, y: 2 } },
152
+ # { name: 'click', data: { x: 2, y: 3 } }
139
153
  # ]
140
154
  # channel.publish messages
141
155
  #
142
- # # Publish an array of Ably::Models::Message objects
156
+ # # Publish an array of Ably::Models::Message objects form
143
157
  # messages = [
144
- # Ably::Models::Message(name: 'click', { x: 1, y: 2 })
145
- # Ably::Models::Message(name: 'click', { x: 2, y: 3 })
158
+ # Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
159
+ # Ably::Models::Message(name: 'click', data: { x: 2, y: 3 })
146
160
  # ]
147
161
  # channel.publish messages
148
162
  #
163
+ # # Publish an array of Ably::Models::Message objects form
164
+ # message = Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
165
+ # channel.publish message
166
+ #
149
167
  # channel.publish('click', 'body') do |message|
150
168
  # puts "#{message.name} event received with #{message.data}"
151
169
  # end
@@ -165,13 +183,7 @@ module Ably
165
183
  return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
166
184
  end
167
185
 
168
- messages = if name.kind_of?(Enumerable)
169
- name
170
- else
171
- name = ensure_utf_8(:name, name, allow_nil: true)
172
- ensure_supported_payload data
173
- [{ name: name, data: data }.merge(attributes)]
174
- end
186
+ messages = build_messages(name, data, attributes) # (RSL1a, RSL1b)
175
187
 
176
188
  if messages.length > Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE
177
189
  error = Ably::Exceptions::InvalidRequest.new("It is not possible to publish more than #{Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE} messages with a single publish request.")
@@ -309,6 +321,16 @@ module Ably
309
321
  )
310
322
  end
311
323
 
324
+ # Sets or updates the stored channel options. (#RTL16)
325
+ # @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
326
+ # @return [Ably::Models::ChannelOptions]
327
+ def set_options(channel_options)
328
+ @options = Ably::Models::ChannelOptions(channel_options)
329
+
330
+ manager.request_reattach if need_reattach?
331
+ end
332
+ alias options= set_options
333
+
312
334
  # @api private
313
335
  def set_channel_error_reason(error)
314
336
  @error_reason = error
@@ -319,22 +341,32 @@ module Ably
319
341
  @error_reason = nil
320
342
  end
321
343
 
322
- # @api private
323
- def update_options(channel_options)
324
- @options = channel_options.clone.freeze
325
- end
326
-
327
344
  # Used by {Ably::Modules::StateEmitter} to debug state changes
328
345
  # @api private
329
346
  def logger
330
347
  client.logger
331
348
  end
332
349
 
350
+ # @api private
351
+ def attach_resume!
352
+ @attach_resume = true
353
+ end
354
+
355
+ # @api private
356
+ def reset_attach_resume!
357
+ @attach_resume = false
358
+ end
359
+
333
360
  # As we are using a state machine, do not allow change_state to be used
334
361
  # #transition_state_machine must be used instead
335
362
  private :change_state
336
363
 
364
+ def need_reattach?
365
+ !!(attaching? || attached?) && !!(options.modes || options.params)
366
+ end
367
+
337
368
  private
369
+
338
370
  def setup_event_handlers
339
371
  __incoming_msgbus__.subscribe(:message) do |message|
340
372
  message.decode(client.encoders, options) do |encode_error, error_message|
@@ -13,7 +13,7 @@ module Ably
13
13
  # Return a {Ably::Realtime::Channel} for the given name
14
14
  #
15
15
  # @param name [String] The name of the channel
16
- # @param channel_options [Hash] Channel options, currently reserved for Encryption options
16
+ # @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
17
17
  # @return [Ably::Realtime::Channel}
18
18
  #
19
19
  def get(*args)
@@ -121,15 +121,23 @@ module Ably::Realtime
121
121
  presence.manager.sync_process_messages protocol_message.channel_serial, protocol_message.presence
122
122
 
123
123
  when ACTION.Presence
124
- presence = get_channel(protocol_message.channel).presence
125
- protocol_message.presence.each do |presence_message|
126
- presence.__incoming_msgbus__.publish :presence, presence_message
124
+ if protocol_message.has_correct_message_size?
125
+ presence = get_channel(protocol_message.channel).presence
126
+ protocol_message.presence.each do |presence_message|
127
+ presence.__incoming_msgbus__.publish :presence, presence_message
128
+ end
129
+ else
130
+ logger.fatal Ably::Exceptions::ProtocolError.new("Not published. Channel message limit exceeded #{protocol_message.message_size} bytes", 400, Ably::Exceptions::Codes::UNABLE_TO_RECOVER_CHANNEL_MESSAGE_LIMIT_EXCEEDED).message
127
131
  end
128
132
 
129
133
  when ACTION.Message
130
- channel = get_channel(protocol_message.channel)
131
- protocol_message.messages.each do |message|
132
- channel.__incoming_msgbus__.publish :message, message
134
+ if protocol_message.has_correct_message_size?
135
+ channel = get_channel(protocol_message.channel)
136
+ protocol_message.messages.each do |message|
137
+ channel.__incoming_msgbus__.publish :message, message
138
+ end
139
+ else
140
+ logger.fatal Ably::Exceptions::ProtocolError.new("Not published. Channel message limit exceeded #{protocol_message.message_size} bytes", 400, Ably::Exceptions::Codes::UNABLE_TO_RECOVER_CHANNEL_MESSAGE_LIMIT_EXCEEDED).message
133
141
  end
134
142
 
135
143
  when ACTION.Auth
@@ -117,17 +117,17 @@ module Ably::Realtime
117
117
  EventMachine.next_tick { connection.trigger_resumed }
118
118
  resend_pending_message_ack_queue
119
119
  else
120
- logger.debug { "ConnectionManager: Connection was not resumed, old connection ID #{connection.id} has been updated with new connection ID #{protocol_message.connection_id} and key #{protocol_message.connection_key}" }
120
+ logger.debug { "ConnectionManager: Connection was not resumed, old connection ID #{connection.id} has been updated with new connection ID #{protocol_message.connection_id} and key #{protocol_message.connection_details.connection_key}" }
121
121
  nack_messages_on_all_channels protocol_message.error
122
122
  force_reattach_on_channels protocol_message.error
123
123
  end
124
124
  else
125
- logger.debug { "ConnectionManager: New connection created with ID #{protocol_message.connection_id} and key #{protocol_message.connection_key}" }
125
+ logger.debug { "ConnectionManager: New connection created with ID #{protocol_message.connection_id} and key #{protocol_message.connection_details.connection_key}" }
126
126
  end
127
127
 
128
128
  reattach_suspended_channels protocol_message.error
129
129
 
130
- connection.configure_new protocol_message.connection_id, protocol_message.connection_key, protocol_message.connection_serial
130
+ connection.configure_new protocol_message.connection_id, protocol_message.connection_details.connection_key, protocol_message.connection_serial
131
131
  end
132
132
 
133
133
  # When connection is CONNECTED and receives an update
@@ -139,7 +139,7 @@ module Ably::Realtime
139
139
  # Update the connection details and any associated defaults
140
140
  connection.set_connection_details protocol_message.connection_details
141
141
 
142
- connection.configure_new protocol_message.connection_id, protocol_message.connection_key, protocol_message.connection_serial
142
+ connection.configure_new protocol_message.connection_id, protocol_message.connection_details.connection_key, protocol_message.connection_serial
143
143
 
144
144
  state_change = Ably::Models::ConnectionStateChange.new(
145
145
  current: connection.state,
@@ -319,6 +319,15 @@ module Ably::Realtime
319
319
  end
320
320
  end
321
321
 
322
+ # @api private
323
+ def reintialize_failed_chanels
324
+ channels.select do |channel|
325
+ channel.failed?
326
+ end.each do |channel|
327
+ channel.transition_state_machine :initialized
328
+ end
329
+ end
330
+
322
331
  # When continuity on a connection is lost all messages
323
332
  # whether queued or awaiting an ACK must be NACK'd as we now have a new connection
324
333
  def nack_messages_on_all_channels(error)
@@ -36,6 +36,10 @@ module Ably::Realtime
36
36
  connection.manager.setup_transport
37
37
  end
38
38
 
39
+ after_transition(to: [:connecting], from: [:failed]) do |connection|
40
+ connection.manager.reintialize_failed_chanels
41
+ end
42
+
39
43
  after_transition(to: [:connecting], from: [:disconnected, :suspended]) do |connection|
40
44
  connection.manager.reconnect_transport
41
45
  end
@@ -292,7 +292,7 @@ module Ably
292
292
  def internet_up?
293
293
  url = "http#{'s' if client.use_tls?}:#{Ably::INTERNET_CHECK.fetch(:url)}"
294
294
  EventMachine::DefaultDeferrable.new.tap do |deferrable|
295
- EventMachine::HttpRequest.new(url).get.tap do |http|
295
+ EventMachine::HttpRequest.new(url, tls: { verify_peer: true }).get.tap do |http|
296
296
  http.errback do
297
297
  yield false if block_given?
298
298
  deferrable.fail Ably::Exceptions::ConnectionFailed.new("Unable to connect to #{url}", nil, Ably::Exceptions::Codes::CONNECTION_FAILED)
@@ -434,7 +434,7 @@ module Ably
434
434
  'format' => client.protocol,
435
435
  'echo' => client.echo_messages,
436
436
  'v' => Ably::PROTOCOL_VERSION,
437
- 'lib' => client.rest_client.lib_version_id,
437
+ 'agent' => client.rest_client.agent
438
438
  )
439
439
 
440
440
  # Use native websocket heartbeats if possible, but allow Ably protocol heartbeats