ably-rest 0.7.3 → 0.7.5

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.
Files changed (69) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +1 -0
  3. data/SPEC.md +480 -472
  4. data/lib/ably-rest.rb +1 -1
  5. data/lib/submodules/ably-ruby/LICENSE.txt +1 -1
  6. data/lib/submodules/ably-ruby/README.md +107 -24
  7. data/lib/submodules/ably-ruby/SPEC.md +531 -398
  8. data/lib/submodules/ably-ruby/lib/ably/auth.rb +24 -16
  9. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +9 -0
  10. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +17 -9
  11. data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +12 -8
  12. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +18 -10
  13. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +15 -4
  14. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +4 -3
  15. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +31 -2
  16. data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +77 -0
  17. data/lib/submodules/ably-ruby/lib/ably/modules/safe_deferrable.rb +71 -0
  18. data/lib/submodules/ably-ruby/lib/ably/modules/safe_yield.rb +41 -0
  19. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +28 -8
  20. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +0 -5
  21. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +24 -29
  22. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +54 -11
  23. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +21 -6
  24. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +7 -2
  25. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +29 -26
  26. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +4 -4
  27. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +41 -9
  28. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +72 -24
  29. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +26 -4
  30. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -6
  31. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +74 -208
  32. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +264 -0
  33. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +59 -0
  34. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +64 -0
  35. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +1 -1
  36. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +6 -2
  37. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
  38. data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +3 -1
  39. data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +18 -0
  40. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  41. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +2 -2
  42. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +28 -6
  43. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +116 -46
  44. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +55 -10
  45. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +32 -0
  46. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +456 -96
  47. data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +2 -2
  48. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +2 -2
  49. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +96 -7
  50. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +8 -0
  51. data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +71 -0
  52. data/lib/submodules/ably-ruby/spec/support/api_helper.rb +1 -1
  53. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +1 -1
  54. data/lib/submodules/ably-ruby/spec/support/test_app.rb +13 -7
  55. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +15 -14
  56. data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +4 -4
  57. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +17 -17
  58. data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +4 -4
  59. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +28 -9
  60. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +50 -0
  61. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +76 -2
  62. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +51 -20
  63. data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +3 -3
  64. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +30 -0
  65. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +52 -26
  66. data/lib/submodules/ably-ruby/spec/unit/realtime/safe_deferrable_spec.rb +12 -0
  67. data/spec/spec_helper.rb +5 -0
  68. metadata +12 -4
  69. data/lib/submodules/ably-ruby/.ruby-version.old +0 -1
