ably 1.0.7 → 1.1.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/.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
|
|