ably 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.ruby-version.old +1 -0
- data/.travis.yml +0 -2
- data/Rakefile +22 -4
- data/SPEC.md +1676 -0
- data/ably.gemspec +1 -1
- data/lib/ably.rb +0 -8
- data/lib/ably/auth.rb +54 -46
- data/lib/ably/exceptions.rb +19 -5
- data/lib/ably/logger.rb +1 -1
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +11 -9
- data/lib/ably/models/message.rb +15 -12
- data/lib/ably/models/message_encoders/base.rb +6 -5
- data/lib/ably/models/message_encoders/base64.rb +1 -0
- data/lib/ably/models/message_encoders/cipher.rb +6 -3
- data/lib/ably/models/message_encoders/json.rb +1 -0
- data/lib/ably/models/message_encoders/utf8.rb +2 -9
- data/lib/ably/models/nil_logger.rb +20 -0
- data/lib/ably/models/paginated_resource.rb +5 -2
- data/lib/ably/models/presence_message.rb +21 -12
- data/lib/ably/models/protocol_message.rb +22 -6
- data/lib/ably/modules/ably.rb +11 -0
- data/lib/ably/modules/async_wrapper.rb +2 -0
- data/lib/ably/modules/conversions.rb +23 -3
- data/lib/ably/modules/encodeable.rb +2 -1
- data/lib/ably/modules/enum.rb +2 -0
- data/lib/ably/modules/event_emitter.rb +7 -1
- data/lib/ably/modules/event_machine_helpers.rb +2 -0
- data/lib/ably/modules/http_helpers.rb +2 -0
- data/lib/ably/modules/model_common.rb +12 -2
- data/lib/ably/modules/state_emitter.rb +76 -0
- data/lib/ably/modules/state_machine.rb +53 -0
- data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/ably/realtime.rb +4 -2
- data/lib/ably/realtime/channel.rb +51 -58
- data/lib/ably/realtime/channel/channel_manager.rb +91 -0
- data/lib/ably/realtime/channel/channel_state_machine.rb +68 -0
- data/lib/ably/realtime/client.rb +70 -26
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +31 -13
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/ably/realtime/connection.rb +135 -92
- data/lib/ably/realtime/connection/connection_manager.rb +216 -33
- data/lib/ably/realtime/connection/connection_state_machine.rb +30 -73
- data/lib/ably/realtime/models/nil_channel.rb +10 -1
- data/lib/ably/realtime/presence.rb +336 -92
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +13 -4
- data/lib/ably/rest/client.rb +138 -38
- data/lib/ably/rest/middleware/logger.rb +24 -3
- data/lib/ably/rest/presence.rb +12 -7
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +101 -85
- data/spec/acceptance/realtime/channel_spec.rb +461 -120
- data/spec/acceptance/realtime/client_spec.rb +119 -0
- data/spec/acceptance/realtime/connection_failures_spec.rb +499 -0
- data/spec/acceptance/realtime/connection_spec.rb +571 -97
- data/spec/acceptance/realtime/message_spec.rb +347 -333
- data/spec/acceptance/realtime/presence_history_spec.rb +35 -40
- data/spec/acceptance/realtime/presence_spec.rb +769 -239
- data/spec/acceptance/realtime/stats_spec.rb +14 -22
- data/spec/acceptance/realtime/time_spec.rb +16 -20
- data/spec/acceptance/rest/auth_spec.rb +425 -364
- data/spec/acceptance/rest/base_spec.rb +108 -176
- data/spec/acceptance/rest/channel_spec.rb +89 -89
- data/spec/acceptance/rest/channels_spec.rb +30 -32
- data/spec/acceptance/rest/client_spec.rb +273 -0
- data/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/spec/acceptance/rest/message_spec.rb +186 -163
- data/spec/acceptance/rest/presence_spec.rb +150 -111
- data/spec/acceptance/rest/stats_spec.rb +45 -40
- data/spec/acceptance/rest/time_spec.rb +8 -10
- data/spec/rspec_config.rb +10 -1
- data/spec/shared/client_initializer_behaviour.rb +212 -0
- data/spec/{support/model_helper.rb → shared/model_behaviour.rb} +6 -6
- data/spec/{support/protocol_msgbus_helper.rb → shared/protocol_msgbus_behaviour.rb} +1 -1
- data/spec/spec_helper.rb +9 -0
- data/spec/support/api_helper.rb +11 -0
- data/spec/support/event_machine_helper.rb +101 -3
- data/spec/support/markdown_spec_formatter.rb +90 -0
- data/spec/support/private_api_formatter.rb +36 -0
- data/spec/support/protocol_helper.rb +32 -0
- data/spec/support/random_helper.rb +15 -0
- data/spec/support/test_app.rb +4 -0
- data/spec/unit/auth_spec.rb +68 -0
- data/spec/unit/logger_spec.rb +77 -66
- data/spec/unit/models/error_info_spec.rb +1 -1
- data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +2 -3
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -2
- data/spec/unit/models/message_encoders/cipher_spec.rb +2 -2
- data/spec/unit/models/message_encoders/utf8_spec.rb +2 -46
- data/spec/unit/models/message_spec.rb +160 -15
- data/spec/unit/models/paginated_resource_spec.rb +29 -27
- data/spec/unit/models/presence_message_spec.rb +163 -20
- data/spec/unit/models/protocol_message_spec.rb +43 -8
- data/spec/unit/modules/async_wrapper_spec.rb +2 -3
- data/spec/unit/modules/conversions_spec.rb +1 -1
- data/spec/unit/modules/enum_spec.rb +2 -3
- data/spec/unit/modules/event_emitter_spec.rb +62 -5
- data/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/spec/unit/realtime/channel_spec.rb +107 -2
- data/spec/unit/realtime/channels_spec.rb +1 -0
- data/spec/unit/realtime/client_spec.rb +8 -48
- data/spec/unit/realtime/connection_spec.rb +3 -3
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +2 -2
- data/spec/unit/realtime/presence_spec.rb +13 -4
- data/spec/unit/realtime/realtime_spec.rb +0 -11
- data/spec/unit/realtime/websocket_transport_spec.rb +2 -2
- data/spec/unit/rest/channel_spec.rb +109 -0
- data/spec/unit/rest/channels_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +30 -125
- data/spec/unit/rest/rest_spec.rb +10 -0
- data/spec/unit/util/crypto_spec.rb +10 -5
- data/spec/unit/util/pub_sub_spec.rb +5 -5
- metadata +44 -12
- data/spec/integration/modules/state_emitter_spec.rb +0 -80
- data/spec/integration/rest/auth.rb +0 -9
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'statesman'
|
2
|
+
require 'ably/modules/statesman_monkey_patch'
|
3
|
+
|
4
|
+
module Ably::Modules
|
5
|
+
# Module providing Statesman StateMachine functionality
|
6
|
+
#
|
7
|
+
# Expects method #logger to be defined
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
module StateMachine
|
11
|
+
def self.included(klass)
|
12
|
+
klass.class_eval do
|
13
|
+
include Statesman::Machine
|
14
|
+
end
|
15
|
+
klass.extend Ably::Modules::StatesmanMonkeyPatch
|
16
|
+
end
|
17
|
+
|
18
|
+
# Alternative to Statesman's #transition_to that:
|
19
|
+
# * log state change failures to {Logger}
|
20
|
+
# * raise an exception on the {Ably::Realtime::Channel}
|
21
|
+
#
|
22
|
+
# @return [void]
|
23
|
+
def transition_state(state, *args)
|
24
|
+
unless result = transition_to(state, *args)
|
25
|
+
exception = exception_for_state_change_to(state)
|
26
|
+
object.trigger :error, exception
|
27
|
+
logger.fatal "#{self.class}: #{exception.message}"
|
28
|
+
end
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Statesman History Object]
|
33
|
+
def previous_transition
|
34
|
+
history[-2]
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Symbol]
|
38
|
+
def previous_state
|
39
|
+
previous_transition.to_state if previous_transition
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Ably::Exceptions::StateChangeError]
|
43
|
+
def exception_for_state_change_to(state)
|
44
|
+
error_message = "#{self.class}: Unable to transition from #{current_state} => #{state}"
|
45
|
+
Ably::Exceptions::StateChangeError.new(error_message, nil, 80020)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def self.is_error_type?(error)
|
50
|
+
error.kind_of?(Ably::Models::ErrorInfo) || error.kind_of?(StandardError)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Ably::Modules
|
2
|
+
# @api private
|
3
|
+
module StatesmanMonkeyPatch
|
4
|
+
# Override Statesman's #before_transition to support :from arrays
|
5
|
+
# This can be removed once https://github.com/gocardless/statesman/issues/95 is solved
|
6
|
+
def before_transition(options = nil, &block)
|
7
|
+
arrayify_transition(options) do |options_without_from_array|
|
8
|
+
super *options_without_from_array, &block
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Override Statesman's #after_transition to support :from arrays
|
13
|
+
# This can be removed once https://github.com/gocardless/statesman/issues/95 is solved
|
14
|
+
def after_transition(options = nil, &block)
|
15
|
+
arrayify_transition(options) do |options_without_from_array|
|
16
|
+
super *options_without_from_array, &block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def arrayify_transition(options, &block)
|
22
|
+
if options.nil?
|
23
|
+
yield []
|
24
|
+
elsif options.fetch(:from, nil).kind_of?(Array)
|
25
|
+
options[:from].each do |from_state|
|
26
|
+
yield [options.merge(from: from_state)]
|
27
|
+
end
|
28
|
+
else
|
29
|
+
yield [options]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Ably::Modules
|
2
|
+
# Mixing module that assists with {https://github.com/gocardless/statesman Statemans State Machine} state transitions
|
3
|
+
# and maintaining state of this object's #state.
|
4
|
+
#
|
5
|
+
# Expects:
|
6
|
+
# - @state_machine is set to the StateMachine
|
7
|
+
# - StateEmitter is included in the object
|
8
|
+
#
|
9
|
+
module UsesStateMachine
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
# Call #transition_to on the StateMachine
|
13
|
+
#
|
14
|
+
# @return [Boolean] true if new_state can be transitioned to by state machine
|
15
|
+
# @api private
|
16
|
+
def transition_state_machine(new_state, emit_object = nil)
|
17
|
+
state_machine.transition_state(new_state, emit_object)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Call #transition_to! on the StateMachine
|
21
|
+
# An exception wil be raised if new_state cannot be transitioned to by state machine
|
22
|
+
#
|
23
|
+
# @return [void]
|
24
|
+
# @api private
|
25
|
+
def transition_state_machine!(new_state, emit_object = nil)
|
26
|
+
state_machine.transition_to!(new_state, emit_object)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Provides an internal method for this object's state to match the StateMachine's current state.
|
30
|
+
# The current object's state will be changed to the StateMachine state and will emit an event
|
31
|
+
# @api private
|
32
|
+
def synchronize_state_with_statemachine(*args)
|
33
|
+
log_state_machine_state_change
|
34
|
+
change_state state_machine.current_state, state_machine.last_transition.metadata
|
35
|
+
end
|
36
|
+
|
37
|
+
# @!attribute [r] previous_state
|
38
|
+
# @return [STATE,nil] The previous state for this connection
|
39
|
+
# @api private
|
40
|
+
def previous_state
|
41
|
+
if state_machine.previous_state
|
42
|
+
STATE(state_machine.previous_state)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @!attribute [r] state_history
|
47
|
+
# @return [Array<Hash>] All previous states including the current state in date ascending order with Hash properties :state, :metadata, :transitioned_at
|
48
|
+
# @api private
|
49
|
+
def state_history
|
50
|
+
state_machine.history.map do |transition|
|
51
|
+
{
|
52
|
+
state: STATE(transition.to_state),
|
53
|
+
metadata: transition.metadata,
|
54
|
+
transitioned_at: transition.created_at
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def_delegators :state_machine, :can_transition_to?
|
60
|
+
|
61
|
+
private
|
62
|
+
attr_reader :state_machine
|
63
|
+
|
64
|
+
def_delegators :state_machine, :exception_for_state_change_to
|
65
|
+
|
66
|
+
def log_state_machine_state_change
|
67
|
+
if state_machine.previous_state
|
68
|
+
logger.debug "#{self.class.name}: Transitioned from #{state_machine.previous_state} => #{state_machine.current_state}"
|
69
|
+
else
|
70
|
+
logger.debug "#{self.class.name}: Transitioned to #{state_machine.current_state}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/ably/realtime.rb
CHANGED
@@ -5,6 +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'
|
8
10
|
require 'ably/realtime/client'
|
9
11
|
require 'ably/realtime/connection'
|
10
12
|
require 'ably/realtime/connection/connection_manager'
|
@@ -55,8 +57,8 @@ module Ably
|
|
55
57
|
# # create a new client authenticating with basic auth and a client_id
|
56
58
|
# client = Ably::Realtime.new(api_key: 'key.id:secret', client_id: 'john')
|
57
59
|
#
|
58
|
-
def self.new(options, &
|
59
|
-
Ably::Realtime::Client.new(options, &
|
60
|
+
def self.new(options, &token_request_block)
|
61
|
+
Ably::Realtime::Client.new(options, &token_request_block)
|
60
62
|
end
|
61
63
|
end
|
62
64
|
end
|
@@ -23,14 +23,10 @@ module Ably
|
|
23
23
|
# Channel::STATE.Detached
|
24
24
|
# Channel::STATE.Failed
|
25
25
|
#
|
26
|
+
# Channels emit errors - use `on(:error)` to subscribe to errors
|
27
|
+
#
|
26
28
|
# @!attribute [r] state
|
27
29
|
# @return {Ably::Realtime::Connection::STATE} channel state
|
28
|
-
# @!attribute [r] client
|
29
|
-
# @return {Ably::Realtime::Client} Ably client associated with this channel
|
30
|
-
# @!attribute [r] name
|
31
|
-
# @return {String} channel name
|
32
|
-
# @!attribute [r] options
|
33
|
-
# @return {Hash} channel options configured for this channel, see {#initialize} for channel_options
|
34
30
|
#
|
35
31
|
class Channel
|
36
32
|
include Ably::Modules::Conversions
|
@@ -48,11 +44,31 @@ module Ably
|
|
48
44
|
:failed
|
49
45
|
)
|
50
46
|
include Ably::Modules::StateEmitter
|
47
|
+
include Ably::Modules::UsesStateMachine
|
51
48
|
|
52
49
|
# Max number of messages to bundle in a single ProtocolMessage
|
53
50
|
MAX_PROTOCOL_MESSAGE_BATCH_SIZE = 50
|
54
51
|
|
55
|
-
|
52
|
+
# {Ably::Realtime::Client} associated with this channel
|
53
|
+
# @return [Ably::Realtime::Client]
|
54
|
+
attr_reader :client
|
55
|
+
|
56
|
+
# Channel name
|
57
|
+
# @return [String]
|
58
|
+
attr_reader :name
|
59
|
+
|
60
|
+
# Channel options configured for this channel, see {#initialize} for channel_options
|
61
|
+
# @return [Hash]
|
62
|
+
attr_reader :options
|
63
|
+
|
64
|
+
# When a channel failure occurs this attribute contains the Ably Exception
|
65
|
+
# @return [Ably::Models::ErrorInfo,Ably::Exceptions::BaseAblyException]
|
66
|
+
attr_reader :error_reason
|
67
|
+
|
68
|
+
# The Channel manager responsible for attaching, detaching and handling failures for this channel
|
69
|
+
# @return [Ably::Realtime::Channel::ChannelManager]
|
70
|
+
# @api private
|
71
|
+
attr_reader :manager
|
56
72
|
|
57
73
|
# Initialize a new Channel object
|
58
74
|
#
|
@@ -63,12 +79,17 @@ module Ably
|
|
63
79
|
# @option channel_options [Hash] :cipher_params A hash of options to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of `cipher_params` options
|
64
80
|
#
|
65
81
|
def initialize(client, name, channel_options = {})
|
82
|
+
ensure_utf_8 :name, name
|
83
|
+
|
66
84
|
@client = client
|
67
85
|
@name = name
|
68
86
|
@options = channel_options.clone.freeze
|
69
87
|
@subscriptions = Hash.new { |hash, key| hash[key] = [] }
|
70
88
|
@queue = []
|
71
|
-
|
89
|
+
|
90
|
+
@state_machine = ChannelStateMachine.new(self)
|
91
|
+
@state = STATE(state_machine.current_state)
|
92
|
+
@manager = ChannelManager.new(self, client.connection)
|
72
93
|
|
73
94
|
setup_event_handlers
|
74
95
|
end
|
@@ -91,9 +112,11 @@ module Ably
|
|
91
112
|
# puts "#{message.name} was not received, error #{error.message}"
|
92
113
|
# end
|
93
114
|
#
|
94
|
-
def publish(name, data, &
|
115
|
+
def publish(name, data, &success_block)
|
116
|
+
ensure_utf_8 :name, name
|
117
|
+
|
95
118
|
create_message(name, data).tap do |message|
|
96
|
-
message.callback(&
|
119
|
+
message.callback(&success_block) if block_given?
|
97
120
|
queue_message message
|
98
121
|
end
|
99
122
|
end
|
@@ -105,9 +128,9 @@ module Ably
|
|
105
128
|
#
|
106
129
|
# @return [void]
|
107
130
|
#
|
108
|
-
def subscribe(name = :all, &
|
131
|
+
def subscribe(name = :all, &callback)
|
109
132
|
attach unless attached? || attaching?
|
110
|
-
subscriptions[message_name_key(name)] <<
|
133
|
+
subscriptions[message_name_key(name)] << callback
|
111
134
|
end
|
112
135
|
|
113
136
|
# Unsubscribe the matching block for messages matching providing event name, or all messages if event name not provided.
|
@@ -117,14 +140,14 @@ module Ably
|
|
117
140
|
#
|
118
141
|
# @return [void]
|
119
142
|
#
|
120
|
-
def unsubscribe(name = :all, &
|
143
|
+
def unsubscribe(name = :all, &callback)
|
121
144
|
if message_name_key(name) == :all
|
122
145
|
subscriptions.keys
|
123
146
|
else
|
124
147
|
Array(message_name_key(name))
|
125
148
|
end.each do |key|
|
126
149
|
subscriptions[key].delete_if do |block|
|
127
|
-
!block_given? ||
|
150
|
+
!block_given? || callback == block
|
128
151
|
end
|
129
152
|
end
|
130
153
|
end
|
@@ -134,18 +157,11 @@ module Ably
|
|
134
157
|
# to need to call attach explicitly.
|
135
158
|
#
|
136
159
|
# @yield [Ably::Realtime::Channel] Block is called as soon as this channel is in the Attached state
|
137
|
-
# @return [
|
160
|
+
# @return [EventMachine::Deferrable] Deferrable that supports both success (callback) and failure (errback) callback
|
138
161
|
#
|
139
|
-
def attach(&
|
140
|
-
if
|
141
|
-
|
142
|
-
else
|
143
|
-
once(STATE.Attached) { block.call self } if block_given?
|
144
|
-
if !attaching?
|
145
|
-
change_state STATE.Attaching
|
146
|
-
send_attach_protocol_message
|
147
|
-
end
|
148
|
-
end
|
162
|
+
def attach(&success_block)
|
163
|
+
transition_state_machine :attaching if can_transition_to?(:attaching)
|
164
|
+
deferrable_for_state_change_to(STATE.Attached, &success_block)
|
149
165
|
end
|
150
166
|
|
151
167
|
# Detach this channel, and call the block if provided when in a Detached or Failed state
|
@@ -153,16 +169,10 @@ module Ably
|
|
153
169
|
# @yield [Ably::Realtime::Channel] Block is called as soon as this channel is in the Detached or Failed state
|
154
170
|
# @return [void]
|
155
171
|
#
|
156
|
-
def detach(&
|
157
|
-
if
|
158
|
-
|
159
|
-
|
160
|
-
once(STATE.Detached, STATE.Failed) { block.call self } if block_given?
|
161
|
-
if !detaching?
|
162
|
-
change_state STATE.Detaching
|
163
|
-
send_detach_protocol_message
|
164
|
-
end
|
165
|
-
end
|
172
|
+
def detach(&success_block)
|
173
|
+
raise exception_for_state_change_to(:detaching) if failed? || initialized?
|
174
|
+
transition_state_machine :detaching if can_transition_to?(:detaching)
|
175
|
+
deferrable_for_state_change_to(STATE.Detached, &success_block)
|
166
176
|
end
|
167
177
|
|
168
178
|
# Presence object for this Channel. This controls this client's
|
@@ -172,6 +182,7 @@ module Ably
|
|
172
182
|
# @return {Ably::Realtime::Presence}
|
173
183
|
#
|
174
184
|
def presence
|
185
|
+
attach if initialized?
|
175
186
|
@presence ||= Presence.new(self)
|
176
187
|
end
|
177
188
|
|
@@ -198,6 +209,11 @@ module Ably
|
|
198
209
|
)
|
199
210
|
end
|
200
211
|
|
212
|
+
# @api private
|
213
|
+
def set_failed_channel_error_reason(error)
|
214
|
+
@error_reason = error
|
215
|
+
end
|
216
|
+
|
201
217
|
private
|
202
218
|
attr_reader :queue, :subscriptions
|
203
219
|
|
@@ -212,14 +228,6 @@ module Ably
|
|
212
228
|
on(STATE.Attached) do
|
213
229
|
process_queue
|
214
230
|
end
|
215
|
-
|
216
|
-
connection.on(Connection::STATE.Closed) do
|
217
|
-
change_state STATE.Detached
|
218
|
-
end
|
219
|
-
|
220
|
-
connection.on(Connection::STATE.Failed) do
|
221
|
-
change_state STATE.Failed unless detached? || initialized?
|
222
|
-
end
|
223
231
|
end
|
224
232
|
|
225
233
|
# Queue message and process queue if channel is attached.
|
@@ -254,21 +262,6 @@ module Ably
|
|
254
262
|
)
|
255
263
|
end
|
256
264
|
|
257
|
-
def send_attach_protocol_message
|
258
|
-
send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Attach
|
259
|
-
end
|
260
|
-
|
261
|
-
def send_detach_protocol_message
|
262
|
-
send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Detach
|
263
|
-
end
|
264
|
-
|
265
|
-
def send_state_change_protocol_message(state)
|
266
|
-
client.connection.send_protocol_message(
|
267
|
-
action: state.to_i,
|
268
|
-
channel: name
|
269
|
-
)
|
270
|
-
end
|
271
|
-
|
272
265
|
def create_message(name, data)
|
273
266
|
message = { name: name }
|
274
267
|
message.merge!(data: data) unless data.nil?
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Ably::Realtime
|
2
|
+
class Channel
|
3
|
+
# ChannelManager is responsible for all actions relating to channel state: attaching, detaching or failure
|
4
|
+
# Channel state changes are performed by this class and executed from {ChannelStateMachine}
|
5
|
+
#
|
6
|
+
# This is a private class and should never be used directly by developers as the API is likely to change in future.
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class ChannelManager
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
def initialize(channel, connection)
|
13
|
+
@channel = channel
|
14
|
+
@connection = connection
|
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
|
23
|
+
|
24
|
+
channel.on(:attached, :detached) do
|
25
|
+
channel.set_failed_channel_error_reason nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Commence attachment
|
30
|
+
def attach
|
31
|
+
if can_transition_to?(:attached)
|
32
|
+
connect_if_connection_initialized
|
33
|
+
send_attach_protocol_message
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Commence attachment
|
38
|
+
def detach
|
39
|
+
if connection.closed?
|
40
|
+
channel.transition_state_machine :detached
|
41
|
+
elsif can_transition_to?(:detached)
|
42
|
+
send_detach_protocol_message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Commence presence SYNC if applicable
|
47
|
+
def sync(attached_protocol_message)
|
48
|
+
if attached_protocol_message.has_presence_flag?
|
49
|
+
channel.presence.sync_started
|
50
|
+
else
|
51
|
+
channel.presence.sync_completed
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Channel has failed
|
56
|
+
def failed(error)
|
57
|
+
logger.error "Channel #{channel.name} error: #{error}"
|
58
|
+
channel.trigger :error, error
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
attr_reader :channel, :connection
|
64
|
+
def_delegators :channel, :can_transition_to?
|
65
|
+
|
66
|
+
# If the connection has not previously connected, connect now
|
67
|
+
def connect_if_connection_initialized
|
68
|
+
connection.connect if connection.initialized?
|
69
|
+
end
|
70
|
+
|
71
|
+
def send_attach_protocol_message
|
72
|
+
send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Attach
|
73
|
+
end
|
74
|
+
|
75
|
+
def send_detach_protocol_message
|
76
|
+
send_state_change_protocol_message Ably::Models::ProtocolMessage::ACTION.Detach
|
77
|
+
end
|
78
|
+
|
79
|
+
def send_state_change_protocol_message(state)
|
80
|
+
connection.send_protocol_message(
|
81
|
+
action: state.to_i,
|
82
|
+
channel: channel.name
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def logger
|
87
|
+
connection.logger
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|