@@ -0,0 +1,71 @@
1
+ require 'eventmachine'
2
+
3
+ module Ably::Modules
4
+ # SafeDeferrable module provides an EventMachine::Deferrable interface to the object it is included in
5
+ # and is safe to use for for public interfaces of this client library.
6
+ # Any exceptions raised in the success or failure callbacks is caught and logged to #logger
7
+ #
8
+ # An exception in a callback provided by a developer should not break this client library
9
+ # and stop further execution of code.
10
+ #
11
+ # @note this Module requires that the method #logger is available
12
+ #
13
+ # See http://www.rubydoc.info/gems/eventmachine/1.0.7/EventMachine/Deferrable
14
+ #
15
+ module SafeDeferrable
16
+ include EventMachine::Deferrable
17
+
18
+ # Specify a block to be executed if and when the Deferrable object receives
19
+ # a status of :succeeded.
20
+ # See http://www.rubydoc.info/gems/eventmachine/1.0.7/EventMachine/Deferrable#callback-instance_method
21
+ def callback(&block)
22
+ super do |*args|
23
+ safe_deferrable_block(*args, &block)
24
+ end
25
+ end
26
+
27
+ # Specify a block to be executed if and when the Deferrable object receives
28
+ # a status of :failed.
29
+ # See http://www.rubydoc.info/gems/eventmachine/1.0.7/EventMachine/Deferrable#errback-instance_method
30
+ def errback(&block)
31
+ super do |*args|
32
+ safe_deferrable_block(*args, &block)
33
+ end
34
+ end
35
+
36
+ # Mark the Deferrable as succeeded and trigger all callbacks
37
+ # See http://www.rubydoc.info/gems/eventmachine/1.0.7/EventMachine/Deferrable#succeed-instance_method
38
+ def succeed(*args)
39
+ super(*args)
40
+ end
41
+
42
+ # Mark the Deferrable as failed and trigger all callbacks
43
+ # See http://www.rubydoc.info/gems/eventmachine/1.0.7/EventMachine/Deferrable#fail-instance_method
44
+ def fail(*args)
45
+ super(*args)
46
+ end
47
+
48
+ private
49
+ def safe_deferrable_block(*args)
50
+ yield *args
51
+ rescue StandardError => e
52
+ message = "An exception in a Deferrable callback was caught. #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
53
+ if defined?(:logger) && logger.respond_to?(:error)
54
+ logger.error message
55
+ else
56
+ fallback_logger.error message
57
+ end
58
+ end
59
+
60
+ def fallback_logger
61
+ @fallback_logger ||= ::Logger.new(STDOUT).tap do |logger|
62
+ logger.formatter = proc do |severity, datetime, progname, msg|
63
+ [
64
+ "#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L")} #{::Logger::SEV_LABEL[severity]} #{msg}",
65
+ "Warning: SafeDeferrable expects the method #logger to be defined in the class it is included in, the method was not found in #{self.class}"
66
+ ].join("\n")
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,41 @@
1
+ module Ably::Modules
2
+ # SafeYield provides the method safe_yield that will yield to the consumer
3
+ # who provided a block, however any exceptions will be caught, logged, and
4
+ # operation of the client library will continue.
5
+ #
6
+ # An exception in a callback provided by a developer should not break this client library
7
+ # and stop further execution of code.
8
+ #
9
+ # @note this Module requires that the method #logger is available
10
+ #
11
+ # @api private
12
+ module SafeYield
13
+ private
14
+
15
+ def safe_yield(block, *args)
16
+ block.call *args
17
+ rescue StandardError => e
18
+ message = "An exception in an external block was caught. #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
19
+ safe_yield_log_error message
20
+ end
21
+
22
+ def safe_yield_log_error(message)
23
+ if defined?(:logger) && logger.respond_to?(:error)
24
+ return logger.error message
25
+ end
26
+ rescue StandardError => e
27
+ fallback_logger.error message
28
+ end
29
+
30
+ def fallback_logger
31
+ @fallback_logger ||= ::Logger.new(STDOUT).tap do |logger|
32
+ logger.formatter = proc do |severity, datetime, progname, msg|
33
+ [
34
+ "#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L")} #{::Logger::SEV_LABEL[severity]} #{msg}",
35
+ "Warning: SafeYield expects the method #logger to be defined in the class it is included in, the method was not found in #{self.class}"
36
+ ].join("\n")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -6,6 +6,8 @@ module Ably::Modules
6
6
  # It also ensures the EventEmitter is configured to retrict permitted events to the
7
7
  # the available STATEs and :error.
8
8
  #
9
+ # @note This module requires that the method #logger is defined.
10
+ #
9
11
  # @example
10
12
  # class Connection
11
13
  # include Ably::Modules::EventEmitter
@@ -91,22 +93,29 @@ module Ably::Modules
91
93
  end if failure_block
92
94
 
93
95
  Array(target_states).each do |target_state|
94
- once target_state, &success_wrapper
96
+ safe_unsafe_method options[:unsafe], :once, target_state, &success_wrapper
95
97
 
96
- once_state_changed do |*args|
98
+ safe_unsafe_method options[:unsafe], :once_state_changed do |*args|
97
99
  failure_wrapper.call *args unless state == target_state
