ably 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.ruby-version.old +1 -0
- data/.travis.yml +0 -2
- data/Rakefile +22 -4
- data/SPEC.md +1676 -0
- data/ably.gemspec +1 -1
- data/lib/ably.rb +0 -8
- data/lib/ably/auth.rb +54 -46
- data/lib/ably/exceptions.rb +19 -5
- data/lib/ably/logger.rb +1 -1
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +11 -9
- data/lib/ably/models/message.rb +15 -12
- data/lib/ably/models/message_encoders/base.rb +6 -5
- data/lib/ably/models/message_encoders/base64.rb +1 -0
- data/lib/ably/models/message_encoders/cipher.rb +6 -3
- data/lib/ably/models/message_encoders/json.rb +1 -0
- data/lib/ably/models/message_encoders/utf8.rb +2 -9
- data/lib/ably/models/nil_logger.rb +20 -0
- data/lib/ably/models/paginated_resource.rb +5 -2
- data/lib/ably/models/presence_message.rb +21 -12
- data/lib/ably/models/protocol_message.rb +22 -6
- data/lib/ably/modules/ably.rb +11 -0
- data/lib/ably/modules/async_wrapper.rb +2 -0
- data/lib/ably/modules/conversions.rb +23 -3
- data/lib/ably/modules/encodeable.rb +2 -1
- data/lib/ably/modules/enum.rb +2 -0
- data/lib/ably/modules/event_emitter.rb +7 -1
- data/lib/ably/modules/event_machine_helpers.rb +2 -0
- data/lib/ably/modules/http_helpers.rb +2 -0
- data/lib/ably/modules/model_common.rb +12 -2
- data/lib/ably/modules/state_emitter.rb +76 -0
- data/lib/ably/modules/state_machine.rb +53 -0
- data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/ably/realtime.rb +4 -2
- data/lib/ably/realtime/channel.rb +51 -58
- data/lib/ably/realtime/channel/channel_manager.rb +91 -0
- data/lib/ably/realtime/channel/channel_state_machine.rb +68 -0
- data/lib/ably/realtime/client.rb +70 -26
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +31 -13
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/ably/realtime/connection.rb +135 -92
- data/lib/ably/realtime/connection/connection_manager.rb +216 -33
- data/lib/ably/realtime/connection/connection_state_machine.rb +30 -73
- data/lib/ably/realtime/models/nil_channel.rb +10 -1
- data/lib/ably/realtime/presence.rb +336 -92
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +13 -4
- data/lib/ably/rest/client.rb +138 -38
- data/lib/ably/rest/middleware/logger.rb +24 -3
- data/lib/ably/rest/presence.rb +12 -7
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +101 -85
- data/spec/acceptance/realtime/channel_spec.rb +461 -120
- data/spec/acceptance/realtime/client_spec.rb +119 -0
- data/spec/acceptance/realtime/connection_failures_spec.rb +499 -0
- data/spec/acceptance/realtime/connection_spec.rb +571 -97
- data/spec/acceptance/realtime/message_spec.rb +347 -333
- data/spec/acceptance/realtime/presence_history_spec.rb +35 -40
- data/spec/acceptance/realtime/presence_spec.rb +769 -239
- data/spec/acceptance/realtime/stats_spec.rb +14 -22
- data/spec/acceptance/realtime/time_spec.rb +16 -20
- data/spec/acceptance/rest/auth_spec.rb +425 -364
- data/spec/acceptance/rest/base_spec.rb +108 -176
- data/spec/acceptance/rest/channel_spec.rb +89 -89
- data/spec/acceptance/rest/channels_spec.rb +30 -32
- data/spec/acceptance/rest/client_spec.rb +273 -0
- data/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/spec/acceptance/rest/message_spec.rb +186 -163
- data/spec/acceptance/rest/presence_spec.rb +150 -111
- data/spec/acceptance/rest/stats_spec.rb +45 -40
- data/spec/acceptance/rest/time_spec.rb +8 -10
- data/spec/rspec_config.rb +10 -1
- data/spec/shared/client_initializer_behaviour.rb +212 -0
- data/spec/{support/model_helper.rb → shared/model_behaviour.rb} +6 -6
- data/spec/{support/protocol_msgbus_helper.rb → shared/protocol_msgbus_behaviour.rb} +1 -1
- data/spec/spec_helper.rb +9 -0
- data/spec/support/api_helper.rb +11 -0
- data/spec/support/event_machine_helper.rb +101 -3
- data/spec/support/markdown_spec_formatter.rb +90 -0
- data/spec/support/private_api_formatter.rb +36 -0
- data/spec/support/protocol_helper.rb +32 -0
- data/spec/support/random_helper.rb +15 -0
- data/spec/support/test_app.rb +4 -0
- data/spec/unit/auth_spec.rb +68 -0
- data/spec/unit/logger_spec.rb +77 -66
- data/spec/unit/models/error_info_spec.rb +1 -1
- data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +2 -3
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -2
- data/spec/unit/models/message_encoders/cipher_spec.rb +2 -2
- data/spec/unit/models/message_encoders/utf8_spec.rb +2 -46
- data/spec/unit/models/message_spec.rb +160 -15
- data/spec/unit/models/paginated_resource_spec.rb +29 -27
- data/spec/unit/models/presence_message_spec.rb +163 -20
- data/spec/unit/models/protocol_message_spec.rb +43 -8
- data/spec/unit/modules/async_wrapper_spec.rb +2 -3
- data/spec/unit/modules/conversions_spec.rb +1 -1
- data/spec/unit/modules/enum_spec.rb +2 -3
- data/spec/unit/modules/event_emitter_spec.rb +62 -5
- data/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/spec/unit/realtime/channel_spec.rb +107 -2
- data/spec/unit/realtime/channels_spec.rb +1 -0
- data/spec/unit/realtime/client_spec.rb +8 -48
- data/spec/unit/realtime/connection_spec.rb +3 -3
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +2 -2
- data/spec/unit/realtime/presence_spec.rb +13 -4
- data/spec/unit/realtime/realtime_spec.rb +0 -11
- data/spec/unit/realtime/websocket_transport_spec.rb +2 -2
- data/spec/unit/rest/channel_spec.rb +109 -0
- data/spec/unit/rest/channels_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +30 -125
- data/spec/unit/rest/rest_spec.rb +10 -0
- data/spec/unit/util/crypto_spec.rb +10 -5
- data/spec/unit/util/pub_sub_spec.rb +5 -5
- metadata +44 -12
- data/spec/integration/modules/state_emitter_spec.rb +0 -80
- data/spec/integration/rest/auth.rb +0 -9
@@ -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
|