ably 1.0.7 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +14 -0
- data/.travis.yml +4 -4
- data/CHANGELOG.md +26 -3
- data/Rakefile +32 -0
- data/SPEC.md +920 -565
- data/ably.gemspec +9 -4
- data/lib/ably/auth.rb +28 -2
- data/lib/ably/exceptions.rb +8 -2
- data/lib/ably/models/channel_state_change.rb +1 -1
- data/lib/ably/models/connection_state_change.rb +1 -1
- data/lib/ably/models/device_details.rb +87 -0
- data/lib/ably/models/device_push_details.rb +86 -0
- data/lib/ably/models/error_info.rb +23 -2
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -4
- data/lib/ably/models/protocol_message.rb +32 -2
- data/lib/ably/models/push_channel_subscription.rb +89 -0
- data/lib/ably/modules/conversions.rb +1 -1
- data/lib/ably/modules/encodeable.rb +1 -1
- data/lib/ably/modules/exception_codes.rb +128 -0
- data/lib/ably/modules/model_common.rb +15 -2
- data/lib/ably/modules/state_machine.rb +1 -1
- data/lib/ably/realtime.rb +1 -0
- data/lib/ably/realtime/auth.rb +1 -1
- data/lib/ably/realtime/channel.rb +24 -102
- data/lib/ably/realtime/channel/channel_manager.rb +2 -6
- data/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
- data/lib/ably/realtime/channel/publisher.rb +74 -0
- data/lib/ably/realtime/channel/push_channel.rb +62 -0
- data/lib/ably/realtime/client.rb +87 -0
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +6 -2
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/ably/realtime/connection.rb +8 -5
- data/lib/ably/realtime/connection/connection_manager.rb +7 -7
- data/lib/ably/realtime/connection/websocket_transport.rb +1 -1
- data/lib/ably/realtime/presence.rb +4 -4
- data/lib/ably/realtime/presence/members_map.rb +3 -3
- data/lib/ably/realtime/push.rb +40 -0
- data/lib/ably/realtime/push/admin.rb +61 -0
- data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
- data/lib/ably/realtime/push/device_registrations.rb +105 -0
- data/lib/ably/rest.rb +1 -0
- data/lib/ably/rest/channel.rb +33 -5
- data/lib/ably/rest/channel/push_channel.rb +62 -0
- data/lib/ably/rest/client.rb +137 -28
- data/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
- data/lib/ably/rest/presence.rb +1 -0
- data/lib/ably/rest/push.rb +42 -0
- data/lib/ably/rest/push/admin.rb +54 -0
- data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
- data/lib/ably/rest/push/device_registrations.rb +103 -0
- data/lib/ably/version.rb +7 -2
- data/spec/acceptance/realtime/auth_spec.rb +6 -8
- data/spec/acceptance/realtime/channel_spec.rb +166 -51
- data/spec/acceptance/realtime/client_spec.rb +149 -0
- data/spec/acceptance/realtime/connection_failures_spec.rb +1 -1
- data/spec/acceptance/realtime/connection_spec.rb +4 -4
- data/spec/acceptance/realtime/message_spec.rb +19 -17
- data/spec/acceptance/realtime/presence_spec.rb +5 -5
- data/spec/acceptance/realtime/push_admin_spec.rb +696 -0
- data/spec/acceptance/realtime/push_spec.rb +27 -0
- data/spec/acceptance/rest/auth_spec.rb +4 -3
- data/spec/acceptance/rest/base_spec.rb +2 -2
- data/spec/acceptance/rest/client_spec.rb +129 -10
- data/spec/acceptance/rest/message_spec.rb +175 -4
- data/spec/acceptance/rest/push_admin_spec.rb +896 -0
- data/spec/acceptance/rest/push_spec.rb +25 -0
- data/spec/acceptance/rest/time_spec.rb +1 -1
- data/spec/run_parallel_tests +33 -0
- data/spec/unit/logger_spec.rb +10 -3
- data/spec/unit/models/device_details_spec.rb +102 -0
- data/spec/unit/models/device_push_details_spec.rb +101 -0
- data/spec/unit/models/error_info_spec.rb +51 -3
- data/spec/unit/models/message_spec.rb +17 -2
- data/spec/unit/models/presence_message_spec.rb +1 -1
- data/spec/unit/models/push_channel_subscription_spec.rb +86 -0
- data/spec/unit/realtime/client_spec.rb +12 -0
- data/spec/unit/realtime/push_channel_spec.rb +36 -0
- data/spec/unit/rest/channel_spec.rb +8 -1
- data/spec/unit/rest/client_spec.rb +30 -0
- data/spec/unit/rest/push_channel_spec.rb +36 -0
- metadata +71 -8
@@ -0,0 +1,74 @@
|
|
1
|
+
module Ably::Realtime
|
2
|
+
class Channel
|
3
|
+
# Publisher module adds publishing capabilities to the current object
|
4
|
+
module Publisher
|
5
|
+
private
|
6
|
+
|
7
|
+
# Prepare and queue messages on the connection queue immediately
|
8
|
+
# @return [Ably::Util::SafeDeferrable]
|
9
|
+
def enqueue_messages_on_connection(client, raw_messages, channel_name, channel_options = {})
|
10
|
+
messages = Array(raw_messages).map do |raw_msg|
|
11
|
+
create_message(client, raw_msg, channel_options).tap do |message|
|
12
|
+
next if message.client_id.nil?
|
13
|
+
if message.client_id == '*'
|
14
|
+
raise Ably::Exceptions::IncompatibleClientId.new('Wildcard client_id is reserved and cannot be used when publishing messages')
|
15
|
+
end
|
16
|
+
if message.client_id && !message.client_id.kind_of?(String)
|
17
|
+
raise Ably::Exceptions::IncompatibleClientId.new('client_id must be a String when publishing messages')
|
18
|
+
end
|
19
|
+
unless client.auth.can_assume_client_id?(message.client_id)
|
20
|
+
raise Ably::Exceptions::IncompatibleClientId.new("Cannot publish with client_id '#{message.client_id}' as it is incompatible with the current configured client_id '#{client.client_id}'")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
connection.send_protocol_message(
|
26
|
+
action: Ably::Models::ProtocolMessage::ACTION.Message.to_i,
|
27
|
+
channel: channel_name,
|
28
|
+
messages: messages
|
29
|
+
)
|
30
|
+
|
31
|
+
if messages.count == 1
|
32
|
+
# A message is a Deferrable so, if publishing only one message, simply return that Deferrable
|
33
|
+
messages.first
|
34
|
+
else
|
35
|
+
deferrable_for_multiple_messages(messages)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# A deferrable object that calls the success callback once all messages are delivered
|
40
|
+
# If any message fails, the errback is called immediately
|
41
|
+
# Only one callback or errback is ever called i.e. if a group of messages all fail, only once
|
42
|
+
# errback will be invoked
|
43
|
+
def deferrable_for_multiple_messages(messages)
|
44
|
+
expected_deliveries = messages.count
|
45
|
+
actual_deliveries = 0
|
46
|
+
failed = false
|
47
|
+
|
48
|
+
Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
|
49
|
+
messages.each do |message|
|
50
|
+
message.callback do
|
51
|
+
next if failed
|
52
|
+
actual_deliveries += 1
|
53
|
+
deferrable.succeed messages if actual_deliveries == expected_deliveries
|
54
|
+
end
|
55
|
+
message.errback do |error|
|
56
|
+
next if failed
|
57
|
+
failed = true
|
58
|
+
deferrable.fail error, message
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_message(client, message, channel_options)
|
65
|
+
Ably::Models::Message(message.dup).tap do |msg|
|
66
|
+
msg.encode(client.encoders, channel_options) do |encode_error, error_message|
|
67
|
+
client.logger.error error_message
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Ably::Realtime
|
2
|
+
class Channel
|
3
|
+
# A push channel used for push notifications
|
4
|
+
# Each PushChannel maps to exactly one Realtime Channel
|
5
|
+
#
|
6
|
+
# @!attribute [r] channel
|
7
|
+
# @return [Ably::Realtime::Channel] Underlying channel object
|
8
|
+
#
|
9
|
+
class PushChannel
|
10
|
+
attr_reader :channel
|
11
|
+
|
12
|
+
def initialize(channel)
|
13
|
+
raise ArgumentError, "Unsupported channel type '#{channel.class}'" unless channel.kind_of?(Ably::Realtime::Channel)
|
14
|
+
@channel = channel
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"<PushChannel: name=#{channel.name}>"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Subscribe local device for push notifications on this channel
|
22
|
+
#
|
23
|
+
# @note This is unsupported in the Ruby library
|
24
|
+
def subscribe_device(*args)
|
25
|
+
raise_unsupported
|
26
|
+
end
|
27
|
+
|
28
|
+
# Subscribe all devices registered to this client's authenticated client_id for push notifications on this channel
|
29
|
+
#
|
30
|
+
# @note This is unsupported in the Ruby library
|
31
|
+
def subscribe_client_id(*args)
|
32
|
+
raise_unsupported
|
33
|
+
end
|
34
|
+
|
35
|
+
# Unsubscribe local device for push notifications on this channel
|
36
|
+
#
|
37
|
+
# @note This is unsupported in the Ruby library
|
38
|
+
def unsubscribe_device(*args)
|
39
|
+
raise_unsupported
|
40
|
+
end
|
41
|
+
|
42
|
+
# Unsubscribe all devices registered to this client's authenticated client_id for push notifications on this channel
|
43
|
+
#
|
44
|
+
# @note This is unsupported in the Ruby library
|
45
|
+
def unsubscribe_client_id(*args)
|
46
|
+
raise_unsupported
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get list of subscriptions on this channel for this device or authenticate client_id
|
50
|
+
#
|
51
|
+
# @note This is unsupported in the Ruby library
|
52
|
+
def get_subscriptions(*args)
|
53
|
+
raise_unsupported
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def raise_unsupported
|
58
|
+
raise Ably::Exceptions::PushNotificationsNotSupported, 'This device does not support receiving or subscribing to push notifications. All PushChannel methods are unavailable'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/ably/realtime/client.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'ably/realtime/channel/publisher'
|
2
3
|
|
3
4
|
module Ably
|
4
5
|
module Realtime
|
@@ -21,6 +22,9 @@ module Ably
|
|
21
22
|
#
|
22
23
|
class Client
|
23
24
|
include Ably::Modules::AsyncWrapper
|
25
|
+
include Ably::Realtime::Channel::Publisher
|
26
|
+
include Ably::Modules::Conversions
|
27
|
+
|
24
28
|
extend Forwardable
|
25
29
|
|
26
30
|
DOMAIN = 'realtime.ably.io'
|
@@ -38,6 +42,7 @@ module Ably
|
|
38
42
|
|
39
43
|
# The {Ably::Rest::Client REST client} instantiated with the same credentials and configuration that is used for all REST operations such as authentication
|
40
44
|
# @return [Ably::Rest::Client]
|
45
|
+
# @private
|
41
46
|
attr_reader :rest_client
|
42
47
|
|
43
48
|
# When false the client suppresses messages originating from this connection being echoed back on the same connection. Defaults to true
|
@@ -162,6 +167,12 @@ module Ably
|
|
162
167
|
connection.connect(&block)
|
163
168
|
end
|
164
169
|
|
170
|
+
# Push notification object for publishing and managing push notifications
|
171
|
+
# @return [Ably::Realtime::Push]
|
172
|
+
def push
|
173
|
+
@push ||= Push.new(self)
|
174
|
+
end
|
175
|
+
|
165
176
|
# (see Ably::Rest::Client#request)
|
166
177
|
# @yield [Ably::Models::HttpPaginatedResponse<>] An Array of Stats
|
167
178
|
#
|
@@ -172,6 +183,74 @@ module Ably
|
|
172
183
|
end
|
173
184
|
end
|
174
185
|
|
186
|
+
# Publish one or more messages to the specified channel.
|
187
|
+
#
|
188
|
+
# This method allows messages to be efficiently published to Ably without instancing a {Ably::Realtime::Channel} object.
|
189
|
+
# If you want to publish a high rate of messages to Ably without instancing channels or using the REST API, then this method
|
190
|
+
# is recommended. However, channel options such as encryption are not supported with this method. If you need to specify channel options
|
191
|
+
# we recommend you use the {Ably::Realtime::Channel} +publish+ method without attaching to each channel, unless you also want to subscribe
|
192
|
+
# to published messages on that channel.
|
193
|
+
#
|
194
|
+
# Note: This feature is still in beta. As such, we cannot guarantee the API will not change in future.
|
195
|
+
#
|
196
|
+
# @param channel [String] The channel name you want to publish the message(s) to
|
197
|
+
# @param name [String, Array<Ably::Models::Message|Hash>, nil] The event name of the message to publish, or an Array of [Ably::Model::Message] objects or [Hash] objects with +:name+ and +:data+ pairs
|
198
|
+
# @param data [String, ByteArray, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument
|
199
|
+
# @param attributes [Hash, nil] Optional additional message attributes such as :client_id or :connection_id, applied when name attribute is nil or a string
|
200
|
+
#
|
201
|
+
# @yield [Ably::Models::Message,Array<Ably::Models::Message>] On success, will call the block with the {Ably::Models::Message} if a single message is published, or an Array of {Ably::Models::Message} when multiple messages are published
|
202
|
+
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callbacks
|
203
|
+
#
|
204
|
+
# @example
|
205
|
+
# # Publish a single message
|
206
|
+
# client.publish 'activityChannel', click', { x: 1, y: 2 }
|
207
|
+
#
|
208
|
+
# # Publish an array of message Hashes
|
209
|
+
# messages = [
|
210
|
+
# { name: 'click', { x: 1, y: 2 } },
|
211
|
+
# { name: 'click', { x: 2, y: 3 } }
|
212
|
+
# ]
|
213
|
+
# client.publish 'activityChannel', messages
|
214
|
+
#
|
215
|
+
# # Publish an array of Ably::Models::Message objects
|
216
|
+
# messages = [
|
217
|
+
# Ably::Models::Message(name: 'click', { x: 1, y: 2 })
|
218
|
+
# Ably::Models::Message(name: 'click', { x: 2, y: 3 })
|
219
|
+
# ]
|
220
|
+
# client.publish 'activityChannel', messages
|
221
|
+
#
|
222
|
+
# client.publish('activityChannel', 'click', 'body') do |message|
|
223
|
+
# puts "#{message.name} event received with #{message.data}"
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# client.publish('activityChannel', 'click', 'body').errback do |error, message|
|
227
|
+
# puts "#{message.name} was not received, error #{error.message}"
|
228
|
+
# end
|
229
|
+
#
|
230
|
+
def publish(channel_name, name, data = nil, attributes = {}, &success_block)
|
231
|
+
if !connection.can_publish_messages?
|
232
|
+
error = Ably::Exceptions::MessageQueueingDisabled.new("Message cannot be published. Client is not allowed to queue messages when connection is in state #{connection.state}")
|
233
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
234
|
+
end
|
235
|
+
|
236
|
+
messages = if name.kind_of?(Enumerable)
|
237
|
+
name
|
238
|
+
else
|
239
|
+
name = ensure_utf_8(:name, name, allow_nil: true)
|
240
|
+
ensure_supported_payload data
|
241
|
+
[{ name: name, data: data }.merge(attributes)]
|
242
|
+
end
|
243
|
+
|
244
|
+
if messages.length > Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE
|
245
|
+
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.")
|
246
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
247
|
+
end
|
248
|
+
|
249
|
+
enqueue_messages_on_connection(self, messages, channel_name).tap do |deferrable|
|
250
|
+
deferrable.callback(&success_block) if block_given?
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
175
254
|
# @!attribute [r] endpoint
|
176
255
|
# @return [URI::Generic] Default Ably Realtime endpoint used for all requests
|
177
256
|
def endpoint
|
@@ -214,6 +293,14 @@ module Ably
|
|
214
293
|
@fallback_endpoints[fallback_endpoint_index % @fallback_endpoints.count]
|
215
294
|
end
|
216
295
|
|
296
|
+
# The local device detilas
|
297
|
+
# @return [Ably::Models::LocalDevice]
|
298
|
+
#
|
299
|
+
# @note This is unsupported in the Ruby library
|
300
|
+
def device
|
301
|
+
raise Ably::Exceptions::PushNotificationsNotSupported, 'This device does not support receiving or subscribing to push notifications. The local device object is not unavailable'
|
302
|
+
end
|
303
|
+
|
217
304
|
private
|
218
305
|
def endpoint_for_host(host)
|
219
306
|
port = if use_tls?
|
@@ -102,7 +102,11 @@ module Ably::Realtime
|
|
102
102
|
if channel.attached?
|
103
103
|
channel.manager.duplicate_attached_received protocol_message
|
104
104
|
else
|
105
|
-
channel.
|
105
|
+
if channel.failed?
|
106
|
+
logger.warn "Ably::Realtime::Client::IncomingMessageDispatcher - Received an ATTACHED protocol message for FAILED channel #{channel.name}. Ignoring ATTACHED message"
|
107
|
+
else
|
108
|
+
channel.transition_state_machine :attached, reason: protocol_message.error, resumed: protocol_message.has_channel_resumed_flag?, protocol_message: protocol_message
|
109
|
+
end
|
106
110
|
end
|
107
111
|
end
|
108
112
|
|
@@ -132,7 +136,7 @@ module Ably::Realtime
|
|
132
136
|
client.auth.authorize
|
133
137
|
|
134
138
|
else
|
135
|
-
error = Ably::Exceptions::ProtocolError.new("Protocol Message Action #{protocol_message.action} is unsupported by this MessageDispatcher", 400,
|
139
|
+
error = Ably::Exceptions::ProtocolError.new("Protocol Message Action #{protocol_message.action} is unsupported by this MessageDispatcher", 400, Ably::Exceptions::Codes::PROTOCOL_ERROR)
|
136
140
|
logger.fatal error.message
|
137
141
|
end
|
138
142
|
end
|
@@ -52,7 +52,7 @@ module Ably::Realtime
|
|
52
52
|
protocol_message = outgoing_queue.shift
|
53
53
|
|
54
54
|
if (!connection.transport)
|
55
|
-
protocol_message.fail Ably::Exceptions::TransportClosed.new('Transport disconnected unexpectedly', nil,
|
55
|
+
protocol_message.fail Ably::Exceptions::TransportClosed.new('Transport disconnected unexpectedly', nil, Ably::Exceptions::Codes::DISCONNECTED)
|
56
56
|
next
|
57
57
|
end
|
58
58
|
|
@@ -79,6 +79,9 @@ module Ably
|
|
79
79
|
websocket_heartbeats_disabled: false,
|
80
80
|
}.freeze
|
81
81
|
|
82
|
+
# Max number of messages to bundle in a single ProtocolMessage
|
83
|
+
MAX_PROTOCOL_MESSAGE_BATCH_SIZE = 50
|
84
|
+
|
82
85
|
# A unique public identifier for this connection, used to identify this member in presence events and messages
|
83
86
|
# @return [String]
|
84
87
|
attr_reader :id
|
@@ -225,7 +228,7 @@ module Ably
|
|
225
228
|
#
|
226
229
|
def ping(&block)
|
227
230
|
if initialized? || suspended? || closing? || closed? || failed?
|
228
|
-
error = Ably::Models::ErrorInfo.new(message: "Cannot send a ping when the connection is #{state}", code:
|
231
|
+
error = Ably::Models::ErrorInfo.new(message: "Cannot send a ping when the connection is #{state}", code: Ably::Exceptions::Codes::DISCONNECTED)
|
229
232
|
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
230
233
|
end
|
231
234
|
|
@@ -256,7 +259,7 @@ module Ably
|
|
256
259
|
once_or_if([:suspended, :closing, :closed, :failed]) do
|
257
260
|
next if finished
|
258
261
|
finished = true
|
259
|
-
deferrable.fail Ably::Models::ErrorInfo.new(message: "Ping failed as connection has changed state to #{state}", code:
|
262
|
+
deferrable.fail Ably::Models::ErrorInfo.new(message: "Ping failed as connection has changed state to #{state}", code: Ably::Exceptions::Codes::DISCONNECTED)
|
260
263
|
end
|
261
264
|
|
262
265
|
EventMachine.add_timer(defaults.fetch(:realtime_request_timeout)) do
|
@@ -265,7 +268,7 @@ module Ably
|
|
265
268
|
__incoming_protocol_msgbus__.unsubscribe(:protocol_message, &wait_for_ping)
|
266
269
|
error_msg = "Ping timed out after #{defaults.fetch(:realtime_request_timeout)}s"
|
267
270
|
logger.warn { error_msg }
|
268
|
-
deferrable.fail Ably::Models::ErrorInfo.new(message: error_msg, code:
|
271
|
+
deferrable.fail Ably::Models::ErrorInfo.new(message: error_msg, code: Ably::Exceptions::Codes::TIMEOUT_ERROR)
|
269
272
|
safe_yield block, nil if block_given?
|
270
273
|
end
|
271
274
|
end
|
@@ -280,7 +283,7 @@ module Ably
|
|
280
283
|
EventMachine::HttpRequest.new(url).get.tap do |http|
|
281
284
|
http.errback do
|
282
285
|
yield false if block_given?
|
283
|
-
deferrable.fail Ably::Exceptions::ConnectionFailed.new("Unable to connect to #{url}", nil,
|
286
|
+
deferrable.fail Ably::Exceptions::ConnectionFailed.new("Unable to connect to #{url}", nil, Ably::Exceptions::Codes::CONNECTION_FAILED)
|
284
287
|
end
|
285
288
|
http.callback do
|
286
289
|
EventMachine.next_tick do
|
@@ -289,7 +292,7 @@ module Ably
|
|
289
292
|
if result
|
290
293
|
deferrable.succeed
|
291
294
|
else
|
292
|
-
deferrable.fail Ably::Exceptions::ConnectionFailed.new("Unexpected response from #{url} (#{http.response_header.status})", 400,
|
295
|
+
deferrable.fail Ably::Exceptions::ConnectionFailed.new("Unexpected response from #{url} (#{http.response_header.status})", 400, Ably::Exceptions::Codes::BAD_REQUEST)
|
293
296
|
end
|
294
297
|
end
|
295
298
|
end
|
@@ -43,7 +43,7 @@ module Ably::Realtime
|
|
43
43
|
end
|
44
44
|
|
45
45
|
unless client.auth.authentication_security_requirements_met?
|
46
|
-
connection.transition_state_machine :failed, reason: Ably::Exceptions::InsecureRequest.new('Cannot use Basic Auth over non-TLS connections', 401,
|
46
|
+
connection.transition_state_machine :failed, reason: Ably::Exceptions::InsecureRequest.new('Cannot use Basic Auth over non-TLS connections', 401, Ably::Exceptions::Codes::INVALID_USE_OF_BASIC_AUTH_OVER_NONTLS_TRANSPORT)
|
47
47
|
return
|
48
48
|
end
|
49
49
|
|
@@ -61,7 +61,7 @@ module Ably::Realtime
|
|
61
61
|
|
62
62
|
logger.debug { "ConnectionManager: Setting up automatic connection timeout timer for #{realtime_request_timeout}s" }
|
63
63
|
create_timeout_timer_whilst_in_state(:connecting, realtime_request_timeout) do
|
64
|
-
connection_opening_failed Ably::Exceptions::ConnectionTimeout.new("Connection to Ably timed out after #{realtime_request_timeout}s", nil,
|
64
|
+
connection_opening_failed Ably::Exceptions::ConnectionTimeout.new("Connection to Ably timed out after #{realtime_request_timeout}s", nil, Ably::Exceptions::Codes::CONNECTION_TIMED_OUT)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -72,7 +72,7 @@ module Ably::Realtime
|
|
72
72
|
if error.kind_of?(Ably::Exceptions::BaseAblyException)
|
73
73
|
# Authentication errors that indicate the authentication failure is terminal should move to the failed state
|
74
74
|
if ([401, 403].include?(error.status) && !RESOLVABLE_ERROR_CODES.fetch(:token_expired).include?(error.code)) ||
|
75
|
-
(error.code == Ably::Exceptions::INVALID_CLIENT_ID)
|
75
|
+
(error.code == Ably::Exceptions::Codes::INVALID_CLIENT_ID)
|
76
76
|
connection.transition_state_machine :failed, reason: error
|
77
77
|
return
|
78
78
|
end
|
@@ -80,7 +80,7 @@ module Ably::Realtime
|
|
80
80
|
|
81
81
|
logger.warn { "ConnectionManager: Connection to #{connection.current_host}:#{connection.port} failed; #{error.message}" }
|
82
82
|
next_state = get_next_retry_state_info
|
83
|
-
connection.transition_state_machine next_state.fetch(:state), retry_in: next_state.fetch(:pause), reason: Ably::Exceptions::ConnectionError.new("Connection failed: #{error.message}", nil,
|
83
|
+
connection.transition_state_machine next_state.fetch(:state), retry_in: next_state.fetch(:pause), reason: Ably::Exceptions::ConnectionError.new("Connection failed: #{error.message}", nil, Ably::Exceptions::Codes::CONNECTION_FAILED, error)
|
84
84
|
end
|
85
85
|
|
86
86
|
# Called whenever a new connection is made
|
@@ -319,7 +319,7 @@ module Ably::Realtime
|
|
319
319
|
@liveness_timer = EventMachine::Timer.new(connection.heartbeat_interval + 0.1) do
|
320
320
|
if connection.connected? && (connection.time_since_connection_confirmed_alive? >= connection.heartbeat_interval)
|
321
321
|
msg = "No activity seen from realtime in #{connection.heartbeat_interval}; assuming connection has dropped";
|
322
|
-
error = Ably::Exceptions::ConnectionTimeout.new(msg,
|
322
|
+
error = Ably::Exceptions::ConnectionTimeout.new(msg, Ably::Exceptions::Codes::DISCONNECTED, 408)
|
323
323
|
connection.transition_state_machine! :disconnected, reason: error
|
324
324
|
end
|
325
325
|
end
|
@@ -492,9 +492,9 @@ module Ably::Realtime
|
|
492
492
|
connection.transition_state_machine :closed
|
493
493
|
elsif !connection.closed? && !connection.disconnected? && !connection.failed? && !connection.suspended?
|
494
494
|
exception = if reason
|
495
|
-
Ably::Exceptions::TransportClosed.new(reason, nil,
|
495
|
+
Ably::Exceptions::TransportClosed.new(reason, nil, Ably::Exceptions::Codes::DISCONNECTED)
|
496
496
|
else
|
497
|
-
Ably::Exceptions::TransportClosed.new('Transport disconnected unexpectedly', nil,
|
497
|
+
Ably::Exceptions::TransportClosed.new('Transport disconnected unexpectedly', nil, Ably::Exceptions::Codes::DISCONNECTED)
|
498
498
|
end
|
499
499
|
next_state = get_next_retry_state_info
|
500
500
|
connection.transition_state_machine next_state.fetch(:state), retry_in: next_state.fetch(:pause), reason: exception
|
@@ -157,7 +157,7 @@ module Ably::Realtime
|
|
157
157
|
logger.debug { "WebsocketTransport: Prot msg recv <=: #{action_name} - #{event_data}" }
|
158
158
|
|
159
159
|
if protocol_message.invalid?
|
160
|
-
error = Ably::Exceptions::ProtocolError.new("Invalid Protocol Message received: #{event_data}\nConnection moving to the failed state as the protocol is invalid and unsupported", 400,
|
160
|
+
error = Ably::Exceptions::ProtocolError.new("Invalid Protocol Message received: #{event_data}\nConnection moving to the failed state as the protocol is invalid and unsupported", 400, Ably::Exceptions::Codes::PROTOCOL_ERROR)
|
161
161
|
logger.fatal { "WebsocketTransport: #{error.message}" }
|
162
162
|
failed_protocol_message = Ably::Models::ProtocolMessage.new(
|
163
163
|
action: Ably::Models::ProtocolMessage::ACTION.Error,
|
@@ -233,7 +233,7 @@ module Ably::Realtime
|
|
233
233
|
deferrable.fail Ably::Exceptions::InvalidState.new(
|
234
234
|
'Presence state is out of sync as channel is SUSPENDED. Presence#get on a SUSPENDED channel is only supported with option wait_for_sync: false',
|
235
235
|
nil,
|
236
|
-
|
236
|
+
Ably::Exceptions::Codes::PRESENCE_STATE_IS_OUT_OF_SYNC
|
237
237
|
)
|
238
238
|
end
|
239
239
|
return deferrable
|
@@ -330,7 +330,7 @@ module Ably::Realtime
|
|
330
330
|
def send_presence_protocol_message(presence_action, client_id, data)
|
331
331
|
presence_message = create_presence_message(presence_action, client_id, data)
|
332
332
|
unless presence_message.client_id
|
333
|
-
raise Ably::Exceptions::Standard.new('Unable to enter create presence message without a client_id', 400,
|
333
|
+
raise Ably::Exceptions::Standard.new('Unable to enter create presence message without a client_id', 400, Ably::Exceptions::Codes::UNABLE_TO_ENTER_PRESENCE_CHANNEL_NO_CLIENTID)
|
334
334
|
end
|
335
335
|
|
336
336
|
protocol_message = {
|
@@ -437,13 +437,13 @@ module Ably::Realtime
|
|
437
437
|
|
438
438
|
def attach_channel_then(deferrable)
|
439
439
|
if channel.detached? || channel.failed?
|
440
|
-
deferrable.fail Ably::Exceptions::InvalidState.new("Operation is not allowed when channel is in #{channel.state}", 400,
|
440
|
+
deferrable.fail Ably::Exceptions::InvalidState.new("Operation is not allowed when channel is in #{channel.state}", 400, Ably::Exceptions::Codes::UNABLE_TO_ENTER_PRESENCE_CHANNEL_INVALID_CHANNEL_STATE)
|
441
441
|
else
|
442
442
|
channel.unsafe_once(:attached, :detached, :failed) do |channel_state_change|
|
443
443
|
if channel_state_change.current == :attached
|
444
444
|
yield
|
445
445
|
else
|
446
|
-
deferrable.fail Ably::Exceptions::InvalidState.new("Operation failed as channel transitioned to #{channel_state_change.current}", 400,
|
446
|
+
deferrable.fail Ably::Exceptions::InvalidState.new("Operation failed as channel transitioned to #{channel_state_change.current}", 400, Ably::Exceptions::Codes::UNABLE_TO_ENTER_PRESENCE_CHANNEL_INVALID_CHANNEL_STATE)
|
447
447
|
end
|
448
448
|
end
|
449
449
|
channel.attach
|
@@ -275,7 +275,7 @@ module Ably::Realtime
|
|
275
275
|
presence_message_client_id = presence_message.client_id || client.auth.client_id
|
276
276
|
re_enter_error = Ably::Models::ErrorInfo.new(
|
277
277
|
message: "unable to automatically re-enter presence channel for client_id '#{presence_message_client_id}'. Source error code #{error.code} and message '#{error.message}'",
|
278
|
-
code:
|
278
|
+
code: Ably::Exceptions::Codes::UNABLE_TO_AUTOMATICALLY_REENTER_PRESENCE_CHANNEL
|
279
279
|
)
|
280
280
|
channel.emit :update, Ably::Models::ChannelStateChange.new(
|
281
281
|
current: channel.state,
|
@@ -312,14 +312,14 @@ module Ably::Realtime
|
|
312
312
|
when Ably::Models::PresenceMessage::ACTION.Leave
|
313
313
|
remove_presence_member presence_message
|
314
314
|
else
|
315
|
-
Ably::Exceptions::ProtocolError.new("Protocol error, unknown presence action #{presence_message.action}", 400,
|
315
|
+
Ably::Exceptions::ProtocolError.new("Protocol error, unknown presence action #{presence_message.action}", 400, Ably::Exceptions::Codes::PROTOCOL_ERROR)
|
316
316
|
end
|
317
317
|
end
|
318
318
|
|
319
319
|
def ensure_presence_message_is_valid(presence_message)
|
320
320
|
return true if presence_message.connection_id
|
321
321
|
|
322
|
-
error = Ably::Exceptions::ProtocolError.new("Protocol error, presence message is missing connectionId", 400,
|
322
|
+
error = Ably::Exceptions::ProtocolError.new("Protocol error, presence message is missing connectionId", 400, Ably::Exceptions::Codes::PROTOCOL_ERROR)
|
323
323
|
logger.error { "PresenceMap: On channel '#{channel.name}' error: #{error}" }
|
324
324
|
end
|
325
325
|
|