98
100
  end if failure_block
99
101
  end
100
102
  end
101
103
  end
102
104
 
105
+ # Equivalent of {#once_or_if} but any exception raised in a block will bubble up and cause this client library to fail.
106
+ # This method should only be used internally by the client library.
107
+ # @api private
108
+ def unsafe_once_or_if(target_states, options = {}, &block)
109
+ once_or_if(target_states, options.merge(unsafe: true), &block)
110
+ end
111
+
103
112
  # Calls the block once when the state changes
104
113
  #
105
114
  # @yield block is called once the state changes
106
115
  # @return [void]
107
116
  #
108
117
  # @api private
109
- def once_state_changed(&block)
118
+ def once_state_changed(options = {}, &block)
110
119
  raise ArgumentError, 'Block required' unless block_given?
111
120
 
112
121
  once_block = proc do |*args|
@@ -114,17 +123,24 @@ module Ably::Modules
114
123
  yield *args
115
124
  end
116
125
 
117
- once *self.class::STATE.map, &once_block
126
+ safe_unsafe_method options[:unsafe], :once, *self.class::STATE.map, &once_block
127
+ end
128
+
129
+ # Equivalent of {#once_state_changed} but any exception raised in a block will bubble up and cause this client library to fail.
130
+ # This method should only be used internally by the client library.
131
+ # @api private
132
+ def unsafe_once_state_changed(&block)
133
+ once_state_changed(unsafe: true, &block)
118
134
  end
119
135
 
120
136
  private
121
137
 
122
- # Returns an {EventMachine::Deferrable} and once the target state is reached, the
123
- # success block if provided and {EventMachine::Deferrable#callback} is called.
124
- # If the state changes to any other state, the {EventMachine::Deferrable#errback} is called.
138
+ # Returns an {Ably::Util::SafeDeferrable} and once the target state is reached, the
139
+ # success block if provided and {Ably::Util::SafeDeferrable#callback} is called.
140
+ # If the state changes to any other state, the {Ably::Util::SafeDeferrable#errback} is called.
125
141
  #
126
142
  def deferrable_for_state_change_to(target_state)
127
- EventMachine::DefaultDeferrable.new.tap do |deferrable|
143
+ Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
128
144
  once_or_if(target_state, else: proc { |*args| deferrable.fail self, *args }) do
129
145
  yield self if block_given?
130
146
  deferrable.succeed self
@@ -149,5 +165,9 @@ module Ably::Modules
149
165
  end
150
166
  end
151
167
  end
168
+
169
+ def safe_unsafe_method(unsafe, method_name, *args, &block)
170
+ public_send("#{'unsafe_' if unsafe}#{method_name}", *args, &block)
171
+ end
152
172
  end
153
173
  end
@@ -5,13 +5,8 @@ require 'ably/modules/event_emitter'
5
5
 
6
6
  require 'ably/realtime/channel'
7
7
  require 'ably/realtime/channels'
8
- require 'ably/realtime/channel/channel_manager'
9
- require 'ably/realtime/channel/channel_state_machine'
10
8
  require 'ably/realtime/client'
11
9
  require 'ably/realtime/connection'
12
- require 'ably/realtime/connection/connection_manager'
13
- require 'ably/realtime/connection/connection_state_machine'
14
- require 'ably/realtime/connection/websocket_transport'
15
10
  require 'ably/realtime/presence'
16
11
 
17
12
  Dir.glob(File.expand_path("models/*.rb", File.dirname(__FILE__))).each do |file|
@@ -33,6 +33,7 @@ module Ably
33
33
  include Ably::Modules::EventEmitter
34
34
  include Ably::Modules::EventMachineHelpers
35
35
  include Ably::Modules::AsyncWrapper
36
+ include Ably::Modules::MessageEmitter
36
37
  extend Ably::Modules::Enum
37
38
 
