ably 1.1.8 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/check.yml +14 -5
- data/CHANGELOG.md +48 -0
- data/README.md +2 -2
- data/UPDATING.md +30 -0
- data/ably.gemspec +12 -24
- data/lib/ably/auth.rb +8 -8
- data/lib/ably/logger.rb +4 -4
- data/lib/ably/models/channel_details.rb +59 -0
- data/lib/ably/models/channel_metrics.rb +84 -0
- data/lib/ably/models/channel_occupancy.rb +43 -0
- data/lib/ably/models/channel_options.rb +97 -0
- data/lib/ably/models/channel_status.rb +53 -0
- data/lib/ably/models/device_details.rb +1 -1
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
- data/lib/ably/models/message.rb +4 -4
- data/lib/ably/models/protocol_message.rb +19 -7
- data/lib/ably/models/token_details.rb +7 -2
- data/lib/ably/models/token_request.rb +1 -1
- data/lib/ably/modules/ably.rb +1 -1
- data/lib/ably/modules/channels_collection.rb +22 -2
- data/lib/ably/modules/conversions.rb +34 -0
- data/lib/ably/realtime/auth.rb +2 -2
- data/lib/ably/realtime/channel/channel_manager.rb +16 -4
- data/lib/ably/realtime/channel/channel_state_machine.rb +5 -0
- data/lib/ably/realtime/channel.rb +54 -24
- data/lib/ably/realtime/channels.rb +1 -1
- data/lib/ably/rest/channel.rb +33 -34
- data/lib/ably/rest/client.rb +8 -5
- data/lib/ably/rest/middleware/encoder.rb +1 -1
- data/lib/ably/rest/middleware/exceptions.rb +1 -1
- data/lib/ably/rest/middleware/external_exceptions.rb +1 -1
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +1 -1
- data/lib/ably/rest/middleware/logger.rb +1 -1
- data/lib/ably/rest/middleware/parse_json.rb +1 -1
- data/lib/ably/rest/middleware/parse_message_pack.rb +1 -1
- data/lib/ably/util/crypto.rb +1 -1
- data/lib/ably/version.rb +2 -2
- data/spec/acceptance/realtime/channel_spec.rb +247 -21
- data/spec/acceptance/realtime/channels_spec.rb +59 -7
- data/spec/acceptance/realtime/connection_spec.rb +21 -1
- data/spec/acceptance/realtime/message_spec.rb +77 -0
- data/spec/acceptance/rest/auth_spec.rb +18 -0
- data/spec/acceptance/rest/channel_spec.rb +19 -1
- data/spec/acceptance/rest/channels_spec.rb +22 -5
- data/spec/acceptance/rest/client_spec.rb +3 -3
- data/spec/acceptance/rest/message_spec.rb +61 -3
- data/spec/lib/unit/models/channel_options_spec.rb +52 -0
- data/spec/run_parallel_tests +2 -7
- data/spec/unit/logger_spec.rb +6 -14
- data/spec/unit/models/channel_details_spec.rb +30 -0
- data/spec/unit/models/channel_metrics_spec.rb +42 -0
- data/spec/unit/models/channel_occupancy_spec.rb +17 -0
- data/spec/unit/models/channel_status_spec.rb +36 -0
- data/spec/unit/models/message_spec.rb +14 -0
- data/spec/unit/models/protocol_message_spec.rb +53 -7
- data/spec/unit/models/token_details_spec.rb +14 -0
- data/spec/unit/realtime/channels_spec.rb +52 -14
- data/spec/unit/rest/channels_spec.rb +81 -14
- metadata +69 -11
data/lib/ably/models/message.rb
CHANGED
@@ -162,15 +162,15 @@ module Ably::Models
|
|
162
162
|
@delta_extras ||= DeltaExtras.new(attributes[:extras][:delta]).freeze
|
163
163
|
end
|
164
164
|
|
165
|
+
def protocol_message_index
|
166
|
+
protocol_message.messages.map(&:object_id).index(self.object_id)
|
167
|
+
end
|
168
|
+
|
165
169
|
private
|
166
170
|
def raw_hash_object
|
167
171
|
@raw_hash_object
|
168
172
|
end
|
169
173
|
|
170
|
-
def protocol_message_index
|
171
|
-
protocol_message.messages.map(&:object_id).index(self.object_id)
|
172
|
-
end
|
173
|
-
|
174
174
|
def set_attributes_object(new_attributes)
|
175
175
|
@attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data, :extras])
|
176
176
|
end
|
@@ -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
|
@@ -66,6 +66,14 @@ module Ably::Models
|
|
66
66
|
auth: 17
|
67
67
|
)
|
68
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
|
+
|
69
77
|
# Indicates this protocol message action will generate an ACK response such as :message or :presence
|
70
78
|
# @api private
|
71
79
|
def self.ack_required?(for_action)
|
@@ -185,6 +193,10 @@ module Ably::Models
|
|
185
193
|
message_size <= connection_details.max_message_size
|
186
194
|
end
|
187
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
|
@@ -218,27 +230,27 @@ module Ably::Models
|
|
218
230
|
|
219
231
|
# @api private
|
220
232
|
def has_attach_resume_flag?
|
221
|
-
flags &
|
233
|
+
flags & ATTACH_FLAGS_MAPPING[:resume] == ATTACH_FLAGS_MAPPING[:resume] # 2^5
|
222
234
|
end
|
223
235
|
|
224
236
|
# @api private
|
225
237
|
def has_attach_presence_flag?
|
226
|
-
flags &
|
238
|
+
flags & ATTACH_FLAGS_MAPPING[:presence] == ATTACH_FLAGS_MAPPING[:presence] # 2^16
|
227
239
|
end
|
228
240
|
|
229
241
|
# @api private
|
230
242
|
def has_attach_publish_flag?
|
231
|
-
flags &
|
243
|
+
flags & ATTACH_FLAGS_MAPPING[:publish] == ATTACH_FLAGS_MAPPING[:publish] # 2^17
|
232
244
|
end
|
233
245
|
|
234
246
|
# @api private
|
235
247
|
def has_attach_subscribe_flag?
|
236
|
-
flags &
|
248
|
+
flags & ATTACH_FLAGS_MAPPING[:subscribe] == ATTACH_FLAGS_MAPPING[:subscribe] # 2^18
|
237
249
|
end
|
238
250
|
|
239
251
|
# @api private
|
240
252
|
def has_attach_presence_subscribe_flag?
|
241
|
-
flags &
|
253
|
+
flags & ATTACH_FLAGS_MAPPING[:presence_subscribe] == ATTACH_FLAGS_MAPPING[:presence_subscribe] # 2^19
|
242
254
|
end
|
243
255
|
|
244
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
|
data/lib/ably/modules/ably.rb
CHANGED
@@ -6,7 +6,7 @@
|
|
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://
|
9
|
+
# see https://ably.com/docs/client-lib-development-guide/features/#RSC15a
|
10
10
|
#
|
11
11
|
FALLBACK_DOMAIN = 'ably-realtime.com'.freeze
|
12
12
|
FALLBACK_IDS = %w(a b c d e).freeze
|
@@ -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
|
data/lib/ably/realtime/auth.rb
CHANGED
@@ -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)
|
@@ -38,6 +38,8 @@ module Ably::Realtime
|
|
38
38
|
if attached_protocol_message
|
39
39
|
update_presence_sync_state_following_attached attached_protocol_message
|
40
40
|
channel.properties.set_attach_serial(attached_protocol_message.channel_serial)
|
41
|
+
channel.options.set_modes_from_flags(attached_protocol_message.flags)
|
42
|
+
channel.options.set_params(attached_protocol_message.params)
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
@@ -64,6 +66,7 @@ module Ably::Realtime
|
|
64
66
|
end
|
65
67
|
|
66
68
|
channel.properties.set_attach_serial(protocol_message.channel_serial)
|
69
|
+
channel.options.set_modes_from_flags(protocol_message.flags)
|
67
70
|
|
68
71
|
if protocol_message.has_channel_resumed_flag?
|
69
72
|
logger.debug { "ChannelManager: Additional resumed ATTACHED message received for #{channel.state} channel '#{channel.name}'" }
|
@@ -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
|
|
@@ -42,6 +42,11 @@ module Ably::Realtime
|
|
42
42
|
|
43
43
|
before_transition(to: [:attached]) do |channel, current_transition|
|
44
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!
|
45
50
|
end
|
46
51
|
|
47
52
|
after_transition(to: [:detaching]) do |channel, current_transition|
|
@@ -36,6 +36,7 @@ module Ably
|
|
36
36
|
include Ably::Modules::MessageEmitter
|
37
37
|
include Ably::Realtime::Channel::Publisher
|
38
38
|
extend Ably::Modules::Enum
|
39
|
+
extend Forwardable
|
39
40
|
|
40
41
|
# ChannelState
|
41
42
|
# The permited states for this channel
|
@@ -92,17 +93,25 @@ module Ably
|
|
92
93
|
# @api private
|
93
94
|
attr_reader :manager
|
94
95
|
|
96
|
+
# Flag that specifies whether channel is resuming attachment(reattach) or is doing a 'clean attach' RTL4j1
|
97
|
+
# @return [Bolean]
|
98
|
+
# @api private
|
99
|
+
attr_reader :attach_resume
|
100
|
+
|
101
|
+
# ChannelOptions params attrribute (#RTL4k)
|
102
|
+
# return [Hash]
|
103
|
+
def_delegators :options, :params
|
104
|
+
|
95
105
|
# Initialize a new Channel object
|
96
106
|
#
|
97
107
|
# @param client [Ably::Rest::Client]
|
98
108
|
# @param name [String] The name of the channel
|
99
|
-
# @param channel_options [Hash]
|
100
|
-
# @option channel_options [Hash,Ably::Models::CipherParams] :cipher A hash of options or a {Ably::Models::CipherParams} to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of +:cipher+ options
|
109
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
101
110
|
#
|
102
111
|
def initialize(client, name, channel_options = {})
|
103
112
|
name = ensure_utf_8(:name, name)
|
104
113
|
|
105
|
-
|
114
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
106
115
|
@client = client
|
107
116
|
@name = name
|
108
117
|
@queue = []
|
@@ -112,6 +121,7 @@ module Ably
|
|
112
121
|
@manager = ChannelManager.new(self, client.connection)
|
113
122
|
@push = PushChannel.new(self)
|
114
123
|
@properties = ChannelProperties.new(self)
|
124
|
+
@attach_resume = false
|
115
125
|
|
116
126
|
setup_event_handlers
|
117
127
|
setup_presence
|
@@ -129,23 +139,31 @@ module Ably
|
|
129
139
|
# @return [Ably::Util::SafeDeferrable] Deferrable that supports both success (callback) and failure (errback) callbacks
|
130
140
|
#
|
131
141
|
# @example
|
132
|
-
# # Publish a single message
|
142
|
+
# # Publish a single message form
|
133
143
|
# channel.publish 'click', { x: 1, y: 2 }
|
134
144
|
#
|
135
|
-
# # Publish
|
145
|
+
# # Publish a single message with single Hash form
|
146
|
+
# message = { name: 'click', data: { x: 1, y: 2 } }
|
147
|
+
# channel.publish message
|
148
|
+
#
|
149
|
+
# # Publish an array of message Hashes form
|
136
150
|
# messages = [
|
137
|
-
# { name: 'click', { x: 1, y: 2 } },
|
138
|
-
# { name: 'click', { x: 2, y: 3 } }
|
151
|
+
# { name: 'click', data: { x: 1, y: 2 } },
|
152
|
+
# { name: 'click', data: { x: 2, y: 3 } }
|
139
153
|
# ]
|
140
154
|
# channel.publish messages
|
141
155
|
#
|
142
|
-
# # Publish an array of Ably::Models::Message objects
|
156
|
+
# # Publish an array of Ably::Models::Message objects form
|
143
157
|
# messages = [
|
144
|
-
# Ably::Models::Message(name: 'click', { x: 1, y: 2 })
|
145
|
-
# Ably::Models::Message(name: 'click', { x: 2, y: 3 })
|
158
|
+
# Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
159
|
+
# Ably::Models::Message(name: 'click', data: { x: 2, y: 3 })
|
146
160
|
# ]
|
147
161
|
# channel.publish messages
|
148
162
|
#
|
163
|
+
# # Publish an array of Ably::Models::Message objects form
|
164
|
+
# message = Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
165
|
+
# channel.publish message
|
166
|
+
#
|
149
167
|
# channel.publish('click', 'body') do |message|
|
150
168
|
# puts "#{message.name} event received with #{message.data}"
|
151
169
|
# end
|
@@ -165,13 +183,7 @@ module Ably
|
|
165
183
|
return Ably::Util::SafeDeferrable.new_and_fail_immediately(logger, error)
|
166
184
|
end
|
167
185
|
|
168
|
-
messages =
|
169
|
-
name
|
170
|
-
else
|
171
|
-
name = ensure_utf_8(:name, name, allow_nil: true)
|
172
|
-
ensure_supported_payload data
|
173
|
-
[{ name: name, data: data }.merge(attributes)]
|
174
|
-
end
|
186
|
+
messages = build_messages(name, data, attributes) # (RSL1a, RSL1b)
|
175
187
|
|
176
188
|
if messages.length > Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE
|
177
189
|
error = Ably::Exceptions::InvalidRequest.new("It is not possible to publish more than #{Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE} messages with a single publish request.")
|
@@ -309,6 +321,16 @@ module Ably
|
|
309
321
|
)
|
310
322
|
end
|
311
323
|
|
324
|
+
# Sets or updates the stored channel options. (#RTL16)
|
325
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
326
|
+
# @return [Ably::Models::ChannelOptions]
|
327
|
+
def set_options(channel_options)
|
328
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
329
|
+
|
330
|
+
manager.request_reattach if need_reattach?
|
331
|
+
end
|
332
|
+
alias options= set_options
|
333
|
+
|
312
334
|
# @api private
|
313
335
|
def set_channel_error_reason(error)
|
314
336
|
@error_reason = error
|
@@ -319,24 +341,32 @@ module Ably
|
|
319
341
|
@error_reason = nil
|
320
342
|
end
|
321
343
|
|
322
|
-
# @api private
|
323
|
-
def update_options(channel_options)
|
324
|
-
@options = channel_options.clone.freeze
|
325
|
-
end
|
326
|
-
alias set_options update_options # (RSL7)
|
327
|
-
alias options= update_options
|
328
|
-
|
329
344
|
# Used by {Ably::Modules::StateEmitter} to debug state changes
|
330
345
|
# @api private
|
331
346
|
def logger
|
332
347
|
client.logger
|
333
348
|
end
|
334
349
|
|
350
|
+
# @api private
|
351
|
+
def attach_resume!
|
352
|
+
@attach_resume = true
|
353
|
+
end
|
354
|
+
|
355
|
+
# @api private
|
356
|
+
def reset_attach_resume!
|
357
|
+
@attach_resume = false
|
358
|
+
end
|
359
|
+
|
335
360
|
# As we are using a state machine, do not allow change_state to be used
|
336
361
|
# #transition_state_machine must be used instead
|
337
362
|
private :change_state
|
338
363
|
|
364
|
+
def need_reattach?
|
365
|
+
!!(attaching? || attached?) && !!(options.modes || options.params)
|
366
|
+
end
|
367
|
+
|
339
368
|
private
|
369
|
+
|
340
370
|
def setup_event_handlers
|
341
371
|
__incoming_msgbus__.subscribe(:message) do |message|
|
342
372
|
message.decode(client.encoders, options) do |encode_error, error_message|
|
@@ -13,7 +13,7 @@ module Ably
|
|
13
13
|
# Return a {Ably::Realtime::Channel} for the given name
|
14
14
|
#
|
15
15
|
# @param name [String] The name of the channel
|
16
|
-
# @param channel_options [Hash]
|
16
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
17
17
|
# @return [Ably::Realtime::Channel}
|
18
18
|
#
|
19
19
|
def get(*args)
|
data/lib/ably/rest/channel.rb
CHANGED
@@ -28,21 +28,20 @@ module Ably
|
|
28
28
|
#
|
29
29
|
# @param client [Ably::Rest::Client]
|
30
30
|
# @param name [String] The name of the channel
|
31
|
-
# @param channel_options [Hash]
|
32
|
-
# @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
|
31
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
33
32
|
#
|
34
33
|
def initialize(client, name, channel_options = {})
|
35
34
|
name = (ensure_utf_8 :name, name)
|
36
35
|
|
37
|
-
|
36
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
38
37
|
@client = client
|
39
38
|
@name = name
|
40
39
|
@push = PushChannel.new(self)
|
41
40
|
end
|
42
41
|
|
43
|
-
# Publish one or more messages to the channel.
|
42
|
+
# Publish one or more messages to the channel. Five overloaded forms
|
44
43
|
# @param name [String, Array<Ably::Models::Message|Hash>, Ably::Models::Message, 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, or a single Ably::Model::Message object
|
45
|
-
# @param data [String,
|
44
|
+
# @param data [String, Array, Hash, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument, in which case an optional hash of query parameters
|
46
45
|
# @param attributes [Hash, nil] Optional additional message attributes such as :extras, :id, :client_id or :connection_id, applied when name attribute is nil or a string (Deprecated, will be removed in 2.0 in favour of constructing a Message object)
|
47
46
|
# @return [Boolean] true if the message was published, otherwise false
|
48
47
|
#
|
@@ -50,42 +49,33 @@ module Ably
|
|
50
49
|
# # Publish a single message with (name, data) form
|
51
50
|
# channel.publish 'click', { x: 1, y: 2 }
|
52
51
|
#
|
53
|
-
# # Publish
|
52
|
+
# # Publish a single message with single Hash form
|
53
|
+
# message = { name: 'click', data: { x: 1, y: 2 } }
|
54
|
+
# channel.publish message
|
55
|
+
#
|
56
|
+
# # Publish an array of message Hashes form
|
54
57
|
# messages = [
|
55
58
|
# { name: 'click', data: { x: 1, y: 2 } },
|
56
59
|
# { name: 'click', data: { x: 2, y: 3 } }
|
57
60
|
# ]
|
58
61
|
# channel.publish messages
|
59
62
|
#
|
60
|
-
# # Publish an array of Ably::Models::Message objects
|
63
|
+
# # Publish an array of Ably::Models::Message objects form
|
61
64
|
# messages = [
|
62
|
-
# Ably::Models::Message(name: 'click', { x: 1, y: 2 })
|
63
|
-
# Ably::Models::Message(name: 'click', { x: 2, y: 3 })
|
65
|
+
# Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
66
|
+
# Ably::Models::Message(name: 'click', data: { x: 2, y: 3 })
|
64
67
|
# ]
|
65
68
|
# channel.publish messages
|
66
69
|
#
|
67
|
-
# # Publish a single Ably::Models::Message object
|
68
|
-
#
|
69
|
-
# message
|
70
|
-
# channel.publish message, quickAck: 'true'
|
70
|
+
# # Publish a single Ably::Models::Message object form
|
71
|
+
# message = Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
72
|
+
# channel.publish message
|
71
73
|
#
|
72
|
-
def publish(
|
73
|
-
|
74
|
-
|
75
|
-
[first, second]
|
76
|
-
elsif first.kind_of?(Ably::Models::Message)
|
77
|
-
# (Message, qs_params) form
|
78
|
-
[[first], second]
|
79
|
-
else
|
80
|
-
# (name, data, attributes) form
|
81
|
-
first = ensure_utf_8(:name, first, allow_nil: true)
|
82
|
-
ensure_supported_payload second
|
83
|
-
# RSL1h - attributes as an extra method parameter is extra-spec but need to
|
84
|
-
# keep it for backcompat until version 2
|
85
|
-
[[{ name: first, data: second }.merge(third)], nil]
|
86
|
-
end
|
74
|
+
def publish(name, data = nil, attributes = {})
|
75
|
+
qs_params = nil
|
76
|
+
qs_params = data if name.kind_of?(Enumerable) || name.kind_of?(Ably::Models::Message)
|
87
77
|
|
88
|
-
messages
|
78
|
+
messages = build_messages(name, data, attributes) # (RSL1a, RSL1b)
|
89
79
|
|
90
80
|
if messages.sum(&:size) > (max_message_size = client.max_message_size || Ably::Rest::Client::MAX_MESSAGE_SIZE)
|
91
81
|
raise Ably::Exceptions::MaxMessageSizeExceeded.new("Maximum message size exceeded #{max_message_size} bytes.")
|
@@ -163,14 +153,23 @@ module Ably
|
|
163
153
|
@presence ||= Presence.new(client, self)
|
164
154
|
end
|
165
155
|
|
166
|
-
#
|
167
|
-
|
168
|
-
|
156
|
+
# Sets or updates the stored channel options. (#RSL7)
|
157
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
158
|
+
# @return [Ably::Models::ChannelOptions]
|
159
|
+
def set_options(channel_options)
|
160
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
161
|
+
end
|
162
|
+
alias options= set_options
|
163
|
+
|
164
|
+
# Makes GET request for channel details (#RSL8, #RSL8a)
|
165
|
+
#
|
166
|
+
# @return [Ably::Models::ChannelDetails]
|
167
|
+
def status
|
168
|
+
Ably::Models::ChannelDetails.new(client.get(base_path).body)
|
169
169
|
end
|
170
|
-
alias set_options update_options # (RSL7)
|
171
|
-
alias options= update_options
|
172
170
|
|
173
171
|
private
|
172
|
+
|
174
173
|
def base_path
|
175
174
|
"/channels/#{URI.encode_www_form_component(name)}"
|
176
175
|
end
|
data/lib/ably/rest/client.rb
CHANGED
@@ -4,7 +4,7 @@ require 'logger'
|
|
4
4
|
require 'uri'
|
5
5
|
|
6
6
|
require 'typhoeus'
|
7
|
-
require 'typhoeus
|
7
|
+
require 'faraday/typhoeus'
|
8
8
|
|
9
9
|
require 'ably/rest/middleware/exceptions'
|
10
10
|
|
@@ -55,7 +55,7 @@ module Ably
|
|
55
55
|
# @return [Symbol]
|
56
56
|
attr_reader :protocol
|
57
57
|
|
58
|
-
# Client agent i.e. `example-gem/1.2.0 ably-ruby/1.1.5 ruby/1.
|
58
|
+
# Client agent i.e. `example-gem/1.2.0 ably-ruby/1.1.5 ruby/3.1.1`
|
59
59
|
# @return [String]
|
60
60
|
attr_reader :agent
|
61
61
|
|
@@ -139,7 +139,7 @@ module Ably
|
|
139
139
|
# @option options [Symbol] :protocol (:msgpack) Protocol used to communicate with Ably, :json and :msgpack currently supported
|
140
140
|
# @option options [Boolean] :use_binary_protocol (true) When true will use the MessagePack binary protocol, when false it will use JSON encoding. This option will overide :protocol option
|
141
141
|
# @option options [Logger::Severity,Symbol] :log_level (Logger::WARN) Log level for the standard Logger that outputs to STDOUT. Can be set to :fatal (Logger::FATAL), :error (Logger::ERROR), :warn (Logger::WARN), :info (Logger::INFO), :debug (Logger::DEBUG) or :none
|
142
|
-
# @option options [Logger] :logger A custom logger can be used however it must adhere to the Ruby Logger interface, see http://www.ruby-doc.org/stdlib-1.
|
142
|
+
# @option options [Logger] :logger A custom logger can be used however it must adhere to the Ruby Logger interface, see http://www.ruby-doc.org/stdlib-3.1.1/libdoc/logger/rdoc/Logger.html
|
143
143
|
# @option options [String] :client_id client ID identifying this connection to other clients
|
144
144
|
# @option options [String] :auth_url a URL to be used to GET or POST a set of token request params, to obtain a signed token request
|
145
145
|
# @option options [Hash] :auth_headers a set of application-specific headers to be added to any request made to the +auth_url+
|
@@ -147,7 +147,7 @@ module Ably
|
|
147
147
|
# @option options [Symbol] :auth_method (:get) HTTP method to use with +auth_url+, must be either +:get+ or +:post+
|
148
148
|
# @option options [Proc] :auth_callback when provided, the Proc will be called with the token params hash as the first argument, whenever a new token is required.
|
149
149
|
# The Proc should return a token string, {Ably::Models::TokenDetails} or JSON equivalent, {Ably::Models::TokenRequest} or JSON equivalent
|
150
|
-
# @option options [Boolean] :query_time when true will query the {https://www.ably.
|
150
|
+
# @option options [Boolean] :query_time when true will query the {https://www.ably.com Ably} system for the current time instead of using the local time
|
151
151
|
# @option options [Hash] :default_token_params convenience to pass in +token_params+ that will be used as a default for all token requests. See {Auth#create_token_request}
|
152
152
|
#
|
153
153
|
# @option options [Integer] :http_open_timeout (4 seconds) timeout in seconds for opening an HTTP connection for all HTTP requests
|
@@ -199,10 +199,13 @@ module Ably
|
|
199
199
|
@custom_tls_port = options.delete(:tls_port)
|
200
200
|
@add_request_ids = options.delete(:add_request_ids)
|
201
201
|
@log_retries_as_info = options.delete(:log_retries_as_info)
|
202
|
-
@idempotent_rest_publishing = options.delete(:idempotent_rest_publishing) || Ably.major_minor_version_numeric > 1.1
|
203
202
|
@max_message_size = options.delete(:max_message_size) || MAX_MESSAGE_SIZE
|
204
203
|
@max_frame_size = options.delete(:max_frame_size) || MAX_FRAME_SIZE
|
205
204
|
|
205
|
+
if (@idempotent_rest_publishing = options.delete(:idempotent_rest_publishing)).nil?
|
206
|
+
@idempotent_rest_publishing = Ably::PROTOCOL_VERSION.to_f > 1.1
|
207
|
+
end
|
208
|
+
|
206
209
|
if options[:fallback_hosts_use_default] && options[:fallback_hosts]
|
207
210
|
raise ArgumentError, "fallback_hosts_use_default cannot be set to try when fallback_hosts is also provided"
|
208
211
|
end
|
@@ -5,7 +5,7 @@ module Ably
|
|
5
5
|
module Rest
|
6
6
|
module Middleware
|
7
7
|
# Encode the body of the message according to the mime type
|
8
|
-
class Encoder <
|
8
|
+
class Encoder < Faraday::Middleware
|
9
9
|
CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
|
10
10
|
|
11
11
|
def call(env)
|
@@ -6,7 +6,7 @@ module Ably
|
|
6
6
|
module Middleware
|
7
7
|
# HTTP exceptions raised by Ably due to an error status code
|
8
8
|
# Ably returns JSON/Msgpack error codes and messages so include this if possible in the exception messages
|
9
|
-
class Exceptions < Faraday::
|
9
|
+
class Exceptions < Faraday::Middleware
|
10
10
|
def on_complete(env)
|
11
11
|
if env.status >= 400
|
12
12
|
error_status_code = env.status
|