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