38
39
  STATE = ruby_enum('STATE',
@@ -84,7 +85,6 @@ module Ably
84
85
  @client = client
85
86
  @name = name
86
87
  @options = channel_options.clone.freeze
87
- @subscriptions = Hash.new { |hash, key| hash[key] = [] }
88
88
  @queue = []
89
89
 
90
90
  @state_machine = ChannelStateMachine.new(self)
@@ -92,6 +92,7 @@ module Ably
92
92
  @manager = ChannelManager.new(self, client.connection)
93
93
 
94
94
  setup_event_handlers
95
+ setup_presence
95
96
  end
96
97
 
97
98
  # Publish a message on the channel
@@ -123,33 +124,25 @@ module Ably
123
124
 
124
125
  # Subscribe to messages matching providing event name, or all messages if event name not provided
125
126
  #
126
- # @param name [String] The event name of the message to subscribe to if provided. Defaults to all events.
127
+ # @param names [String] The event name of the message to subscribe to if provided. Defaults to all events.
127
128
  # @yield [Ably::Models::Message] For each message received, the block is called
128
129
  #
129
130
  # @return [void]
130
131
  #
131
- def subscribe(name = :all, &callback)
132
+ def subscribe(*names, &callback)
132
133
  attach unless attached? || attaching?
133
- subscriptions[message_name_key(name)] << callback
134
+ super
134
135
  end
135
136
 
136
137
  # Unsubscribe the matching block for messages matching providing event name, or all messages if event name not provided.
137
138
  # If a block is not provided, all subscriptions will be unsubscribed
138
139
  #
139
- # @param name [String] The event name of the message to subscribe to if provided. Defaults to all events.
140
+ # @param names [String] The event name of the message to subscribe to if provided. Defaults to all events.
140
141
  #
141
142
  # @return [void]
142
143
  #
143
- def unsubscribe(name = :all, &callback)
144
- if message_name_key(name) == :all
145
- subscriptions.keys
146
- else
147
- Array(message_name_key(name))
148
- end.each do |key|
149
- subscriptions[key].delete_if do |block|
150
- !block_given? || callback == block
151
- end
152
- end
144
+ def unsubscribe(*names, &callback)
145
+ super
153
146
  end
154
147
 
155
148
  # Attach to this channel, and call the block if provided when attached.
@@ -157,7 +150,7 @@ module Ably
157
150
  # to need to call attach explicitly.
158
151
  #
159
152
  # @yield [Ably::Realtime::Channel] Block is called as soon as this channel is in the Attached state
160
- # @return [EventMachine::Deferrable] Deferrable that supports both success (callback) and failure (errback) callback
153
+ # @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callback
161
154
  #
162
155
  def attach(&success_block)
163
156
  transition_state_machine :attaching if can_transition_to?(:attaching)
@@ -183,7 +176,7 @@ module Ably
183
176
  #
184
177
  def presence
185
178
  attach if initialized?
186
- @presence ||= Presence.new(self)
179
+ @presence
187
180
  end
188
181
 
189
182
  # Return the message history of the channel
@@ -193,7 +186,7 @@ module Ably
193
186
  #
194
187
  # @yield [Ably::Models::PaginatedResource<Ably::Models::Message>] An Array of {Ably::Models::Message} objects that supports paging (#next_page, #first_page)
195
188
  #
196
- # @return [EventMachine::Deferrable]
189
+ # @return [Ably::Util::SafeDeferrable]
197
190
  def history(options = {}, &callback)
198
191
  async_wrap(callback) do
199
192
  rest_channel.history(options.merge(async_blocking_operations: true))
@@ -214,6 +207,11 @@ module Ably
214
207
  @error_reason = error
215
208
  end
216
209
 
210
+ # @api private
211
+ def clear_error_reason
212
+ @error_reason = nil
213
+ end
214
+
217
215
  # Used by {Ably::Modules::StateEmitter} to debug state changes
218
216
  # @api private
219
217
  def logger
@@ -221,14 +219,12 @@ module Ably
221
219
  end
222
220
 
223
221
  private
224
- attr_reader :queue, :subscriptions
222
+ attr_reader :queue
225
223
 
226
224
  def setup_event_handlers
227
225
  __incoming_msgbus__.subscribe(:message) do |message|
228
226
  message.decode self
229
-
230
- subscriptions[:all].each { |cb| cb.call(message) }
231
- subscriptions[message.name].each { |cb| cb.call(message) }
227
+ emit_message message.name, message
232
228
  end
233
229
 
234
230
  on(STATE.Attached) do
@@ -273,7 +269,7 @@ module Ably
273
269
  message.merge!(data: data) unless data.nil?
274
270
  message.merge!(clientId: client.client_id) if client.client_id
275
271
 
276
- Ably::Models::Message.new(message, nil).tap do |message|
272
+ Ably::Models::Message.new(message, logger: logger).tap do |message|
277
273
  message.encode self
278
274
  end
279
275
  end
@@ -286,13 +282,12 @@ module Ably
286
282
  client.connection
287
283
  end
288
284
 
289
- def message_name_key(name)
290
- if name == :all
291
- :all
292
- else
293
- name.to_s
294
- end
285
+ def setup_presence
286
+ @presence ||= Presence.new(self)
295
287
  end
296
288
  end
297
289
  end
298
290
  end
291
+
292
+ require 'ably/realtime/channel/channel_manager'
293
+ require 'ably/realtime/channel/channel_state_machine'
@@ -13,13 +13,7 @@ module Ably::Realtime
13
13
  @channel = channel
14
14
  @connection = connection
15
15
 
16
- connection.on(:closed) do
17
- channel.transition_state_machine :detaching if can_transition_to?(:detaching)
18
- end
19
-
20
- connection.on(:failed) do |error|
21
- channel.transition_state_machine :failed, error if can_transition_to?(:failed)
22
- end
16
+ setup_connection_event_handlers
23
17
  end
24
18
 
25
19
  # Commence attachment
@@ -39,12 +33,12 @@ module Ably::Realtime
39
33
  end
40
34
  end
41
35
 
42
- # Commence presence SYNC if applicable
43
- def sync(attached_protocol_message)
36
+ # Channel is attached, notify presence if sync is expected
37
+ def attached(attached_protocol_message)
44
38
  if attached_protocol_message.has_presence_flag?
45
- channel.presence.sync_started
39
+ channel.presence.manager.sync_expected
46
40
  else
47
- channel.presence.sync_completed
41
+ channel.presence.manager.sync_not_expected
48
42
  end
49
43
  end
50
44
 
@@ -59,6 +53,45 @@ module Ably::Realtime
59
53
  channel.transition_state_machine! :detaching, error
60
54
  end
61
55
 
56
+ # When a channel is no longer attached or has failed,
57
+ # all messages awaiting an ACK response should fail immediately
58
+ def fail_messages_awaiting_ack(error)
59
+ # Allow a short time for other queued operations to complete before failing all messages
60
+ EventMachine.add_timer(0.1) do
61
+ error = Ably::Exceptions::MessageDeliveryError.new('Channel is no longer in a state suitable to deliver this message to the server') unless error
62
+ fail_messages_in_queue connection.__pending_message_ack_queue__, error
63
+ fail_messages_in_queue connection.__outgoing_message_queue__, error
64
+ end
65
+ end
66
+
67
+ def fail_messages_in_queue(queue, error)
68
+ queue.delete_if do |protocol_message|
69
+ if protocol_message.channel == channel.name
70
+ nack_messages protocol_message, error
71
+ true
72
+ end
73
+ end
74
+ end
75
+
76
+ def nack_messages(protocol_message, error)
77
+ (protocol_message.messages + protocol_message.presence).each do |message|
78
+ logger.debug "Calling NACK failure callbacks for #{message.class.name} - #{message.to_json}, protocol message: #{protocol_message}"
79
+ message.fail message, error
80
+ end
81
+ logger.debug "Calling NACK failure callbacks for #{protocol_message.class.name} - #{protocol_message.to_json}"
82
+ protocol_message.fail protocol_message, error
83
+ end
84
+
85
+ def drop_pending_queue_from_ack(ack_protocol_message)
86
+ message_serial_up_to = ack_protocol_message.message_serial + ack_protocol_message.count - 1
87
+ connection.__pending_message_ack_queue__.drop_while do |protocol_message|
88
+ if protocol_message.message_serial <= message_serial_up_to
89
+ yield protocol_message
90
+ true
91
+ end
92
+ end
93
+ end
94
+
62
95
  private
63
96
 
64
97
  attr_reader :channel, :connection
@@ -84,6 +117,16 @@ module Ably::Realtime
84
117
  )
