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