ably 1.1.8 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -0
- data/README.md +1 -1
- data/UPDATING.md +30 -0
- data/lib/ably/auth.rb +3 -3
- data/lib/ably/models/channel_options.rb +97 -0
- 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 +17 -5
- data/lib/ably/models/token_details.rb +7 -2
- data/lib/ably/modules/channels_collection.rb +22 -2
- data/lib/ably/modules/conversions.rb +34 -0
- 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 +26 -34
- data/lib/ably/rest/client.rb +4 -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 +1 -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 +1 -1
- data/spec/acceptance/rest/channels_spec.rb +22 -5
- data/spec/acceptance/rest/client_spec.rb +2 -2
- data/spec/acceptance/rest/message_spec.rb +61 -3
- data/spec/lib/unit/models/channel_options_spec.rb +52 -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 +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f42d74184e0de100d535fa3c01595727b78a6d2cd6018d1743e2593c20fe7ed7
|
4
|
+
data.tar.gz: db674f894bc006187816c0e51df19b84a7473d178b8360271a27640e7b3e4f6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5950df21ad66e4c59eb6bd772ab71aa91b421679139166ddaa9076ea4fc7cc9a6eb9993a3f4e15e30a2d362a05c008587b153617c967da6a41aa6e0efdc3f091
|
7
|
+
data.tar.gz: a9d61d9b6c12397df274f55028a1fcbd6c285235cb489027188c799949466a6a74c4e6ea3829bd44851be48af14e05a2f7d49494ea61d1ea190176773079df23
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,51 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v1.2.0](https://github.com/ably/ably-ruby/tree/v1.2.0)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/ably/ably-ruby/compare/v1.1.8...v1.2.0)
|
6
|
+
|
7
|
+
This release updates ably-ruby to be compliant with the 1.2 version of the Ably client library feature specification. There are some minor breaking changes, please see [the migration guide](./UPDATING.md) for more information.
|
8
|
+
|
9
|
+
**Closed issues:**
|
10
|
+
|
11
|
+
- create migration guide for the upgrade to ruby 1.2 [\#347](https://github.com/ably/ably-ruby/issues/347)
|
12
|
+
- Write spec tests for RTL17 [\#304](https://github.com/ably/ably-ruby/issues/304)
|
13
|
+
- Write spec tests for RTL16, RTL16a [\#303](https://github.com/ably/ably-ruby/issues/303)
|
14
|
+
- Write spec tests for RTL4m [\#302](https://github.com/ably/ably-ruby/issues/302)
|
15
|
+
- Write spec tests for RTL4l [\#301](https://github.com/ably/ably-ruby/issues/301)
|
16
|
+
- Write spec tests for RTL4k, RTL4k1 [\#300](https://github.com/ably/ably-ruby/issues/300)
|
17
|
+
- Write spec tests for RTL4j, RTL4j1, RTL4j2 [\#299](https://github.com/ably/ably-ruby/issues/299)
|
18
|
+
- Write spec tests for RTS3c, RTS3c1 [\#298](https://github.com/ably/ably-ruby/issues/298)
|
19
|
+
- Write spec tests for RTS3a [\#297](https://github.com/ably/ably-ruby/issues/297)
|
20
|
+
- Add support for RTL21 [\#296](https://github.com/ably/ably-ruby/issues/296)
|
21
|
+
- Add support for RTL17 [\#292](https://github.com/ably/ably-ruby/issues/292)
|
22
|
+
- Add support for RTL16, RTL16a [\#291](https://github.com/ably/ably-ruby/issues/291)
|
23
|
+
- Add support for RTL4m [\#290](https://github.com/ably/ably-ruby/issues/290)
|
24
|
+
- Add support for RTL4l [\#289](https://github.com/ably/ably-ruby/issues/289)
|
25
|
+
- Add support for RTL4k, RTL4k1 [\#288](https://github.com/ably/ably-ruby/issues/288)
|
26
|
+
- Add support for RTL4j, RTL4j1, RTL4j2 [\#287](https://github.com/ably/ably-ruby/issues/287)
|
27
|
+
- Add support for RTS3c, RTS3c1 [\#286](https://github.com/ably/ably-ruby/issues/286)
|
28
|
+
- Add support for RTS3a [\#285](https://github.com/ably/ably-ruby/issues/285)
|
29
|
+
- Write spec tests for RSL1a, b, h, k1, k2, l, l1 \(Channels\) [\#283](https://github.com/ably/ably-ruby/issues/283)
|
30
|
+
- Write spec tests for RSN3a, c \(Channels\) [\#282](https://github.com/ably/ably-ruby/issues/282)
|
31
|
+
- Write spec tests for RSA4b, b1, c, RSA16 \(Authentication\) [\#281](https://github.com/ably/ably-ruby/issues/281)
|
32
|
+
- Add support for RSN3a, c \(Channels\) [\#269](https://github.com/ably/ably-ruby/issues/269)
|
33
|
+
- Add support for RSA4b, b1, c, RSA16 \(Authentication\) [\#268](https://github.com/ably/ably-ruby/issues/268)
|
34
|
+
- Add support for RSC7a, RSC7c \(RestClient\)
|
35
|
+
[\#266](https://github.com/ably/ably-ruby/issues/266)
|
36
|
+
- Add support for Test Guidance G4 [\#265](https://github.com/ably/ably-ruby/issues/265)
|
37
|
+
- Add support for TO3o, TO3p [\#264](https://github.com/ably/ably-ruby/issues/264)
|
38
|
+
|
39
|
+
**Merged pull requests:**
|
40
|
+
|
41
|
+
- Add migration guide from 1.1.8 to 1.2.0 [\#348](https://github.com/ably/ably-ruby/pull/348) ([TheSmartnik](https://github.com/TheSmartnik))
|
42
|
+
- RTL21 [\#345](https://github.com/ably/ably-ruby/pull/345) ([lukaszsliwa](https://github.com/lukaszsliwa))
|
43
|
+
- RTL4j [\#341](https://github.com/ably/ably-ruby/pull/341) ([TheSmartnik](https://github.com/TheSmartnik))
|
44
|
+
- RSL1a, RSL1b [\#340](https://github.com/ably/ably-ruby/pull/340) ([lukaszsliwa](https://github.com/lukaszsliwa))
|
45
|
+
- Add support for RSA4b, b1, c, RSA16 \(Authentication\) [\#338](https://github.com/ably/ably-ruby/pull/338) ([lukaszsliwa](https://github.com/lukaszsliwa))
|
46
|
+
- ChannelOptions related tasks [\#336](https://github.com/ably/ably-ruby/pull/336) ([TheSmartnik](https://github.com/TheSmartnik))
|
47
|
+
- Update RSC7 [\#334](https://github.com/ably/ably-ruby/pull/334) ([TheSmartnik](https://github.com/TheSmartnik))
|
48
|
+
|
3
49
|
## [v1.1.8](https://github.com/ably/ably-ruby/tree/v1.1.8)
|
4
50
|
|
5
51
|
[Full Changelog](https://github.com/ably/ably-ruby/compare/v1.1.7...v1.1.8)
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
_[Ably](https://ably.com) is the platform that powers synchronized digital experiences in realtime. Whether attending an event in a virtual venue, receiving realtime financial information, or monitoring live car performance data – consumers simply expect realtime digital experiences as standard. Ably provides a suite of APIs to build, extend, and deliver powerful digital experiences in realtime for more than 250 million devices across 80 countries each month. Organizations like Bloomberg, HubSpot, Verizon, and Hopin depend on Ably’s platform to offload the growing complexity of business-critical realtime data synchronization at global scale. For more information, see the [Ably documentation](https://ably.com/documentation)._
|
7
7
|
|
8
|
-
This is a Ruby client library for Ably. The library currently targets the [Ably 1.
|
8
|
+
This is a Ruby client library for Ably. The library currently targets the [Ably 1.2 client library specification](https://ably.com/documentation/client-lib-development-guide/features/). You can see the complete list of features this client library supports in [our client library SDKs feature support matrix](https://ably.com/download/sdk-feature-support-matrix).
|
9
9
|
|
10
10
|
## Supported platforms
|
11
11
|
|
data/UPDATING.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Upgrade / Migration Guide
|
2
|
+
|
3
|
+
## Version 1.1.8 to 1.2.0
|
4
|
+
|
5
|
+
### Notable Changes
|
6
|
+
This release is all about channel options. Here is the full [changelog](https://github.com/ably/ably-ruby/blob/main/CHANGELOG.md)
|
7
|
+
|
8
|
+
* Channel options were extracted into a seperate model [ChannelOptions](https://github.com/ably/ably-ruby/blob/main/lib/ably/models/channel_options.rb). However it's still backward campatible with `Hash` and you don't need to do make any adjustments to your code
|
9
|
+
|
10
|
+
* The `ChannelOptions` class now supports `:params`, `:modes` and `:cipher` as options. Previously only `:cipher` was available
|
11
|
+
|
12
|
+
* The client `:idempotent_rest_publishing` option is `true` by default. Previously `:idempotent_rest_publishing` was `false` by default.
|
13
|
+
|
14
|
+
### Breaking Changes
|
15
|
+
|
16
|
+
* Changing channel options with `Channels#get` is now deprecated in favor of explicit options change
|
17
|
+
|
18
|
+
1. If channel state is attached or attaching an exception will be raised
|
19
|
+
2. Otherwise the library will emit a warning
|
20
|
+
|
21
|
+
For example, the following code
|
22
|
+
```
|
23
|
+
client.channels.get(channel_name, new_channel_options)
|
24
|
+
```
|
25
|
+
|
26
|
+
Should be changed to:
|
27
|
+
```
|
28
|
+
channel = client.channels.get(channel_name)
|
29
|
+
channel.options = new_channel_options
|
30
|
+
```
|
data/lib/ably/auth.rb
CHANGED
@@ -510,11 +510,11 @@ module Ably
|
|
510
510
|
end
|
511
511
|
|
512
512
|
def authorize_when_necessary
|
513
|
-
if current_token_details && !current_token_details.expired?
|
513
|
+
if current_token_details && !current_token_details.expired?(from: current_time)
|
514
514
|
return current_token_details
|
515
|
-
else
|
516
|
-
authorize
|
517
515
|
end
|
516
|
+
|
517
|
+
authorize
|
518
518
|
end
|
519
519
|
|
520
520
|
# Returns the current device clock time unless the
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Ably::Models
|
2
|
+
# Convert token details argument to a {ChannelOptions} object
|
3
|
+
#
|
4
|
+
# @param attributes (see #initialize)
|
5
|
+
#
|
6
|
+
# @return [ChannelOptions]
|
7
|
+
def self.ChannelOptions(attributes)
|
8
|
+
case attributes
|
9
|
+
when ChannelOptions
|
10
|
+
return attributes
|
11
|
+
else
|
12
|
+
ChannelOptions.new(attributes)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Represents options of a channel
|
17
|
+
class ChannelOptions
|
18
|
+
extend Ably::Modules::Enum
|
19
|
+
extend Forwardable
|
20
|
+
include Ably::Modules::ModelCommon
|
21
|
+
|
22
|
+
MODES = ruby_enum('MODES',
|
23
|
+
presence: 0,
|
24
|
+
publish: 1,
|
25
|
+
subscribe: 2,
|
26
|
+
presence_subscribe: 3
|
27
|
+
)
|
28
|
+
|
29
|
+
attr_reader :attributes
|
30
|
+
|
31
|
+
alias_method :to_h, :attributes
|
32
|
+
|
33
|
+
def_delegators :attributes, :fetch, :size, :empty?
|
34
|
+
# Initialize a new ChannelOptions
|
35
|
+
#
|
36
|
+
# @option params [Hash] (TB2c) params (for realtime client libraries only) a of key/value pairs
|
37
|
+
# @option modes [Hash] modes (for realtime client libraries only) an array of ChannelMode
|
38
|
+
# @option cipher [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.
|
39
|
+
#
|
40
|
+
def initialize(attrs)
|
41
|
+
@attributes = IdiomaticRubyWrapper(attrs.clone)
|
42
|
+
|
43
|
+
attributes[:modes] = modes.to_a.map { |mode| Ably::Models::ChannelOptions::MODES[mode] } if modes
|
44
|
+
attributes[:cipher] = Ably::Models::CipherParams(cipher) if cipher
|
45
|
+
attributes.clone
|
46
|
+
end
|
47
|
+
|
48
|
+
# @!attribute cipher
|
49
|
+
#
|
50
|
+
# @return [CipherParams]
|
51
|
+
def cipher
|
52
|
+
attributes[:cipher]
|
53
|
+
end
|
54
|
+
|
55
|
+
# @!attribute params
|
56
|
+
#
|
57
|
+
# @return [Hash]
|
58
|
+
def params
|
59
|
+
attributes[:params].to_h
|
60
|
+
end
|
61
|
+
|
62
|
+
# @!attribute modes
|
63
|
+
#
|
64
|
+
# @return [Array<ChannelOptions::MODES>]
|
65
|
+
def modes
|
66
|
+
attributes[:modes]
|
67
|
+
end
|
68
|
+
|
69
|
+
# Converts modes to a bitfield that coresponds to ProtocolMessage#flags
|
70
|
+
#
|
71
|
+
# @return [Integer]
|
72
|
+
def modes_to_flags
|
73
|
+
modes.map { |mode| Ably::Models::ProtocolMessage::ATTACH_FLAGS_MAPPING[mode.to_sym] }.reduce(:|)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [Hash]
|
77
|
+
# @api private
|
78
|
+
def set_params(hash)
|
79
|
+
attributes[:params] = hash
|
80
|
+
end
|
81
|
+
|
82
|
+
# Sets modes from ProtocolMessage#flags
|
83
|
+
#
|
84
|
+
# @return [Array<ChannelOptions::MODES>]
|
85
|
+
# @api private
|
86
|
+
def set_modes_from_flags(flags)
|
87
|
+
return unless flags
|
88
|
+
|
89
|
+
message_modes = MODES.select do |mode|
|
90
|
+
flag = Ably::Models::ProtocolMessage::ATTACH_FLAGS_MAPPING[mode.to_sym]
|
91
|
+
flags & flag == flag
|
92
|
+
end
|
93
|
+
|
94
|
+
attributes[:modes] = message_modes.map { |mode| Ably::Models::ChannelOptions::MODES[mode] }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
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
|
@@ -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
|
@@ -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
|
@@ -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)
|