85
118
  end
86
119
 
120
+ def setup_connection_event_handlers
121
+ connection.unsafe_on(:closed) do
122
+ channel.transition_state_machine :detaching if can_transition_to?(:detaching)
123
+ end
124
+
125
+ connection.unsafe_on(:failed) do |error|
126
+ channel.transition_state_machine :failed, error if can_transition_to?(:failed)
127
+ end
128
+ end
129
+
87
130
  def logger
88
131
  connection.logger
89
132
  end
@@ -35,7 +35,7 @@ module Ably::Realtime
35
35
  end
36
36
 
37
37
  before_transition(to: [:attached]) do |channel, current_transition|
38
- channel.manager.sync current_transition.metadata
38
+ channel.manager.attached current_transition.metadata
39
39
  end
40
40
 
41
41
  after_transition(to: [:detaching]) do |channel, current_transition|
@@ -43,17 +43,31 @@ module Ably::Realtime
43
43
  end
44
44
 
45
45
  after_transition(to: [:detached]) do |channel, current_transition|
46
- channel.manager.emit_error current_transition.metadata if current_transition.metadata
46
+ channel.manager.fail_messages_awaiting_ack nil_unless_error(current_transition.metadata)
47
+ channel.manager.emit_error current_transition.metadata if is_error_type?(current_transition.metadata)
47
48
  end
