ably 1.1.7 → 1.2.1
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 +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