ably 0.8.15 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -4
- data/CHANGELOG.md +6 -2
- data/README.md +5 -1
- data/SPEC.md +1473 -852
- data/ably.gemspec +11 -8
- data/lib/ably/auth.rb +90 -53
- data/lib/ably/exceptions.rb +37 -8
- data/lib/ably/logger.rb +10 -1
- data/lib/ably/models/auth_details.rb +42 -0
- data/lib/ably/models/channel_state_change.rb +18 -4
- data/lib/ably/models/connection_details.rb +6 -3
- data/lib/ably/models/connection_state_change.rb +4 -3
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/message.rb +17 -1
- data/lib/ably/models/message_encoders/base.rb +103 -82
- data/lib/ably/models/message_encoders/base64.rb +1 -1
- data/lib/ably/models/presence_message.rb +16 -1
- data/lib/ably/models/protocol_message.rb +20 -3
- data/lib/ably/models/token_details.rb +11 -1
- data/lib/ably/models/token_request.rb +16 -6
- data/lib/ably/modules/async_wrapper.rb +7 -3
- data/lib/ably/modules/encodeable.rb +51 -12
- data/lib/ably/modules/enum.rb +17 -7
- data/lib/ably/modules/event_emitter.rb +29 -14
- data/lib/ably/modules/model_common.rb +13 -21
- data/lib/ably/modules/state_emitter.rb +7 -4
- data/lib/ably/modules/state_machine.rb +2 -4
- data/lib/ably/modules/uses_state_machine.rb +7 -3
- data/lib/ably/realtime.rb +2 -0
- data/lib/ably/realtime/auth.rb +102 -42
- data/lib/ably/realtime/channel.rb +68 -26
- data/lib/ably/realtime/channel/channel_manager.rb +154 -65
- data/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
- data/lib/ably/realtime/client.rb +18 -3
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
- data/lib/ably/realtime/connection.rb +108 -49
- data/lib/ably/realtime/connection/connection_manager.rb +167 -61
- data/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
- data/lib/ably/realtime/connection/websocket_transport.rb +19 -10
- data/lib/ably/realtime/presence.rb +70 -45
- data/lib/ably/realtime/presence/members_map.rb +201 -36
- data/lib/ably/realtime/presence/presence_manager.rb +30 -6
- data/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +5 -5
- data/lib/ably/rest/client.rb +31 -27
- data/lib/ably/rest/middleware/exceptions.rb +1 -3
- data/lib/ably/rest/middleware/logger.rb +2 -2
- data/lib/ably/rest/presence.rb +2 -2
- data/lib/ably/util/pub_sub.rb +1 -1
- data/lib/ably/util/safe_deferrable.rb +26 -0
- data/lib/ably/version.rb +2 -2
- data/spec/acceptance/realtime/auth_spec.rb +470 -111
- data/spec/acceptance/realtime/channel_history_spec.rb +5 -3
- data/spec/acceptance/realtime/channel_spec.rb +1017 -168
- data/spec/acceptance/realtime/client_spec.rb +6 -6
- data/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
- data/spec/acceptance/realtime/connection_spec.rb +424 -105
- data/spec/acceptance/realtime/message_spec.rb +52 -23
- data/spec/acceptance/realtime/presence_history_spec.rb +5 -3
- data/spec/acceptance/realtime/presence_spec.rb +1110 -96
- data/spec/acceptance/rest/auth_spec.rb +222 -59
- data/spec/acceptance/rest/base_spec.rb +1 -1
- data/spec/acceptance/rest/channel_spec.rb +1 -2
- data/spec/acceptance/rest/client_spec.rb +104 -48
- data/spec/acceptance/rest/message_spec.rb +42 -15
- data/spec/acceptance/rest/presence_spec.rb +4 -11
- data/spec/rspec_config.rb +2 -1
- data/spec/shared/client_initializer_behaviour.rb +2 -2
- data/spec/shared/safe_deferrable_behaviour.rb +6 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/support/debug_failure_helper.rb +20 -4
- data/spec/support/event_machine_helper.rb +32 -1
- data/spec/unit/auth_spec.rb +4 -11
- data/spec/unit/logger_spec.rb +28 -2
- data/spec/unit/models/auth_details_spec.rb +49 -0
- data/spec/unit/models/channel_state_change_spec.rb +23 -3
- data/spec/unit/models/connection_details_spec.rb +12 -1
- data/spec/unit/models/connection_state_change_spec.rb +15 -4
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -1
- data/spec/unit/models/message_spec.rb +153 -0
- data/spec/unit/models/presence_message_spec.rb +192 -0
- data/spec/unit/models/protocol_message_spec.rb +64 -6
- data/spec/unit/models/token_details_spec.rb +75 -0
- data/spec/unit/models/token_request_spec.rb +74 -0
- data/spec/unit/modules/async_wrapper_spec.rb +2 -1
- data/spec/unit/modules/enum_spec.rb +69 -0
- data/spec/unit/modules/event_emitter_spec.rb +149 -22
- data/spec/unit/modules/state_emitter_spec.rb +9 -3
- data/spec/unit/realtime/client_spec.rb +1 -1
- data/spec/unit/realtime/connection_spec.rb +8 -5
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
- data/spec/unit/realtime/presence_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +1 -1
- data/spec/unit/util/crypto_spec.rb +3 -3
- metadata +22 -19
@@ -0,0 +1,42 @@
|
|
1
|
+
module Ably::Models
|
2
|
+
# Convert auth details attributes to a {AuthDetails} object
|
3
|
+
#
|
4
|
+
# @param attributes (see #initialize)
|
5
|
+
#
|
6
|
+
# @return [AuthDetails]
|
7
|
+
def self.AuthDetails(attributes)
|
8
|
+
case attributes
|
9
|
+
when AuthDetails
|
10
|
+
return attributes
|
11
|
+
else
|
12
|
+
AuthDetails.new(attributes || {})
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# AuthDetails are included in an +AUTH+ {Ably::Models::ProtocolMessage#auth} attribute
|
17
|
+
# to provide the realtime service with new token authentication details following a re-auth workflow
|
18
|
+
#
|
19
|
+
class AuthDetails
|
20
|
+
include Ably::Modules::ModelCommon
|
21
|
+
|
22
|
+
# @param attributes [Hash]
|
23
|
+
# @option attributes [String] :access_token token string
|
24
|
+
#
|
25
|
+
def initialize(attributes = {})
|
26
|
+
@hash_object = IdiomaticRubyWrapper(attributes.clone)
|
27
|
+
self.attributes.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
%w(access_token).each do |attribute|
|
31
|
+
define_method attribute do
|
32
|
+
attributes[attribute.to_sym]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!attribute [r] attributes
|
37
|
+
# @return [Hash] Access the token details Hash object ruby'fied to use symbolized keys
|
38
|
+
def attributes
|
39
|
+
@hash_object
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -8,31 +8,45 @@ module Ably::Models
|
|
8
8
|
# @return [Connection::STATE] Previous channel state
|
9
9
|
# @!attribute [r] reason
|
10
10
|
# @return [Ably::Models::ErrorInfo] Object describing the reason for a state change when not initiated by the consumer of the client library
|
11
|
+
# @!attribute [r] resumed
|
12
|
+
# @return [Boolean] True when a channel is resumed, false when continuity on the channel is no longer provided indicating that the developer is now responsible for recovering lost messages on this channel through other means, such as using the hisory API
|
11
13
|
#
|
12
14
|
class ChannelStateChange
|
13
15
|
include Ably::Modules::ModelCommon
|
14
16
|
|
15
17
|
def initialize(hash_object)
|
16
|
-
unless (hash_object.keys - [:current, :previous, :reason, :protocol_message]).empty?
|
17
|
-
raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :reason'
|
18
|
+
unless (hash_object.keys - [:current, :previous, :event, :reason, :resumed, :protocol_message]).empty?
|
19
|
+
raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :event, :reason, :resumed'
|
18
20
|
end
|
19
21
|
|
20
22
|
@hash_object = {
|
21
23
|
current: hash_object.fetch(:current),
|
22
24
|
previous: hash_object.fetch(:previous),
|
25
|
+
event: hash_object[:event],
|
23
26
|
reason: hash_object[:reason],
|
24
|
-
protocol_message: hash_object[:protocol_message]
|
27
|
+
protocol_message: hash_object[:protocol_message],
|
28
|
+
resumed: hash_object[:resumed]
|
25
29
|
}
|
26
30
|
rescue KeyError => e
|
27
31
|
raise ArgumentError, e
|
28
32
|
end
|
29
33
|
|
30
|
-
%w(current previous reason
|
34
|
+
%w(current previous event reason).each do |attribute|
|
31
35
|
define_method attribute do
|
32
36
|
@hash_object[attribute.to_sym]
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
40
|
+
def resumed
|
41
|
+
!!@hash_object[:resumed]
|
42
|
+
end
|
43
|
+
alias_method :resumed?, :resumed
|
44
|
+
|
45
|
+
# @api private
|
46
|
+
def protocol_message
|
47
|
+
@hash_object[:protocol_message]
|
48
|
+
end
|
49
|
+
|
36
50
|
def to_s
|
37
51
|
"ChannelStateChange: current state #{current}, previous state #{previous}"
|
38
52
|
end
|
@@ -27,18 +27,21 @@ module Ably::Models
|
|
27
27
|
# @option attributes [Integer] :max_message_size maximum individual message size in bytes
|
28
28
|
# @option attributes [Integer] :max_frame_size maximum size for a single frame of data sent to Ably. This restriction applies to a {Ably::Models::ProtocolMessage} sent over a realtime connection, or the total body size for a REST request
|
29
29
|
# @option attributes [Integer] :max_inbound_rate maximum allowable number of requests per second from a client
|
30
|
+
# @option attributes [Integer] :max_idle_interval is the maximum length of time in seconds that the server will allow no activity to occur in the server->client direction. After such a period of inactivity, the server will send a @HEARTBEAT@ or transport-level ping to the client. If the value is 0, the server will allow arbitrarily-long levels of inactivity.
|
30
31
|
# @option attributes [Integer] :connection_state_ttl duration in seconds that Ably will persist the connection state when a Realtime client is abruptly disconnected
|
31
32
|
# @option attributes [String] :server_id unique identifier of the Ably server where the connection is established
|
32
33
|
#
|
33
34
|
def initialize(attributes = {})
|
34
35
|
@hash_object = IdiomaticRubyWrapper(attributes.clone)
|
35
|
-
|
36
|
-
|
36
|
+
[:connection_state_ttl, :max_idle_interval].each do |duration_field|
|
37
|
+
if self.attributes[duration_field]
|
38
|
+
self.attributes[duration_field] = (self.attributes[duration_field].to_f / 1000).round
|
39
|
+
end
|
37
40
|
end
|
38
41
|
self.attributes.freeze
|
39
42
|
end
|
40
43
|
|
41
|
-
%w(client_id connection_key max_message_size max_frame_size max_inbound_rate connection_state_ttl server_id).each do |attribute|
|
44
|
+
%w(client_id connection_key max_message_size max_frame_size max_inbound_rate connection_state_ttl max_idle_interval server_id).each do |attribute|
|
42
45
|
define_method attribute do
|
43
46
|
attributes[attribute.to_sym]
|
44
47
|
end
|
@@ -15,13 +15,14 @@ module Ably::Models
|
|
15
15
|
include Ably::Modules::ModelCommon
|
16
16
|
|
17
17
|
def initialize(hash_object)
|
18
|
-
unless (hash_object.keys - [:current, :previous, :retry_in, :reason, :protocol_message]).empty?
|
19
|
-
raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :retry_in, :reason'
|
18
|
+
unless (hash_object.keys - [:current, :previous, :event, :retry_in, :reason, :protocol_message]).empty?
|
19
|
+
raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :event, :retry_in, :reason'
|
20
20
|
end
|
21
21
|
|
22
22
|
@hash_object = {
|
23
23
|
current: hash_object.fetch(:current),
|
24
24
|
previous: hash_object.fetch(:previous),
|
25
|
+
event: hash_object[:event],
|
25
26
|
retry_in: hash_object[:retry_in],
|
26
27
|
reason: hash_object[:reason],
|
27
28
|
protocol_message: hash_object[:protocol_message]
|
@@ -30,7 +31,7 @@ module Ably::Models
|
|
30
31
|
raise ArgumentError, e
|
31
32
|
end
|
32
33
|
|
33
|
-
%w(current previous retry_in reason protocol_message).each do |attribute|
|
34
|
+
%w(current previous event retry_in reason protocol_message).each do |attribute|
|
34
35
|
define_method attribute do
|
35
36
|
@hash_object[attribute.to_sym]
|
36
37
|
end
|
@@ -11,7 +11,7 @@ module Ably::Models
|
|
11
11
|
# @!attribute [r] attributes
|
12
12
|
# @return [Hash] Access the protocol message Hash object ruby'fied to use symbolized keys
|
13
13
|
#
|
14
|
-
class ErrorInfo
|
14
|
+
class ErrorInfo < Ably::Exceptions::BaseAblyException
|
15
15
|
include Ably::Modules::ModelCommon
|
16
16
|
|
17
17
|
def initialize(hash_object)
|
data/lib/ably/models/message.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ably/models/message_encoders/base'
|
2
|
+
|
1
3
|
module Ably::Models
|
2
4
|
# Convert messsage argument to a {Message} object and associate with a protocol message if provided
|
3
5
|
#
|
@@ -43,6 +45,9 @@ module Ably::Models
|
|
43
45
|
include Ably::Modules::ModelCommon
|
44
46
|
include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
|
45
47
|
|
48
|
+
# Statically register a default set of encoders for this class
|
49
|
+
Ably::Models::MessageEncoders.register_default_encoders self
|
50
|
+
|
46
51
|
# {Message} initializer
|
47
52
|
#
|
48
53
|
# @param attributes [Hash] object with the underlying message detail key value attributes
|
@@ -119,6 +124,17 @@ module Ably::Models
|
|
119
124
|
@protocol_message
|
120
125
|
end
|
121
126
|
|
127
|
+
# Contains any arbitrary key value pairs which may also contain other primitive JSON types, JSON-encodable objects or JSON-encodable arrays.
|
128
|
+
# The extras field is provided to contain message metadata and/or ancillary payloads in support of specific functionality, e.g. push
|
129
|
+
# @api private
|
130
|
+
def extras
|
131
|
+
attributes[:extras].tap do |val|
|
132
|
+
unless val.kind_of?(IdiomaticRubyWrapper) || val.kind_of?(Array) || val.kind_of?(Hash) || val.nil?
|
133
|
+
raise ArgumentError, "extras contains an unsupported type #{val.class}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
122
138
|
private
|
123
139
|
def raw_hash_object
|
124
140
|
@raw_hash_object
|
@@ -129,7 +145,7 @@ module Ably::Models
|
|
129
145
|
end
|
130
146
|
|
131
147
|
def set_attributes_object(new_attributes)
|
132
|
-
@attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])
|
148
|
+
@attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data, :extras])
|
133
149
|
end
|
134
150
|
|
135
151
|
def logger
|
@@ -7,98 +7,119 @@ require 'ably/modules/conversions'
|
|
7
7
|
# of the message is defined as 'json'.
|
8
8
|
# Encrypted messages are encoded & decoded by the Cipher encoder.
|
9
9
|
#
|
10
|
-
module Ably
|
11
|
-
|
10
|
+
module Ably
|
11
|
+
module Models
|
12
|
+
module MessageEncoders
|
13
|
+
extend Ably::Modules::Conversions
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
# Base interface for an Ably Encoder
|
16
|
+
#
|
17
|
+
class Base
|
18
|
+
attr_reader :client, :options
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
def initialize(client, options = {})
|
21
|
+
@client = client
|
22
|
+
@options = options
|
23
|
+
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
# #encode is called once before a message is sent to Ably
|
26
|
+
#
|
27
|
+
# It is the responsibility of the #encode method to detect the intended encoding and modify the :data & :encoding properties of the message object.
|
28
|
+
#
|
29
|
+
# @param [Hash] message the message as a Hash object received directly from Ably.
|
30
|
+
# The message contains properties :name, :data, :encoding, :timestamp, and optionally :id and :client_id.
|
31
|
+
# This #encode method should modify the message Hash if any encoding action is to be taken
|
32
|
+
# @param [Hash] channel_options the options used to initialize the channel that this message was received on
|
33
|
+
#
|
34
|
+
# @return [void]
|
35
|
+
def encode(message, channel_options)
|
36
|
+
raise "Not yet implemented"
|
37
|
+
end
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
39
|
+
# #decode is called once for every encoding step
|
40
|
+
# i.e. if message encoding arrives with 'utf-8/cipher+aes-128-cbc/base64'
|
41
|
+
# the decoder will call #decode once for each encoding part such as 'base64', then 'cipher+aes-128-cbc', and finally 'utf-8'
|
42
|
+
#
|
43
|
+
# It is the responsibility of the #decode method to detect the current encoding part and modify the :data & :encoding properties of the message object.
|
44
|
+
#
|
45
|
+
# @param [Hash] message the message as a Hash object received directly from Ably.
|
46
|
+
# The message contains properties :name, :data, :encoding, :timestamp, and optionally :id and :client_id.
|
47
|
+
# This #encode method should modify the message Hash if any decoding action is to be taken
|
48
|
+
# @param [Hash] channel_options the options used to initialize the channel that this message was received on
|
49
|
+
#
|
50
|
+
# @return [void]
|
51
|
+
def decode(message, channel_options)
|
52
|
+
raise "Not yet implemented"
|
53
|
+
end
|
51
54
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
# Add encoding to the message Hash.
|
56
|
+
# Ensures that encoding delimeter is used where required i.e utf-8/cipher+aes-128-cbc/base64
|
57
|
+
#
|
58
|
+
# @param [Hash] message the message as a Hash object received directly from Ably.
|
59
|
+
# @param [String] encoding encoding to add to the current encoding
|
60
|
+
#
|
61
|
+
# @return [void]
|
62
|
+
def add_encoding_to_message(encoding, message)
|
63
|
+
message[:encoding] = [message[:encoding], encoding].compact.join('/')
|
64
|
+
end
|
62
65
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
# Returns the right most encoding form a meessage encoding, and nil if none exists
|
67
|
+
# i.e. current_encoding_part('utf-8/cipher+aes-128-cbc/base64') => 'base64'
|
68
|
+
#
|
69
|
+
# @return [String,nil]
|
70
|
+
def current_encoding_part(message)
|
71
|
+
if message[:encoding]
|
72
|
+
message[:encoding].split('/')[-1]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Strip the current encoding part within the message Hash.
|
77
|
+
#
|
78
|
+
# For example, calling this method on an :encoding value of 'utf-8/cipher+aes-128-cbc/base64' would update the attribute
|
79
|
+
# :encoding to 'utf-8/cipher+aes-128-cbc'
|
80
|
+
#
|
81
|
+
# @param [Hash] message the message as a Hash object received directly from Ably.
|
82
|
+
#
|
83
|
+
# @return [void]
|
84
|
+
def strip_current_encoding_part(message)
|
85
|
+
raise "Cannot strip encoding when there is no encoding for this message" unless message[:encoding]
|
86
|
+
message[:encoding] = message[:encoding].split('/')[0...-1].join('/')
|
87
|
+
message[:encoding] = nil if message[:encoding].empty?
|
88
|
+
end
|
89
|
+
|
90
|
+
# True of the message data payload is empty
|
91
|
+
#
|
92
|
+
# @param [Hash] message the message as a Hash object received directly from Ably.
|
93
|
+
#
|
94
|
+
# @return [Boolean]
|
95
|
+
def is_empty?(message)
|
96
|
+
message[:data].nil? || message[:data] == ''
|
97
|
+
end
|
70
98
|
end
|
71
|
-
end
|
72
99
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
def strip_current_encoding_part(message)
|
82
|
-
raise "Cannot strip encoding when there is no encoding for this message" unless message[:encoding]
|
83
|
-
message[:encoding] = message[:encoding].split('/')[0...-1].join('/')
|
84
|
-
message[:encoding] = nil if message[:encoding].empty?
|
85
|
-
end
|
100
|
+
# @api private
|
101
|
+
def self.register_default_encoders(client, options = {})
|
102
|
+
binary_protocol = !!options[:binary_protocol]
|
103
|
+
client.register_encoder Ably::Models::MessageEncoders::Utf8
|
104
|
+
client.register_encoder Ably::Models::MessageEncoders::Json
|
105
|
+
client.register_encoder Ably::Models::MessageEncoders::Cipher
|
106
|
+
client.register_encoder Ably::Models::MessageEncoders::Base64, binary_protocol: binary_protocol
|
107
|
+
end
|
86
108
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
109
|
+
# @api private
|
110
|
+
def self.encoder_from(encoder, options)
|
111
|
+
encoder_klass = if encoder.kind_of?(String)
|
112
|
+
encoder.split('::').inject(Kernel) do |base, klass_name|
|
113
|
+
base.public_send(:const_get, klass_name)
|
114
|
+
end
|
115
|
+
else
|
116
|
+
encoder
|
117
|
+
end
|
96
118
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
client.register_encoder Ably::Models::MessageEncoders::Base64
|
119
|
+
raise "Encoder must inherit from `Ably::Models::MessageEncoders::Base`" unless encoder_klass.ancestors.include?(Ably::Models::MessageEncoders::Base)
|
120
|
+
encoder_klass.new(self, options)
|
121
|
+
end
|
122
|
+
end
|
102
123
|
end
|
103
124
|
end
|
104
125
|
|
@@ -52,6 +52,9 @@ module Ably::Models
|
|
52
52
|
:update
|
53
53
|
)
|
54
54
|
|
55
|
+
# Statically register a default set of encoders for this class
|
56
|
+
Ably::Models::MessageEncoders.register_default_encoders self
|
57
|
+
|
55
58
|
# {PresenceMessage} initializer
|
56
59
|
#
|
57
60
|
# @param attributes [Hash] object with the underlying presence message key value attributes
|
@@ -120,7 +123,6 @@ module Ably::Models
|
|
120
123
|
end.to_json
|
121
124
|
end
|
122
125
|
|
123
|
-
|
124
126
|
# Assign this presence message to a ProtocolMessage before delivery to the Ably system
|
125
127
|
# @api private
|
126
128
|
def assign_to_protocol_message(protocol_message)
|
@@ -142,6 +144,19 @@ module Ably::Models
|
|
142
144
|
@protocol_message
|
143
145
|
end
|
144
146
|
|
147
|
+
# Create a static shallow clone of this object with the optional attributes to overide existing values
|
148
|
+
# Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
|
149
|
+
# Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
|
150
|
+
def shallow_clone(new_attributes = {})
|
151
|
+
new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])
|
152
|
+
|
153
|
+
self.class.new(attributes.to_hash.merge(
|
154
|
+
id: new_attributes[:id] || id,
|
155
|
+
connection_id: new_attributes[:connection_id] || connection_id,
|
156
|
+
timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
|
157
|
+
).merge(new_attributes.to_hash))
|
158
|
+
end
|
159
|
+
|
145
160
|
private
|
146
161
|
def raw_hash_object
|
147
162
|
@raw_hash_object
|