48
49
 
49
50
  after_transition(to: [:failed]) do |channel, current_transition|
50
- channel.manager.emit_error current_transition.metadata
51
+ channel.manager.fail_messages_awaiting_ack nil_unless_error(current_transition.metadata)
52
+ channel.manager.emit_error current_transition.metadata if is_error_type?(current_transition.metadata)
51
53
  end
52
54
 
53
55
  # Transitions responsible for updating channel#error_reason
54
- before_transition(to: [:attached, :detached, :failed]) do |channel, current_transition|
55
- reason = current_transition.metadata if is_error_type?(current_transition.metadata)
56
- channel.set_failed_channel_error_reason reason
56
+ before_transition(to: [:failed]) do |channel, current_transition|
57
+ channel.set_failed_channel_error_reason current_transition.metadata if is_error_type?(current_transition.metadata)
58
+ end
59
+
60
+ before_transition(to: [:attached, :detached]) do |channel, current_transition|
61
+ if is_error_type?(current_transition.metadata)
62
+ channel.set_failed_channel_error_reason current_transition.metadata
63
+ else
64
+ # Attached & Detached are "healthy" final states so reset the error reason
65
+ channel.clear_error_reason
66
+ end
67
+ end
68
+
69
+ def self.nil_unless_error(error_object)
70
+ error_object if is_error_type?(error_object)
57
71
  end
58
72
 
59
73
  private
@@ -61,6 +75,7 @@ module Ably::Realtime
61
75
  object
62
76
  end
63
77
 
78
+ # Logged needs to be defined as it is used by {Ably::Modules::StateMachine}
64
79
  def logger
65
80
  channel.logger
66
81
  end