ably-rest 1.1.2 → 1.2.2
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/.travis.yml +3 -0
- data/CHANGELOG.md +1 -1
- data/MAINTAINERS.md +1 -0
- data/README.md +4 -2
- data/ably-rest.gemspec +15 -18
- data/lib/ably-rest.rb +2 -0
- data/lib/submodules/ably-ruby/.github/workflows/check.yml +50 -0
- data/lib/submodules/ably-ruby/CHANGELOG.md +200 -0
- data/lib/submodules/ably-ruby/COPYRIGHT +1 -0
- data/lib/submodules/ably-ruby/LICENSE +172 -11
- data/lib/submodules/ably-ruby/MAINTAINERS.md +1 -0
- data/lib/submodules/ably-ruby/README.md +24 -22
- data/lib/submodules/ably-ruby/SPEC.md +1020 -929
- data/lib/submodules/ably-ruby/UPDATING.md +30 -0
- data/lib/submodules/ably-ruby/ably.gemspec +16 -23
- data/lib/submodules/ably-ruby/lib/ably/agent.rb +3 -0
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +20 -10
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +8 -2
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +4 -4
- data/lib/submodules/ably-ruby/lib/ably/models/channel_details.rb +59 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_metrics.rb +84 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_occupancy.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_options.rb +97 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_status.rb +53 -0
- data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +8 -0
- data/lib/submodules/ably-ruby/lib/ably/models/delta_extras.rb +29 -0
- data/lib/submodules/ably-ruby/lib/ably/models/device_details.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +6 -2
- data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +28 -3
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +14 -0
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +31 -14
- data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +7 -2
- data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +11 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +22 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +34 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +19 -7
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_properties.rb +24 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +10 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/publisher.rb +6 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +56 -28
- data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +9 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +13 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +67 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +6 -5
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +0 -14
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +44 -29
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +60 -29
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +5 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -14
- data/lib/submodules/ably-ruby/lib/ably.rb +1 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +25 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +476 -21
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +59 -7
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +72 -16
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +85 -13
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +301 -34
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +77 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +3 -59
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +84 -158
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_admin_spec.rb +3 -19
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +24 -75
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +8 -4
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +141 -10
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +23 -6
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +146 -47
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +61 -3
- data/lib/submodules/ably-ruby/spec/acceptance/rest/push_admin_spec.rb +3 -19
- data/lib/submodules/ably-ruby/spec/lib/unit/models/channel_options_spec.rb +52 -0
- data/lib/submodules/ably-ruby/spec/run_parallel_tests +2 -7
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +131 -8
- data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +1 -1
- data/lib/submodules/ably-ruby/spec/spec_helper.rb +12 -2
- data/lib/submodules/ably-ruby/spec/support/serialization_helper.rb +21 -0
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +3 -3
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +6 -14
- data/lib/submodules/ably-ruby/spec/unit/models/channel_details_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_metrics_spec.rb +42 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_occupancy_spec.rb +17 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_status_spec.rb +36 -0
- data/lib/submodules/ably-ruby/spec/unit/models/delta_extras_spec.rb +14 -0
- data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +17 -1
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +97 -0
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +49 -0
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +125 -27
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +14 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +3 -2
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +53 -15
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +19 -6
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +44 -1
- data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +81 -14
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +47 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/unit/client_spec.rb +30 -0
- metadata +88 -25
- data/lib/submodules/ably-ruby/.travis.yml +0 -19
|
@@ -105,6 +105,20 @@ module Ably::Models
|
|
|
105
105
|
end.to_json
|
|
106
106
|
end
|
|
107
107
|
|
|
108
|
+
# The size is the sum over name, data, clientId, and extras in bytes (TO3l8a)
|
|
109
|
+
#
|
|
110
|
+
def size
|
|
111
|
+
%w(name data client_id extras).map do |attr|
|
|
112
|
+
if (value = attributes[attr.to_sym]).is_a?(String)
|
|
113
|
+
value.bytesize
|
|
114
|
+
elsif value.nil?
|
|
115
|
+
0
|
|
116
|
+
else
|
|
117
|
+
value.to_json.bytesize
|
|
118
|
+
end
|
|
119
|
+
end.sum
|
|
120
|
+
end
|
|
121
|
+
|
|
108
122
|
# Assign this message to a ProtocolMessage before delivery to the Ably system
|
|
109
123
|
# @api private
|
|
110
124
|
def assign_to_protocol_message(protocol_message)
|
|
@@ -128,6 +142,9 @@ module Ably::Models
|
|
|
128
142
|
|
|
129
143
|
# Contains any arbitrary key value pairs which may also contain other primitive JSON types, JSON-encodable objects or JSON-encodable arrays.
|
|
130
144
|
# The extras field is provided to contain message metadata and/or ancillary payloads in support of specific functionality, e.g. push
|
|
145
|
+
# 1.2 adds the delta extension which is of type DeltaExtras, and the headers extension, which contains arbitrary string->string key-value pairs,
|
|
146
|
+
# settable at publish time. Unless otherwise specified, the client library should not attempt to do any filtering or validation of the extras
|
|
147
|
+
# field itself, but should treat it opaquely, encoding it and passing it to realtime unaltered.
|
|
131
148
|
# @api private
|
|
132
149
|
def extras
|
|
133
150
|
attributes[:extras].tap do |val|
|
|
@@ -137,15 +154,23 @@ module Ably::Models
|
|
|
137
154
|
end
|
|
138
155
|
end
|
|
139
156
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
157
|
+
# Delta extras extension (TM2i)
|
|
158
|
+
# @return [DeltaExtras, nil]
|
|
159
|
+
# @api private
|
|
160
|
+
def delta_extras
|
|
161
|
+
return nil if attributes[:extras][:delta].nil?
|
|
162
|
+
@delta_extras ||= DeltaExtras.new(attributes[:extras][:delta]).freeze
|
|
143
163
|
end
|
|
144
164
|
|
|
145
165
|
def protocol_message_index
|
|
146
166
|
protocol_message.messages.map(&:object_id).index(self.object_id)
|
|
147
167
|
end
|
|
148
168
|
|
|
169
|
+
private
|
|
170
|
+
def raw_hash_object
|
|
171
|
+
@raw_hash_object
|
|
172
|
+
end
|
|
173
|
+
|
|
149
174
|
def set_attributes_object(new_attributes)
|
|
150
175
|
@attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data, :extras])
|
|
151
176
|
end
|
|
@@ -125,6 +125,20 @@ module Ably::Models
|
|
|
125
125
|
end.to_json
|
|
126
126
|
end
|
|
127
127
|
|
|
128
|
+
# The size is the sum over data and clientId in bytes (TO3l8a)
|
|
129
|
+
#
|
|
130
|
+
def size
|
|
131
|
+
%w(data client_id).map do |attr|
|
|
132
|
+
if (value = attributes[attr.to_sym]).is_a?(String)
|
|
133
|
+
value.bytesize
|
|
134
|
+
elsif value.nil?
|
|
135
|
+
0
|
|
136
|
+
else
|
|
137
|
+
value.to_json.bytesize
|
|
138
|
+
end
|
|
139
|
+
end.sum
|
|
140
|
+
end
|
|
141
|
+
|
|
128
142
|
# Assign this presence message to a ProtocolMessage before delivery to the Ably system
|
|
129
143
|
# @api private
|
|
130
144
|
def assign_to_protocol_message(protocol_message)
|
|
@@ -3,7 +3,7 @@ module Ably::Models
|
|
|
3
3
|
# A ProtocolMessage always relates to a single channel only, but
|
|
4
4
|
# can contain multiple individual Messages or PresenceMessages.
|
|
5
5
|
# ProtocolMessages are serially numbered on a connection.
|
|
6
|
-
# See the {http://
|
|
6
|
+
# See the {http://ably.com/docs/client-lib-development-guide/protocol/ Ably client library developer documentation}
|
|
7
7
|
# for further details on the members of a ProtocolMessage
|
|
8
8
|
#
|
|
9
9
|
# @!attribute [r] action
|
|
@@ -11,7 +11,7 @@ module Ably::Models
|
|
|
11
11
|
# @!attribute [r] auth
|
|
12
12
|
# @return [Ably::Models::AuthDetails] Authentication details used to perform authentication upgrades over an existing transport
|
|
13
13
|
# @!attribute [r] count
|
|
14
|
-
# @return [Integer] The count field is used for ACK and NACK actions. See {http://
|
|
14
|
+
# @return [Integer] The count field is used for ACK and NACK actions. See {http://ably.com/docs/client-lib-development-guide/protocol/#message-acknowledgement message acknowledgement protocol}
|
|
15
15
|
# @!attribute [r] error
|
|
16
16
|
# @return [ErrorInfo] Contains error information
|
|
17
17
|
# @!attribute [r] channel
|
|
@@ -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
|
|
@@ -98,7 +98,7 @@ module Ably::Models
|
|
|
98
98
|
|
|
99
99
|
# @!attribute [r] mac
|
|
100
100
|
# @return [String] the Message Authentication Code for this request. See the
|
|
101
|
-
# {https://www.ably.
|
|
101
|
+
# {https://www.ably.com/docs Ably Authentication documentation} for more details.
|
|
102
102
|
def mac
|
|
103
103
|
attributes.fetch(:mac) { raise Ably::Exceptions::InvalidTokenRequest, 'MAC is missing' }
|
|
104
104
|
end
|
|
@@ -6,8 +6,18 @@
|
|
|
6
6
|
module Ably
|
|
7
7
|
# Fallback hosts to use when a connection to rest/realtime.ably.io is not possible due to
|
|
8
8
|
# network failures either at the client, between the client and Ably, within an Ably data center, or at the IO domain registrar
|
|
9
|
+
# see https://ably.com/docs/client-lib-development-guide/features/#RSC15a
|
|
9
10
|
#
|
|
10
|
-
|
|
11
|
+
FALLBACK_DOMAIN = 'ably-realtime.com'.freeze
|
|
12
|
+
FALLBACK_IDS = %w(a b c d e).freeze
|
|
13
|
+
|
|
14
|
+
# Default production fallbacks a.ably-realtime.com ... e.ably-realtime.com
|
|
15
|
+
FALLBACK_HOSTS = FALLBACK_IDS.map { |host| "#{host}.#{FALLBACK_DOMAIN}".freeze }.freeze
|
|
16
|
+
|
|
17
|
+
# Custom environment default fallbacks {ENV}-a-fallback.ably-realtime.com ... {ENV}-a-fallback.ably-realtime.com
|
|
18
|
+
CUSTOM_ENVIRONMENT_FALLBACKS_SUFFIXES = FALLBACK_IDS.map do |host|
|
|
19
|
+
"-#{host}-fallback.#{FALLBACK_DOMAIN}".freeze
|
|
20
|
+
end.freeze
|
|
11
21
|
|
|
12
22
|
INTERNET_CHECK = {
|
|
13
23
|
url: '//internet-up.ably-realtime.com/is-the-internet-up.txt',
|
|
@@ -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
|
|
@@ -2,10 +2,10 @@ require 'ably/auth'
|
|
|
2
2
|
|
|
3
3
|
module Ably
|
|
4
4
|
module Realtime
|
|
5
|
-
# Auth is responsible for authentication with {https://www.ably.
|
|
5
|
+
# Auth is responsible for authentication with {https://www.ably.com Ably} using basic or token authentication
|
|
6
6
|
# This {Ably::Realtime::Auth Realtime::Auth} class wraps the {Ably::Auth Synchronous Ably::Auth} class in an EventMachine friendly way using Deferrables for all IO. See {Ably::Auth Ably::Auth} for more information
|
|
7
7
|
#
|
|
8
|
-
# Find out more about Ably authentication at: https://www.ably.
|
|
8
|
+
# Find out more about Ably authentication at: https://www.ably.com/docs/general/authentication/
|
|
9
9
|
#
|
|
10
10
|
# @!attribute [r] client_id
|
|
11
11
|
# (see Ably::Auth#client_id)
|
|
@@ -37,7 +37,9 @@ module Ably::Realtime
|
|
|
37
37
|
# library, such as returning to attached whne detach has failed
|
|
38
38
|
if attached_protocol_message
|
|
39
39
|
update_presence_sync_state_following_attached attached_protocol_message
|
|
40
|
-
channel.
|
|
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.set_attached_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
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Ably::Realtime
|
|
2
|
+
class Channel
|
|
3
|
+
# Represents properties of a channel and its state
|
|
4
|
+
class ChannelProperties
|
|
5
|
+
# {Ably::Realtime::Channel} this object associated with
|
|
6
|
+
# @return [Ably::Realtime::Channel]
|
|
7
|
+
attr_reader :channel
|
|
8
|
+
|
|
9
|
+
# Contains the last channelSerial received in an ATTACHED ProtocolMesage for the channel, see RTL15a
|
|
10
|
+
#
|
|
11
|
+
# @return [String]
|
|
12
|
+
attr_reader :attach_serial
|
|
13
|
+
|
|
14
|
+
def initialize(channel)
|
|
15
|
+
@channel = channel
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @api private
|
|
19
|
+
def set_attach_serial(attach_serial)
|
|
20
|
+
@attach_serial = attach_serial
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -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
|
|
@@ -79,6 +80,10 @@ module Ably
|
|
|
79
80
|
# @return [Hash]
|
|
80
81
|
attr_reader :options
|
|
81
82
|
|
|
83
|
+
# Properties of a channel and its state
|
|
84
|
+
# @return [{Ably::Realtime::Channel::ChannelProperties}]
|
|
85
|
+
attr_reader :properties
|
|
86
|
+
|
|
82
87
|
# When a channel failure occurs this attribute contains the Ably Exception
|
|
83
88
|
# @return [Ably::Models::ErrorInfo,Ably::Exceptions::BaseAblyException]
|
|
84
89
|
attr_reader :error_reason
|
|
@@ -88,22 +93,25 @@ module Ably
|
|
|
88
93
|
# @api private
|
|
89
94
|
attr_reader :manager
|
|
90
95
|
|
|
91
|
-
#
|
|
92
|
-
# @return [
|
|
96
|
+
# Flag that specifies whether channel is resuming attachment(reattach) or is doing a 'clean attach' RTL4j1
|
|
97
|
+
# @return [Bolean]
|
|
93
98
|
# @api private
|
|
94
|
-
attr_reader :
|
|
99
|
+
attr_reader :attach_resume
|
|
100
|
+
|
|
101
|
+
# ChannelOptions params attrribute (#RTL4k)
|
|
102
|
+
# return [Hash]
|
|
103
|
+
def_delegators :options, :params
|
|
95
104
|
|
|
96
105
|
# Initialize a new Channel object
|
|
97
106
|
#
|
|
98
107
|
# @param client [Ably::Rest::Client]
|
|
99
108
|
# @param name [String] The name of the channel
|
|
100
|
-
# @param channel_options [Hash]
|
|
101
|
-
# @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}
|
|
102
110
|
#
|
|
103
111
|
def initialize(client, name, channel_options = {})
|
|
104
112
|
name = ensure_utf_8(:name, name)
|
|
105
113
|
|
|
106
|
-
|
|
114
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
|
107
115
|
@client = client
|
|
108
116
|
@name = name
|
|
109
117
|
@queue = []
|
|
@@ -112,6 +120,8 @@ module Ably
|
|
|
112
120
|
@state = STATE(state_machine.current_state)
|
|
113
121
|
@manager = ChannelManager.new(self, client.connection)
|
|
114
122
|
@push = PushChannel.new(self)
|
|
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.")
|
|
@@ -292,7 +304,7 @@ module Ably
|
|
|
292
304
|
error = Ably::Exceptions::InvalidRequest.new('option :until_attach is invalid as the channel is not attached' )
|
|
293
305
|
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
|
294
306
|
end
|
|
295
|
-
options[:from_serial] =
|
|
307
|
+
options[:from_serial] = properties.attach_serial
|
|
296
308
|
end
|
|
297
309
|
|
|
298
310
|
async_wrap(callback) do
|
|
@@ -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,27 +341,32 @@ module Ably
|
|
|
319
341
|
@error_reason = nil
|
|
320
342
|
end
|
|
321
343
|
|
|
344
|
+
# Used by {Ably::Modules::StateEmitter} to debug state changes
|
|
322
345
|
# @api private
|
|
323
|
-
def
|
|
324
|
-
|
|
346
|
+
def logger
|
|
347
|
+
client.logger
|
|
325
348
|
end
|
|
326
349
|
|
|
327
350
|
# @api private
|
|
328
|
-
def
|
|
329
|
-
@
|
|
351
|
+
def attach_resume!
|
|
352
|
+
@attach_resume = true
|
|
330
353
|
end
|
|
331
354
|
|
|
332
|
-
# Used by {Ably::Modules::StateEmitter} to debug state changes
|
|
333
355
|
# @api private
|
|
334
|
-
def
|
|
335
|
-
|
|
356
|
+
def reset_attach_resume!
|
|
357
|
+
@attach_resume = false
|
|
336
358
|
end
|
|
337
359
|
|
|
338
360
|
# As we are using a state machine, do not allow change_state to be used
|
|
339
361
|
# #transition_state_machine must be used instead
|
|
340
362
|
private :change_state
|
|
341
363
|
|
|
364
|
+
def need_reattach?
|
|
365
|
+
!!(attaching? || attached?) && !!(options.modes || options.params)
|
|
366
|
+
end
|
|
367
|
+
|
|
342
368
|
private
|
|
369
|
+
|
|
343
370
|
def setup_event_handlers
|
|
344
371
|
__incoming_msgbus__.subscribe(:message) do |message|
|
|
345
372
|
message.decode(client.encoders, options) do |encode_error, error_message|
|
|
@@ -372,3 +399,4 @@ end
|
|
|
372
399
|
require 'ably/realtime/channel/channel_manager'
|
|
373
400
|
require 'ably/realtime/channel/channel_state_machine'
|
|
374
401
|
require 'ably/realtime/channel/push_channel'
|
|
402
|
+
require 'ably/realtime/channel/channel_properties'
|
|
@@ -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)
|