ably 1.1.7 → 1.2.1
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 +1 -1
- data/CHANGELOG.md +99 -0
- data/COPYRIGHT +1 -1
- data/README.md +2 -2
- data/SPEC.md +0 -7
- data/UPDATING.md +30 -0
- data/ably.gemspec +11 -24
- data/lib/ably/auth.rb +8 -8
- data/lib/ably/logger.rb +4 -4
- data/lib/ably/models/channel_options.rb +97 -0
- data/lib/ably/models/connection_details.rb +8 -2
- data/lib/ably/models/delta_extras.rb +29 -0
- data/lib/ably/models/device_details.rb +1 -1
- data/lib/ably/models/error_info.rb +6 -2
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
- data/lib/ably/models/message.rb +14 -3
- data/lib/ably/models/protocol_message.rb +23 -14
- 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 +10 -1
- data/lib/ably/realtime/channel/publisher.rb +3 -2
- data/lib/ably/realtime/channel.rb +54 -22
- data/lib/ably/realtime/channels.rb +1 -1
- data/lib/ably/realtime/connection/connection_manager.rb +13 -4
- data/lib/ably/realtime/connection/connection_state_machine.rb +4 -0
- data/lib/ably/realtime/connection.rb +0 -3
- data/lib/ably/rest/channel.rb +28 -35
- data/lib/ably/rest/client.rb +23 -8
- 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 +458 -27
- data/spec/acceptance/realtime/channels_spec.rb +59 -7
- data/spec/acceptance/realtime/connection_failures_spec.rb +56 -1
- data/spec/acceptance/realtime/connection_spec.rb +270 -1
- data/spec/acceptance/realtime/message_spec.rb +77 -0
- data/spec/acceptance/realtime/presence_spec.rb +18 -1
- data/spec/acceptance/rest/auth_spec.rb +18 -0
- data/spec/acceptance/rest/channel_spec.rb +73 -11
- data/spec/acceptance/rest/channels_spec.rb +23 -6
- 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/support/test_app.rb +1 -1
- data/spec/unit/logger_spec.rb +6 -14
- data/spec/unit/models/delta_extras_spec.rb +14 -0
- data/spec/unit/models/error_info_spec.rb +17 -1
- data/spec/unit/models/message_spec.rb +38 -0
- data/spec/unit/models/protocol_message_spec.rb +77 -27
- data/spec/unit/models/token_details_spec.rb +14 -0
- data/spec/unit/realtime/channel_spec.rb +2 -1
- data/spec/unit/realtime/channels_spec.rb +53 -15
- data/spec/unit/rest/channel_spec.rb +40 -7
- data/spec/unit/rest/channels_spec.rb +81 -14
- data/spec/unit/rest/client_spec.rb +27 -0
- metadata +46 -11
data/lib/ably/rest/channel.rb
CHANGED
@@ -23,27 +23,25 @@ module Ably
|
|
23
23
|
attr_reader :push
|
24
24
|
|
25
25
|
IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH = 9 # See spec RSL1k1
|
26
|
-
MAX_MESSAGE_SIZE = 65536 # See spec TO3l8
|
27
26
|
|
28
27
|
# Initialize a new Channel object
|
29
28
|
#
|
30
29
|
# @param client [Ably::Rest::Client]
|
31
30
|
# @param name [String] The name of the channel
|
32
|
-
# @param channel_options [Hash]
|
33
|
-
# @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}
|
34
32
|
#
|
35
33
|
def initialize(client, name, channel_options = {})
|
36
34
|
name = (ensure_utf_8 :name, name)
|
37
35
|
|
38
|
-
|
36
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
39
37
|
@client = client
|
40
38
|
@name = name
|
41
39
|
@push = PushChannel.new(self)
|
42
40
|
end
|
43
41
|
|
44
|
-
# Publish one or more messages to the channel.
|
42
|
+
# Publish one or more messages to the channel. Five overloaded forms
|
45
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
|
46
|
-
# @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
|
47
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)
|
48
46
|
# @return [Boolean] true if the message was published, otherwise false
|
49
47
|
#
|
@@ -51,45 +49,36 @@ module Ably
|
|
51
49
|
# # Publish a single message with (name, data) form
|
52
50
|
# channel.publish 'click', { x: 1, y: 2 }
|
53
51
|
#
|
54
|
-
# # 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
|
55
57
|
# messages = [
|
56
58
|
# { name: 'click', data: { x: 1, y: 2 } },
|
57
59
|
# { name: 'click', data: { x: 2, y: 3 } }
|
58
60
|
# ]
|
59
61
|
# channel.publish messages
|
60
62
|
#
|
61
|
-
# # Publish an array of Ably::Models::Message objects
|
63
|
+
# # Publish an array of Ably::Models::Message objects form
|
62
64
|
# messages = [
|
63
|
-
# Ably::Models::Message(name: 'click', { x: 1, y: 2 })
|
64
|
-
# 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 })
|
65
67
|
# ]
|
66
68
|
# channel.publish messages
|
67
69
|
#
|
68
|
-
# # Publish a single Ably::Models::Message object
|
69
|
-
#
|
70
|
-
# message
|
71
|
-
# 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
|
72
73
|
#
|
73
|
-
def publish(
|
74
|
-
|
75
|
-
|
76
|
-
[first, second]
|
77
|
-
elsif first.kind_of?(Ably::Models::Message)
|
78
|
-
# (Message, qs_params) form
|
79
|
-
[[first], second]
|
80
|
-
else
|
81
|
-
# (name, data, attributes) form
|
82
|
-
first = ensure_utf_8(:name, first, allow_nil: true)
|
83
|
-
ensure_supported_payload second
|
84
|
-
# RSL1h - attributes as an extra method parameter is extra-spec but need to
|
85
|
-
# keep it for backcompat until version 2
|
86
|
-
[[{ name: first, data: second }.merge(third)], nil]
|
87
|
-
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)
|
88
77
|
|
89
|
-
messages
|
78
|
+
messages = build_messages(name, data, attributes) # (RSL1a, RSL1b)
|
90
79
|
|
91
|
-
if messages.sum(&:size) > Ably::Rest::
|
92
|
-
raise Ably::Exceptions::MaxMessageSizeExceeded.new("Maximum message size exceeded #{
|
80
|
+
if messages.sum(&:size) > (max_message_size = client.max_message_size || Ably::Rest::Client::MAX_MESSAGE_SIZE)
|
81
|
+
raise Ably::Exceptions::MaxMessageSizeExceeded.new("Maximum message size exceeded #{max_message_size} bytes.")
|
93
82
|
end
|
94
83
|
|
95
84
|
payload = messages.map do |message|
|
@@ -164,12 +153,16 @@ module Ably
|
|
164
153
|
@presence ||= Presence.new(client, self)
|
165
154
|
end
|
166
155
|
|
167
|
-
#
|
168
|
-
|
169
|
-
|
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)
|
170
161
|
end
|
162
|
+
alias options= set_options
|
171
163
|
|
172
164
|
private
|
165
|
+
|
173
166
|
def base_path
|
174
167
|
"/channels/#{URI.encode_www_form_component(name)}"
|
175
168
|
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
|
|
@@ -25,7 +25,8 @@ module Ably
|
|
25
25
|
# Default Ably domain for REST
|
26
26
|
DOMAIN = 'rest.ably.io'
|
27
27
|
|
28
|
-
|
28
|
+
MAX_MESSAGE_SIZE = 65536 # See spec TO3l8
|
29
|
+
MAX_FRAME_SIZE = 524288 # See spec TO3l8
|
29
30
|
|
30
31
|
# Configuration for HTTP timeouts and HTTP request reattempts to fallback hosts
|
31
32
|
HTTP_DEFAULTS = {
|
@@ -54,7 +55,7 @@ module Ably
|
|
54
55
|
# @return [Symbol]
|
55
56
|
attr_reader :protocol
|
56
57
|
|
57
|
-
# 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`
|
58
59
|
# @return [String]
|
59
60
|
attr_reader :agent
|
60
61
|
|
@@ -118,6 +119,14 @@ module Ably
|
|
118
119
|
# @return [Boolean]
|
119
120
|
attr_reader :idempotent_rest_publishing
|
120
121
|
|
122
|
+
# Max message size (TO2, TO3l8) by default (65536 bytes) 64KiB
|
123
|
+
# @return [Integer]
|
124
|
+
attr_reader :max_message_size
|
125
|
+
|
126
|
+
# Max frame size (TO2, TO3l8) by default (524288 bytes) 512KiB
|
127
|
+
# @return [Integer]
|
128
|
+
attr_reader :max_frame_size
|
129
|
+
|
121
130
|
# Creates a {Ably::Rest::Client Rest Client} and configures the {Ably::Auth} object for the connection.
|
122
131
|
#
|
123
132
|
# @param [Hash,String] options an options Hash used to configure the client and the authentication, or String with an API key or Token ID
|
@@ -130,7 +139,7 @@ module Ably
|
|
130
139
|
# @option options [Symbol] :protocol (:msgpack) Protocol used to communicate with Ably, :json and :msgpack currently supported
|
131
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
|
132
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
|
133
|
-
# @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
|
134
143
|
# @option options [String] :client_id client ID identifying this connection to other clients
|
135
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
|
136
145
|
# @option options [Hash] :auth_headers a set of application-specific headers to be added to any request made to the +auth_url+
|
@@ -138,7 +147,7 @@ module Ably
|
|
138
147
|
# @option options [Symbol] :auth_method (:get) HTTP method to use with +auth_url+, must be either +:get+ or +:post+
|
139
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.
|
140
149
|
# The Proc should return a token string, {Ably::Models::TokenDetails} or JSON equivalent, {Ably::Models::TokenRequest} or JSON equivalent
|
141
|
-
# @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
|
142
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}
|
143
152
|
#
|
144
153
|
# @option options [Integer] :http_open_timeout (4 seconds) timeout in seconds for opening an HTTP connection for all HTTP requests
|
@@ -152,6 +161,8 @@ module Ably
|
|
152
161
|
#
|
153
162
|
# @option options [Boolean] :add_request_ids (false) When true, adds a unique request_id to each request sent to Ably servers. This is handy when reporting issues, because you can refer to a specific request.
|
154
163
|
# @option options [Boolean] :idempotent_rest_publishing (false if ver < 1.2) When true, idempotent publishing is enabled for all messages published via REST
|
164
|
+
# @option options [Integer] :max_message_size (65536 bytes) Maximum size of all messages when publishing via REST publish()
|
165
|
+
# @option options [Integer] :max_frame_size (524288 bytes) Maximum size of frame
|
155
166
|
#
|
156
167
|
# @return [Ably::Rest::Client]
|
157
168
|
#
|
@@ -188,8 +199,12 @@ module Ably
|
|
188
199
|
@custom_tls_port = options.delete(:tls_port)
|
189
200
|
@add_request_ids = options.delete(:add_request_ids)
|
190
201
|
@log_retries_as_info = options.delete(:log_retries_as_info)
|
191
|
-
@
|
202
|
+
@max_message_size = options.delete(:max_message_size) || MAX_MESSAGE_SIZE
|
203
|
+
@max_frame_size = options.delete(:max_frame_size) || MAX_FRAME_SIZE
|
192
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
|
193
208
|
|
194
209
|
if options[:fallback_hosts_use_default] && options[:fallback_hosts]
|
195
210
|
raise ArgumentError, "fallback_hosts_use_default cannot be set to try when fallback_hosts is also provided"
|
@@ -365,8 +380,8 @@ module Ably
|
|
365
380
|
send_request(method, path, params, headers: headers)
|
366
381
|
end
|
367
382
|
when :post, :patch, :put
|
368
|
-
if body.to_json.bytesize >
|
369
|
-
raise Ably::Exceptions::MaxFrameSizeExceeded.new("Maximum frame size exceeded #{
|
383
|
+
if body.to_json.bytesize > max_frame_size
|
384
|
+
raise Ably::Exceptions::MaxFrameSizeExceeded.new("Maximum frame size exceeded #{max_frame_size} bytes.")
|
370
385
|
end
|
371
386
|
path_with_params = Addressable::URI.new
|
372
387
|
path_with_params.query_values = params || {}
|
@@ -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
|
@@ -5,7 +5,7 @@ module Ably
|
|
5
5
|
module Middleware
|
6
6
|
# HTTP exceptions raised due to a status code error on a 3rd party site
|
7
7
|
# Used by auth calls
|
8
|
-
class ExternalExceptions < Faraday::
|
8
|
+
class ExternalExceptions < Faraday::Middleware
|
9
9
|
def on_complete(env)
|
10
10
|
if env.status >= 400
|
11
11
|
error_status_code = env.status
|
@@ -4,7 +4,7 @@ require 'json'
|
|
4
4
|
module Ably
|
5
5
|
module Rest
|
6
6
|
module Middleware
|
7
|
-
class FailIfUnsupportedMimeType < Faraday::
|
7
|
+
class FailIfUnsupportedMimeType < Faraday::Middleware
|
8
8
|
def on_complete(env)
|
9
9
|
unless env.response_headers['Ably-Middleware-Parsed'] == true
|
10
10
|
# Ignore empty body with success status code for no body response
|
@@ -4,7 +4,7 @@ require 'json'
|
|
4
4
|
module Ably
|
5
5
|
module Rest
|
6
6
|
module Middleware
|
7
|
-
class ParseJson < Faraday::
|
7
|
+
class ParseJson < Faraday::Middleware
|
8
8
|
def on_complete(env)
|
9
9
|
if env.response_headers['Content-Type'] == 'application/json'
|
10
10
|
env.body = parse(env.body) unless env.response_headers['Ably-Middleware-Parsed'] == true
|
@@ -4,7 +4,7 @@ require 'msgpack'
|
|
4
4
|
module Ably
|
5
5
|
module Rest
|
6
6
|
module Middleware
|
7
|
-
class ParseMessagePack < Faraday::
|
7
|
+
class ParseMessagePack < Faraday::Middleware
|
8
8
|
def on_complete(env)
|
9
9
|
if env.response_headers['Content-Type'] == 'application/x-msgpack'
|
10
10
|
env.body = parse(env.body) unless env.response_headers['Ably-Middleware-Parsed'] == true
|
data/lib/ably/util/crypto.rb
CHANGED
@@ -30,7 +30,7 @@ module Ably::Util
|
|
30
30
|
# crypto.decrypt(decrypted) # => 'secret text'
|
31
31
|
#
|
32
32
|
def initialize(params)
|
33
|
-
@fixed_iv = params
|
33
|
+
@fixed_iv = params[:fixed_iv]
|
34
34
|
@cipher_params = Ably::Models::CipherParams(params)
|
35
35
|
end
|
36
36
|
|
data/lib/ably/version.rb
CHANGED