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.
- checksums.yaml +8 -8
- data/.travis.yml +1 -0
- data/SPEC.md +480 -472
- data/lib/ably-rest.rb +1 -1
- data/lib/submodules/ably-ruby/LICENSE.txt +1 -1
- data/lib/submodules/ably-ruby/README.md +107 -24
- data/lib/submodules/ably-ruby/SPEC.md +531 -398
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +24 -16
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +9 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +17 -9
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +12 -8
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +18 -10
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +15 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +4 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +31 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +77 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/safe_deferrable.rb +71 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/safe_yield.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +28 -8
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +0 -5
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +24 -29
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +54 -11
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +21 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +7 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +29 -26
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +4 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +41 -9
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +72 -24
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +26 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +74 -208
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +264 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +59 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +64 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +6 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +3 -1
- data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +18 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +28 -6
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +116 -46
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +55 -10
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +32 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +456 -96
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +96 -7
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +8 -0
- data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +71 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +1 -1
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +1 -1
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +13 -7
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +15 -14
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +17 -17
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +28 -9
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +50 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +76 -2
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +51 -20
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +3 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +52 -26
- data/lib/submodules/ably-ruby/spec/unit/realtime/safe_deferrable_spec.rb +12 -0
- data/spec/spec_helper.rb +5 -0
- metadata +12 -4
- 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 {
|
123
|
-
# success block if provided and {
|
124
|
-
# If the state changes to any other state, the {
|
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
|
-
|
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
|
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(
|
132
|
+
def subscribe(*names, &callback)
|
132
133
|
attach unless attached? || attaching?
|
133
|
-
|
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
|
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(
|
144
|
-
|
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 [
|
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
|
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 [
|
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
|
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,
|
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
|
290
|
-
|
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
|
-
|
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
|
-
#
|
43
|
-
def
|
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.
|
39
|
+
channel.presence.manager.sync_expected
|
46
40
|
else
|
47
|
-
channel.presence.
|
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.
|
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.
|
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.
|
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: [:
|
55
|
-
|
56
|
-
|
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
|