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
@@ -113,7 +113,7 @@ module Ably::Modules
|
|
113
113
|
payload.kind_of?(Array) ||
|
114
114
|
payload.nil?
|
115
115
|
|
116
|
-
raise Ably::Exceptions::UnsupportedDataType.new('Invalid data payload', 400,
|
116
|
+
raise Ably::Exceptions::UnsupportedDataType.new('Invalid data payload', 400, Ably::Exceptions::Codes::INVALID_MESSAGE_DATA_OR_ENCODING)
|
117
117
|
end
|
118
118
|
end
|
119
119
|
end
|
@@ -27,7 +27,7 @@ module Ably::Modules
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# Return an Array of Message or Presence objects from the encoded Array of JSON-like objects, using the optional channel options
|
30
|
-
# @param
|
30
|
+
# @param message_object_array [Array<Hash>] Array of JSON-like objects with encoded messages
|
31
31
|
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
32
32
|
# @return [Array<Message,Presence>]
|
33
33
|
def from_encoded_array(message_object_array, channel_options = {})
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# This file is generated by running `rake :generate_error_codes`
|
2
|
+
# Do not manually modify this file
|
3
|
+
# Generated at: 2018-09-18 18:28:58 UTC
|
4
|
+
#
|
5
|
+
module Ably
|
6
|
+
module Exceptions
|
7
|
+
module Codes
|
8
|
+
NO_ERROR = 10000
|
9
|
+
BAD_REQUEST = 40000
|
10
|
+
INVALID_REQUEST_BODY = 40001
|
11
|
+
INVALID_PARAMETER_NAME = 40002
|
12
|
+
INVALID_PARAMETER_VALUE = 40003
|
13
|
+
INVALID_HEADER = 40004
|
14
|
+
INVALID_CREDENTIAL = 40005
|
15
|
+
INVALID_CONNECTION_ID = 40006
|
16
|
+
INVALID_MESSAGE_ID = 40007
|
17
|
+
INVALID_CONTENT_LENGTH = 40008
|
18
|
+
MAXIMUM_MESSAGE_LENGTH_EXCEEDED = 40009
|
19
|
+
INVALID_CHANNEL_NAME = 40010
|
20
|
+
STALE_RING_STATE = 40011
|
21
|
+
INVALID_CLIENT_ID = 40012
|
22
|
+
INVALID_MESSAGE_DATA_OR_ENCODING = 40013
|
23
|
+
RESOURCE_DISPOSED = 40014
|
24
|
+
INVALID_DEVICE_ID = 40015
|
25
|
+
BATCH_ERROR = 40020
|
26
|
+
INVALID_PUBLISH_REQUEST_UNSPECIFIED = 40030
|
27
|
+
INVALID_PUBLISH_REQUEST_INVALID_CLIENTSPECIFIED_ID = 40031
|
28
|
+
UNAUTHORIZED = 40100
|
29
|
+
INVALID_CREDENTIALS = 40101
|
30
|
+
INCOMPATIBLE_CREDENTIALS = 40102
|
31
|
+
INVALID_USE_OF_BASIC_AUTH_OVER_NONTLS_TRANSPORT = 40103
|
32
|
+
TIMESTAMP_NOT_CURRENT = 40104
|
33
|
+
NONCE_VALUE_REPLAYED = 40105
|
34
|
+
UNABLE_TO_OBTAIN_CREDENTIALS_FROM_GIVEN_PARAMETERS = 40106
|
35
|
+
ACCOUNT_DISABLED = 40110
|
36
|
+
ACCOUNT_RESTRICTED_CONNECTION_LIMITS_EXCEEDED = 40111
|
37
|
+
ACCOUNT_BLOCKED_MESSAGE_LIMITS_EXCEEDED = 40112
|
38
|
+
ACCOUNT_BLOCKED = 40113
|
39
|
+
ACCOUNT_RESTRICTED_CHANNEL_LIMITS_EXCEEDED = 40114
|
40
|
+
APPLICATION_DISABLED = 40120
|
41
|
+
KEY_ERROR_UNSPECIFIED = 40130
|
42
|
+
KEY_REVOKED = 40131
|
43
|
+
KEY_EXPIRED = 40132
|
44
|
+
KEY_DISABLED = 40133
|
45
|
+
TOKEN_ERROR_UNSPECIFIED = 40140
|
46
|
+
TOKEN_REVOKED = 40141
|
47
|
+
TOKEN_EXPIRED = 40142
|
48
|
+
TOKEN_UNRECOGNISED = 40143
|
49
|
+
INVALID_JWT_FORMAT = 40144
|
50
|
+
INVALID_TOKEN_FORMAT = 40145
|
51
|
+
CONNECTION_BLOCKED_LIMITS_EXCEEDED = 40150
|
52
|
+
OPERATION_NOT_PERMITTED_WITH_PROVIDED_CAPABILITY = 40160
|
53
|
+
ERROR_FROM_CLIENT_TOKEN_CALLBACK = 40170
|
54
|
+
FORBIDDEN = 40300
|
55
|
+
ACCOUNT_DOES_NOT_PERMIT_TLS_CONNECTION = 40310
|
56
|
+
OPERATION_REQUIRES_TLS_CONNECTION = 40311
|
57
|
+
APPLICATION_REQUIRES_AUTHENTICATION = 40320
|
58
|
+
UNABLE_TO_ACTIVATE_ACCOUNT_DUE_TO_PLACEMENT_CONSTRAINT_UNSPECIFIED = 40330
|
59
|
+
UNABLE_TO_ACTIVATE_ACCOUNT_DUE_TO_PLACEMENT_CONSTRAINT_INCOMPATIBLE_ENVIRONMENT = 40331
|
60
|
+
UNABLE_TO_ACTIVATE_ACCOUNT_DUE_TO_PLACEMENT_CONSTRAINT_INCOMPATIBLE_SITE = 40332
|
61
|
+
NOT_FOUND = 40400
|
62
|
+
METHOD_NOT_ALLOWED = 40500
|
63
|
+
RATE_LIMIT_EXCEEDED_NONFATAL_REQUEST_REJECTED_UNSPECIFIED = 42910
|
64
|
+
MAX_PERCONNECTION_PUBLISH_RATE_LIMIT_EXCEEDED_NONFATAL_UNABLE_TO_PUBLISH_MESSAGE = 42911
|
65
|
+
RATE_LIMIT_EXCEEDED_FATAL = 42920
|
66
|
+
MAX_PERCONNECTION_PUBLISH_RATE_LIMIT_EXCEEDED_FATAL_CLOSING_CONNECTION = 42921
|
67
|
+
INTERNAL_ERROR = 50000
|
68
|
+
INTERNAL_CHANNEL_ERROR = 50001
|
69
|
+
INTERNAL_CONNECTION_ERROR = 50002
|
70
|
+
TIMEOUT_ERROR = 50003
|
71
|
+
REQUEST_FAILED_DUE_TO_OVERLOADED_INSTANCE = 50004
|
72
|
+
REACTOR_OPERATION_FAILED = 70000
|
73
|
+
REACTOR_OPERATION_FAILED_POST_OPERATION_FAILED = 70001
|
74
|
+
REACTOR_OPERATION_FAILED_POST_OPERATION_RETURNED_UNEXPECTED_CODE = 70002
|
75
|
+
REACTOR_OPERATION_FAILED_MAXIMUM_NUMBER_OF_CONCURRENT_INFLIGHT_REQUESTS_EXCEEDED = 70003
|
76
|
+
EXCHANGE_ERROR_UNSPECIFIED = 71000
|
77
|
+
FORCED_REATTACHMENT_DUE_TO_PERMISSIONS_CHANGE = 71001
|
78
|
+
EXCHANGE_PUBLISHER_ERROR_UNSPECIFIED = 71100
|
79
|
+
NO_SUCH_PUBLISHER = 71101
|
80
|
+
PUBLISHER_NOT_ENABLED_AS_AN_EXCHANGE_PUBLISHER = 71102
|
81
|
+
EXCHANGE_PRODUCT_ERROR_UNSPECIFIED = 71200
|
82
|
+
NO_SUCH_PRODUCT = 71201
|
83
|
+
PRODUCT_DISABLED = 71202
|
84
|
+
NO_SUCH_CHANNEL_IN_THIS_PRODUCT = 71203
|
85
|
+
EXCHANGE_SUBSCRIPTION_ERROR_UNSPECIFIED = 71300
|
86
|
+
SUBSCRIPTION_DISABLED = 71301
|
87
|
+
REQUESTER_HAS_NO_SUBSCRIPTION_TO_THIS_PRODUCT = 71302
|
88
|
+
CONNECTION_FAILED = 80000
|
89
|
+
CONNECTION_FAILED_NO_COMPATIBLE_TRANSPORT = 80001
|
90
|
+
CONNECTION_SUSPENDED = 80002
|
91
|
+
DISCONNECTED = 80003
|
92
|
+
ALREADY_CONNECTED = 80004
|
93
|
+
INVALID_CONNECTION_ID_REMOTE_NOT_FOUND = 80005
|
94
|
+
UNABLE_TO_RECOVER_CONNECTION_MESSAGES_EXPIRED = 80006
|
95
|
+
UNABLE_TO_RECOVER_CONNECTION_MESSAGE_LIMIT_EXCEEDED = 80007
|
96
|
+
UNABLE_TO_RECOVER_CONNECTION_CONNECTION_EXPIRED = 80008
|
97
|
+
CONNECTION_NOT_ESTABLISHED_NO_TRANSPORT_HANDLE = 80009
|
98
|
+
INVALID_OPERATION_INVALID_TRANSPORT_HANDLE = 80010
|
99
|
+
UNABLE_TO_RECOVER_CONNECTION_INCOMPATIBLE_AUTH_PARAMS = 80011
|
100
|
+
UNABLE_TO_RECOVER_CONNECTION_INVALID_OR_UNSPECIFIED_CONNECTION_SERIAL = 80012
|
101
|
+
PROTOCOL_ERROR = 80013
|
102
|
+
CONNECTION_TIMED_OUT = 80014
|
103
|
+
INCOMPATIBLE_CONNECTION_PARAMETERS = 80015
|
104
|
+
OPERATION_ON_SUPERSEDED_TRANSPORT = 80016
|
105
|
+
CONNECTION_CLOSED = 80017
|
106
|
+
INVALID_CONNECTION_ID_INVALID_FORMAT = 80018
|
107
|
+
CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED = 80019
|
108
|
+
CONTINUITY_LOSS_DUE_TO_MAXIMUM_SUBSCRIBE_MESSAGE_RATE_EXCEEDED = 80020
|
109
|
+
CLIENT_RESTRICTION_NOT_SATISFIED = 80030
|
110
|
+
CHANNEL_OPERATION_FAILED = 90000
|
111
|
+
CHANNEL_OPERATION_FAILED_INVALID_CHANNEL_STATE = 90001
|
112
|
+
CHANNEL_OPERATION_FAILED_EPOCH_EXPIRED_OR_NEVER_EXISTED = 90002
|
113
|
+
UNABLE_TO_RECOVER_CHANNEL_MESSAGES_EXPIRED = 90003
|
114
|
+
UNABLE_TO_RECOVER_CHANNEL_MESSAGE_LIMIT_EXCEEDED = 90004
|
115
|
+
UNABLE_TO_RECOVER_CHANNEL_NO_MATCHING_EPOCH = 90005
|
116
|
+
UNABLE_TO_RECOVER_CHANNEL_UNBOUNDED_REQUEST = 90006
|
117
|
+
CHANNEL_OPERATION_FAILED_NO_RESPONSE_FROM_SERVER = 90007
|
118
|
+
MAXIMUM_NUMBER_OF_CHANNELS_PER_CONNECTION_EXCEEDED = 90010
|
119
|
+
UNABLE_TO_ENTER_PRESENCE_CHANNEL_NO_CLIENTID = 91000
|
120
|
+
UNABLE_TO_ENTER_PRESENCE_CHANNEL_INVALID_CHANNEL_STATE = 91001
|
121
|
+
UNABLE_TO_LEAVE_PRESENCE_CHANNEL_THAT_IS_NOT_ENTERED = 91002
|
122
|
+
UNABLE_TO_ENTER_PRESENCE_CHANNEL_MAXIMUM_MEMBER_LIMIT_EXCEEDED = 91003
|
123
|
+
UNABLE_TO_AUTOMATICALLY_REENTER_PRESENCE_CHANNEL = 91004
|
124
|
+
PRESENCE_STATE_IS_OUT_OF_SYNC = 91005
|
125
|
+
MEMBER_IMPLICITLY_LEFT_PRESENCE_CHANNEL_CONNECTION_CLOSED = 91100
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -42,10 +42,23 @@ module Ably::Modules
|
|
42
42
|
attributes.hash
|
43
43
|
end
|
44
44
|
|
45
|
+
def to_s
|
46
|
+
representation = attributes.map do |key, val|
|
47
|
+
if val.nil?
|
48
|
+
nil
|
49
|
+
else
|
50
|
+
val_str = val.to_s
|
51
|
+
val_str = "#{val_str[0...80]}..." if val_str.length > 80
|
52
|
+
"#{key}=#{val_str}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
"<#{self.class.name}: #{representation.compact.join(', ')}>"
|
56
|
+
end
|
57
|
+
|
45
58
|
module ClassMethods
|
46
59
|
# Return a new instance of this object using the provided JSON-like object or JSON string
|
47
|
-
# @param [Hash, String]
|
48
|
-
# @return a new instance
|
60
|
+
# @param json_like_object [Hash, String] JSON-like object or JSON string
|
61
|
+
# @return a new instance to this object
|
49
62
|
def from_json(json_like_object)
|
50
63
|
if json_like_object.kind_of?(String)
|
51
64
|
new(JSON.parse(json_like_object))
|
@@ -41,7 +41,7 @@ module Ably::Modules
|
|
41
41
|
# @return [Ably::Exceptions::InvalidStateChange]
|
42
42
|
def exception_for_state_change_to(state)
|
43
43
|
error_message = "#{self.class}: Unable to transition from #{current_state} => #{state}"
|
44
|
-
Ably::Exceptions::InvalidStateChange.new(error_message, nil,
|
44
|
+
Ably::Exceptions::InvalidStateChange.new(error_message, nil, Ably::Exceptions::Codes::CHANNEL_OPERATION_FAILED_INVALID_CHANNEL_STATE)
|
45
45
|
end
|
46
46
|
|
47
47
|
module ClassMethods
|
data/lib/ably/realtime.rb
CHANGED
data/lib/ably/realtime/auth.rb
CHANGED
@@ -239,7 +239,7 @@ module Ably
|
|
239
239
|
# Use base exception if it exists carrying forward the status codes
|
240
240
|
deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, nil, nil, error)
|
241
241
|
else
|
242
|
-
deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500,
|
242
|
+
deferrable.fail Ably::Exceptions::AuthenticationFailed.new(error.message, 500, Ably::Exceptions::Codes::CLIENT_CONFIGURED_AUTHENTICATION_PROVIDER_REQUEST_FAILED)
|
243
243
|
end
|
244
244
|
end
|
245
245
|
async_wrap(success_callback, fail_callback) do
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ably/realtime/channel/publisher'
|
2
|
+
|
1
3
|
module Ably
|
2
4
|
module Realtime
|
3
5
|
# The Channel class represents a Channel belonging to this application.
|
@@ -32,6 +34,7 @@ module Ably
|
|
32
34
|
include Ably::Modules::EventMachineHelpers
|
33
35
|
include Ably::Modules::AsyncWrapper
|
34
36
|
include Ably::Modules::MessageEmitter
|
37
|
+
include Ably::Realtime::Channel::Publisher
|
35
38
|
extend Ably::Modules::Enum
|
36
39
|
|
37
40
|
# ChannelState
|
@@ -61,12 +64,17 @@ module Ably
|
|
61
64
|
|
62
65
|
# {Ably::Realtime::Client} associated with this channel
|
63
66
|
# @return [Ably::Realtime::Client]
|
67
|
+
# @api private
|
64
68
|
attr_reader :client
|
65
69
|
|
66
70
|
# Channel name
|
67
71
|
# @return [String]
|
68
72
|
attr_reader :name
|
69
73
|
|
74
|
+
# Push channel used for push notification
|
75
|
+
# @return [Ably::Realtime::Channel::PushChannel]
|
76
|
+
attr_reader :push
|
77
|
+
|
70
78
|
# Channel options configured for this channel, see {#initialize} for channel_options
|
71
79
|
# @return [Hash]
|
72
80
|
attr_reader :options
|
@@ -103,6 +111,7 @@ module Ably
|
|
103
111
|
@state_machine = ChannelStateMachine.new(self)
|
104
112
|
@state = STATE(state_machine.current_state)
|
105
113
|
@manager = ChannelManager.new(self, client.connection)
|
114
|
+
@push = PushChannel.new(self)
|
106
115
|
|
107
116
|
setup_event_handlers
|
108
117
|
setup_presence
|
@@ -116,7 +125,7 @@ module Ably
|
|
116
125
|
# @param data [String, ByteArray, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument
|
117
126
|
# @param attributes [Hash, nil] Optional additional message attributes such as :client_id or :connection_id, applied when name attribute is nil or a string
|
118
127
|
#
|
119
|
-
# @yield [Ably::Models::Message,Array<Ably::Models::Message>] On success, will call the block with the {Ably::Models::Message} if a single message is
|
128
|
+
# @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
|
120
129
|
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callbacks
|
121
130
|
#
|
122
131
|
# @example
|
@@ -146,13 +155,13 @@ module Ably
|
|
146
155
|
# end
|
147
156
|
#
|
148
157
|
def publish(name, data = nil, attributes = {}, &success_block)
|
149
|
-
if
|
158
|
+
if suspended? || failed?
|
150
159
|
error = Ably::Exceptions::ChannelInactive.new("Cannot publish messages on a channel in state #{state}")
|
151
160
|
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
152
161
|
end
|
153
162
|
|
154
163
|
if !connection.can_publish_messages?
|
155
|
-
error = Ably::Exceptions::MessageQueueingDisabled.new("Message cannot be published. Client is
|
164
|
+
error = Ably::Exceptions::MessageQueueingDisabled.new("Message cannot be published. Client is not allowed to queue messages when connection is in state #{connection.state}")
|
156
165
|
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
157
166
|
end
|
158
167
|
|
@@ -164,7 +173,12 @@ module Ably
|
|
164
173
|
[{ name: name, data: data }.merge(attributes)]
|
165
174
|
end
|
166
175
|
|
167
|
-
|
176
|
+
if messages.length > Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE
|
177
|
+
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.")
|
178
|
+
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
179
|
+
end
|
180
|
+
|
181
|
+
enqueue_messages_on_connection(client, messages, channel_name, options).tap do |deferrable|
|
168
182
|
deferrable.callback(&success_block) if block_given?
|
169
183
|
end
|
170
184
|
end
|
@@ -321,12 +335,6 @@ module Ably
|
|
321
335
|
client.logger
|
322
336
|
end
|
323
337
|
|
324
|
-
# Internal queue used for messages published that cannot yet be enqueued on the connection
|
325
|
-
# @api private
|
326
|
-
def __queue__
|
327
|
-
@queue
|
328
|
-
end
|
329
|
-
|
330
338
|
# As we are using a state machine, do not allow change_state to be used
|
331
339
|
# #transition_state_machine must be used instead
|
332
340
|
private :change_state
|
@@ -339,98 +347,6 @@ module Ably
|
|
339
347
|
end
|
340
348
|
emit_message message.name, message
|
341
349
|
end
|
342
|
-
|
343
|
-
unsafe_on(STATE.Attached) do
|
344
|
-
process_queue
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
# Queue messages and process queue if channel is attached.
|
349
|
-
# If channel is not yet attached, attempt to attach it before the message queue is processed.
|
350
|
-
# @return [Ably::Util::SafeDeferrable]
|
351
|
-
def queue_messages(raw_messages)
|
352
|
-
messages = Array(raw_messages).map do |raw_msg|
|
353
|
-
create_message(raw_msg).tap do |message|
|
354
|
-
next if message.client_id.nil?
|
355
|
-
if message.client_id == '*'
|
356
|
-
raise Ably::Exceptions::IncompatibleClientId.new('Wildcard client_id is reserved and cannot be used when publishing messages')
|
357
|
-
end
|
358
|
-
if message.client_id && !message.client_id.kind_of?(String)
|
359
|
-
raise Ably::Exceptions::IncompatibleClientId.new('client_id must be a String when publishing messages')
|
360
|
-
end
|
361
|
-
unless client.auth.can_assume_client_id?(message.client_id)
|
362
|
-
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}'")
|
363
|
-
end
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
__queue__.push(*messages)
|
368
|
-
|
369
|
-
if attached?
|
370
|
-
process_queue
|
371
|
-
else
|
372
|
-
attach
|
373
|
-
end
|
374
|
-
|
375
|
-
if messages.count == 1
|
376
|
-
# A message is a Deferrable so, if publishing only one message, simply return that Deferrable
|
377
|
-
messages.first
|
378
|
-
else
|
379
|
-
deferrable_for_multiple_messages(messages)
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
|
-
# A deferrable object that calls the success callback once all messages are delivered
|
384
|
-
# If any message fails, the errback is called immediately
|
385
|
-
# Only one callback or errback is ever called i.e. if a group of messages all fail, only once
|
386
|
-
# errback will be invoked
|
387
|
-
def deferrable_for_multiple_messages(messages)
|
388
|
-
expected_deliveries = messages.count
|
389
|
-
actual_deliveries = 0
|
390
|
-
failed = false
|
391
|
-
|
392
|
-
Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
|
393
|
-
messages.each do |message|
|
394
|
-
message.callback do
|
395
|
-
next if failed
|
396
|
-
actual_deliveries += 1
|
397
|
-
deferrable.succeed messages if actual_deliveries == expected_deliveries
|
398
|
-
end
|
399
|
-
message.errback do |error|
|
400
|
-
next if failed
|
401
|
-
failed = true
|
402
|
-
deferrable.fail error, message
|
403
|
-
end
|
404
|
-
end
|
405
|
-
end
|
406
|
-
end
|
407
|
-
|
408
|
-
def messages_in_queue?
|
409
|
-
!__queue__.empty?
|
410
|
-
end
|
411
|
-
|
412
|
-
# Move messages from Channel Queue into Outgoing Connection Queue
|
413
|
-
def process_queue
|
414
|
-
condition = -> { attached? && messages_in_queue? }
|
415
|
-
non_blocking_loop_while(condition) do
|
416
|
-
send_messages_within_protocol_message __queue__.shift(MAX_PROTOCOL_MESSAGE_BATCH_SIZE)
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
def send_messages_within_protocol_message(messages)
|
421
|
-
connection.send_protocol_message(
|
422
|
-
action: Ably::Models::ProtocolMessage::ACTION.Message.to_i,
|
423
|
-
channel: name,
|
424
|
-
messages: messages
|
425
|
-
)
|
426
|
-
end
|
427
|
-
|
428
|
-
def create_message(message)
|
429
|
-
Ably::Models::Message(message.dup).tap do |msg|
|
430
|
-
msg.encode(client.encoders, options) do |encode_error, error_message|
|
431
|
-
client.logger.error error_message
|
432
|
-
end
|
433
|
-
end
|
434
350
|
end
|
435
351
|
|
436
352
|
def rest_channel
|
@@ -444,9 +360,15 @@ module Ably
|
|
444
360
|
def setup_presence
|
445
361
|
@presence ||= Presence.new(self)
|
446
362
|
end
|
363
|
+
|
364
|
+
# Alias useful for methods with a name argument
|
365
|
+
def channel_name
|
366
|
+
name
|
367
|
+
end
|
447
368
|
end
|
448
369
|
end
|
449
370
|
end
|
450
371
|
|
451
372
|
require 'ably/realtime/channel/channel_manager'
|
452
373
|
require 'ably/realtime/channel/channel_state_machine'
|
374
|
+
require 'ably/realtime/channel/push_channel'
|
@@ -111,16 +111,12 @@ module Ably::Realtime
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
# When a channel becomes
|
114
|
+
# When a channel becomes suspended or failed,
|
115
115
|
# all queued messages should be failed immediately as we don't queue in
|
116
116
|
# any of those states
|
117
117
|
def fail_queued_messages(error)
|
118
118
|
error = Ably::Exceptions::MessageDeliveryFailed.new("Queued messages on channel '#{channel.name}' in state '#{channel.state}' will never be delivered") unless error
|
119
119
|
fail_messages_in_queue connection.__outgoing_message_queue__, error
|
120
|
-
channel.__queue__.each do |message|
|
121
|
-
nack_message message, error
|
122
|
-
end
|
123
|
-
channel.__queue__.clear
|
124
120
|
end
|
125
121
|
|
126
122
|
def fail_messages_in_queue(queue, error)
|
@@ -214,7 +210,7 @@ module Ably::Realtime
|
|
214
210
|
state_at_time_of_request = channel.state
|
215
211
|
@pending_state_change_timer = EventMachine::Timer.new(realtime_request_timeout) do
|
216
212
|
if channel.state == state_at_time_of_request
|
217
|
-
error = Ably::Models::ErrorInfo.new(code:
|
213
|
+
error = Ably::Models::ErrorInfo.new(code: Ably::Exceptions::Codes::CHANNEL_OPERATION_FAILED_NO_RESPONSE_FROM_SERVER, message: "Channel #{new_state} operation failed (timed out)")
|
218
214
|
channel.transition_state_machine state_if_failed, reason: error
|
219
215
|
end
|
220
216
|
end
|
@@ -25,7 +25,7 @@ module Ably::Realtime
|
|
25
25
|
transition :from => :attached, :to => [:attaching, :detaching, :detached, :failed, :suspended]
|
26
26
|
transition :from => :detaching, :to => [:detached, :attaching, :attached, :failed, :suspended]
|
27
27
|
transition :from => :detached, :to => [:attaching, :attached, :failed]
|
28
|
-
transition :from => :suspended, :to => [:attaching, :detached, :failed]
|
28
|
+
transition :from => :suspended, :to => [:attaching, :attached, :detached, :failed]
|
29
29
|
transition :from => :failed, :to => [:attaching]
|
30
30
|
|
31
31
|
after_transition do |channel, transition|
|
@@ -47,7 +47,7 @@ module Ably::Realtime
|
|
47
47
|
|
48
48
|
after_transition(to: [:detached, :failed, :suspended]) do |channel, current_transition|
|
49
49
|
err = error_from_state_change(current_transition)
|
50
|
-
channel.manager.fail_queued_messages
|
50
|
+
channel.manager.fail_queued_messages(err) if channel.failed? or channel.suspended? #RTL11
|
51
51
|
channel.manager.log_channel_error err if err
|
52
52
|
end
|
53
53
|
|