Class: Ably::Models::PresenceMessage

Inherits:
Object
  • Object
show all
Extended by:
Ably::Modules::Enum
Includes:
Ably::Modules::Conversions, Ably::Modules::Encodeable, Ably::Modules::ModelCommon, Ably::Modules::SafeDeferrable
Defined in:
lib/ably/models/presence_message.rb

Overview

A class representing an individual presence message to be sent or received via the Ably Realtime service.

Constant Summary collapse

ACTION =
ruby_enum('ACTION',
  :absent,
  :present,
  :enter,
  :leave,
  :update
)

Instance Attribute Summary collapse

Attributes included from Ably::Modules::ModelCommon

#hash

Instance Method Summary collapse

Methods included from Ably::Modules::SafeDeferrable

#callback, #errback, #fail, #succeed

Methods included from Ably::Modules::ModelCommon

#==, #[], included, #to_s

Methods included from Ably::Modules::MessagePack

#to_msgpack

Methods included from Ably::Modules::Encodeable

#decode, #encode, included, #original_encoding

Constructor Details

#initialize(attributes, options = {}) ⇒ PresenceMessage

Parameters:

  • attributes (Hash)

    object with the underlying presence message key value attributes

  • options (Hash) (defaults to: {})

    an options Hash for this initializer

Options Hash (options):


65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/ably/models/presence_message.rb', line 65

def initialize(attributes, options = {})
  @logger           = options[:logger] # Logger expected for SafeDeferrable
  @protocol_message = options[:protocol_message]
  @raw_hash_object  = attributes

  set_attributes_object attributes

  self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
  self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
  self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

  self.attributes.freeze
end

Instance Attribute Details

#actionACTION (readonly)

Returns the state change event signified by a PresenceMessage

Returns:

  • (ACTION)

    the state change event signified by a PresenceMessage


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ably/models/presence_message.rb', line 40

class PresenceMessage
  include Ably::Modules::Conversions
  include Ably::Modules::Encodeable
  include Ably::Modules::ModelCommon
  include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
  extend Ably::Modules::Enum

  ACTION = ruby_enum('ACTION',
    :absent,
    :present,
    :enter,
    :leave,
    :update
  )

  # Statically register a default set of encoders for this class
  Ably::Models::MessageEncoders.register_default_encoders self

  # {PresenceMessage} initializer
  #
  # @param  attributes  [Hash]            object with the underlying presence message key value attributes
  # @param  [Hash]      options           an options Hash for this initializer
  # @option options     [ProtocolMessage] :protocol_message  An optional protocol message to assocate the presence message with
  # @option options     [Logger]          :logger            An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
  #
  def initialize(attributes, options = {})
    @logger           = options[:logger] # Logger expected for SafeDeferrable
    @protocol_message = options[:protocol_message]
    @raw_hash_object  = attributes

    set_attributes_object attributes

    self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
    self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
    self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

    self.attributes.freeze
  end

  %w( client_id data encoding ).each do |attribute|
    define_method attribute do
      attributes[attribute.to_sym]
    end
  end

  def id
    attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
  end

  def connection_id
    attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
  end

  def member_key
    "#{connection_id}:#{client_id}"
  end

  def timestamp
    if attributes[:timestamp]
      as_time_from_epoch(attributes[:timestamp])
    else
      protocol_message.timestamp
    end
  end

  def action
    ACTION(attributes[:action])
  end

  def attributes
    @attributes
  end

  # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
  def as_json(*args)
    attributes.dup.tap do |presence_message|
      presence_message['action'] = action.to_i
    end.as_json.reject { |key, val| val.nil? }
  rescue KeyError
    raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
  end

  def to_json(*args)
    as_json(*args).tap do |presence_message|
      decode_binary_data_before_to_json presence_message
    end.to_json
  end

  # Assign this presence message to a ProtocolMessage before delivery to the Ably system
  # @api private
  def assign_to_protocol_message(protocol_message)
    @protocol_message = protocol_message
  end

  # True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
  # @return [Boolean]
  # @api private
  def assigned_to_protocol_message?
    !!@protocol_message
  end

  # The optional ProtocolMessage this presence message is assigned to.  If ProtocolMessage is nil, an error will be raised.
  # @return [Ably::Models::ProtocolMessage]
  # @api private
  def protocol_message
    raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
    @protocol_message
  end

  # Create a static shallow clone of this object with the optional attributes to overide existing values
  # Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
  # Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
  def shallow_clone(new_attributes = {})
    new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

    self.class.new(attributes.to_hash.merge(
      id: new_attributes[:id] || id,
      connection_id: new_attributes[:connection_id] || connection_id,
      timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
    ).merge(new_attributes.to_hash))
  end

  private
  def raw_hash_object
    @raw_hash_object
  end

  def protocol_message_index
    protocol_message.presence.index(self)
  end

  def set_attributes_object(new_attributes)
    @attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
  end

  def logger
    return @logger if @logger
    protocol_message.logger if protocol_message
  end
end

#attributesHash (readonly)

Returns Access the protocol message Hash object ruby'fied to use symbolized keys

Returns:

  • (Hash)

    Access the protocol message Hash object ruby'fied to use symbolized keys


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ably/models/presence_message.rb', line 40

class PresenceMessage
  include Ably::Modules::Conversions
  include Ably::Modules::Encodeable
  include Ably::Modules::ModelCommon
  include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
  extend Ably::Modules::Enum

  ACTION = ruby_enum('ACTION',
    :absent,
    :present,
    :enter,
    :leave,
    :update
  )

  # Statically register a default set of encoders for this class
  Ably::Models::MessageEncoders.register_default_encoders self

  # {PresenceMessage} initializer
  #
  # @param  attributes  [Hash]            object with the underlying presence message key value attributes
  # @param  [Hash]      options           an options Hash for this initializer
  # @option options     [ProtocolMessage] :protocol_message  An optional protocol message to assocate the presence message with
  # @option options     [Logger]          :logger            An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
  #
  def initialize(attributes, options = {})
    @logger           = options[:logger] # Logger expected for SafeDeferrable
    @protocol_message = options[:protocol_message]
    @raw_hash_object  = attributes

    set_attributes_object attributes

    self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
    self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
    self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

    self.attributes.freeze
  end

  %w( client_id data encoding ).each do |attribute|
    define_method attribute do
      attributes[attribute.to_sym]
    end
  end

  def id
    attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
  end

  def connection_id
    attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
  end

  def member_key
    "#{connection_id}:#{client_id}"
  end

  def timestamp
    if attributes[:timestamp]
      as_time_from_epoch(attributes[:timestamp])
    else
      protocol_message.timestamp
    end
  end

  def action
    ACTION(attributes[:action])
  end

  def attributes
    @attributes
  end

  # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
  def as_json(*args)
    attributes.dup.tap do |presence_message|
      presence_message['action'] = action.to_i
    end.as_json.reject { |key, val| val.nil? }
  rescue KeyError
    raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
  end

  def to_json(*args)
    as_json(*args).tap do |presence_message|
      decode_binary_data_before_to_json presence_message
    end.to_json
  end

  # Assign this presence message to a ProtocolMessage before delivery to the Ably system
  # @api private
  def assign_to_protocol_message(protocol_message)
    @protocol_message = protocol_message
  end

  # True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
  # @return [Boolean]
  # @api private
  def assigned_to_protocol_message?
    !!@protocol_message
  end

  # The optional ProtocolMessage this presence message is assigned to.  If ProtocolMessage is nil, an error will be raised.
  # @return [Ably::Models::ProtocolMessage]
  # @api private
  def protocol_message
    raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
    @protocol_message
  end

  # Create a static shallow clone of this object with the optional attributes to overide existing values
  # Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
  # Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
  def shallow_clone(new_attributes = {})
    new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

    self.class.new(attributes.to_hash.merge(
      id: new_attributes[:id] || id,
      connection_id: new_attributes[:connection_id] || connection_id,
      timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
    ).merge(new_attributes.to_hash))
  end

  private
  def raw_hash_object
    @raw_hash_object
  end

  def protocol_message_index
    protocol_message.presence.index(self)
  end

  def set_attributes_object(new_attributes)
    @attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
  end

  def logger
    return @logger if @logger
    protocol_message.logger if protocol_message
  end
end

#client_idString (readonly)

Returns The client_id associated with this presence state

Returns:

  • (String)

    The client_id associated with this presence state


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ably/models/presence_message.rb', line 40

class PresenceMessage
  include Ably::Modules::Conversions
  include Ably::Modules::Encodeable
  include Ably::Modules::ModelCommon
  include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
  extend Ably::Modules::Enum

  ACTION = ruby_enum('ACTION',
    :absent,
    :present,
    :enter,
    :leave,
    :update
  )

  # Statically register a default set of encoders for this class
  Ably::Models::MessageEncoders.register_default_encoders self

  # {PresenceMessage} initializer
  #
  # @param  attributes  [Hash]            object with the underlying presence message key value attributes
  # @param  [Hash]      options           an options Hash for this initializer
  # @option options     [ProtocolMessage] :protocol_message  An optional protocol message to assocate the presence message with
  # @option options     [Logger]          :logger            An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
  #
  def initialize(attributes, options = {})
    @logger           = options[:logger] # Logger expected for SafeDeferrable
    @protocol_message = options[:protocol_message]
    @raw_hash_object  = attributes

    set_attributes_object attributes

    self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
    self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
    self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

    self.attributes.freeze
  end

  %w( client_id data encoding ).each do |attribute|
    define_method attribute do
      attributes[attribute.to_sym]
    end
  end

  def id
    attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
  end

  def connection_id
    attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
  end

  def member_key
    "#{connection_id}:#{client_id}"
  end

  def timestamp
    if attributes[:timestamp]
      as_time_from_epoch(attributes[:timestamp])
    else
      protocol_message.timestamp
    end
  end

  def action
    ACTION(attributes[:action])
  end

  def attributes
    @attributes
  end

  # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
  def as_json(*args)
    attributes.dup.tap do |presence_message|
      presence_message['action'] = action.to_i
    end.as_json.reject { |key, val| val.nil? }
  rescue KeyError
    raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
  end

  def to_json(*args)
    as_json(*args).tap do |presence_message|
      decode_binary_data_before_to_json presence_message
    end.to_json
  end

  # Assign this presence message to a ProtocolMessage before delivery to the Ably system
  # @api private
  def assign_to_protocol_message(protocol_message)
    @protocol_message = protocol_message
  end

  # True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
  # @return [Boolean]
  # @api private
  def assigned_to_protocol_message?
    !!@protocol_message
  end

  # The optional ProtocolMessage this presence message is assigned to.  If ProtocolMessage is nil, an error will be raised.
  # @return [Ably::Models::ProtocolMessage]
  # @api private
  def protocol_message
    raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
    @protocol_message
  end

  # Create a static shallow clone of this object with the optional attributes to overide existing values
  # Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
  # Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
  def shallow_clone(new_attributes = {})
    new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

    self.class.new(attributes.to_hash.merge(
      id: new_attributes[:id] || id,
      connection_id: new_attributes[:connection_id] || connection_id,
      timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
    ).merge(new_attributes.to_hash))
  end

  private
  def raw_hash_object
    @raw_hash_object
  end

  def protocol_message_index
    protocol_message.presence.index(self)
  end

  def set_attributes_object(new_attributes)
    @attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
  end

  def logger
    return @logger if @logger
    protocol_message.logger if protocol_message
  end
end

#connection_idString (readonly)

Returns A unique member identifier, disambiguating situations where a given client_id is present on multiple connections simultaneously

Returns:

  • (String)

    A unique member identifier, disambiguating situations where a given client_id is present on multiple connections simultaneously


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ably/models/presence_message.rb', line 40

class PresenceMessage
  include Ably::Modules::Conversions
  include Ably::Modules::Encodeable
  include Ably::Modules::ModelCommon
  include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
  extend Ably::Modules::Enum

  ACTION = ruby_enum('ACTION',
    :absent,
    :present,
    :enter,
    :leave,
    :update
  )

  # Statically register a default set of encoders for this class
  Ably::Models::MessageEncoders.register_default_encoders self

  # {PresenceMessage} initializer
  #
  # @param  attributes  [Hash]            object with the underlying presence message key value attributes
  # @param  [Hash]      options           an options Hash for this initializer
  # @option options     [ProtocolMessage] :protocol_message  An optional protocol message to assocate the presence message with
  # @option options     [Logger]          :logger            An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
  #
  def initialize(attributes, options = {})
    @logger           = options[:logger] # Logger expected for SafeDeferrable
    @protocol_message = options[:protocol_message]
    @raw_hash_object  = attributes

    set_attributes_object attributes

    self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
    self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
    self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

    self.attributes.freeze
  end

  %w( client_id data encoding ).each do |attribute|
    define_method attribute do
      attributes[attribute.to_sym]
    end
  end

  def id
    attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
  end

  def connection_id
    attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
  end

  def member_key
    "#{connection_id}:#{client_id}"
  end

  def timestamp
    if attributes[:timestamp]
      as_time_from_epoch(attributes[:timestamp])
    else
      protocol_message.timestamp
    end
  end

  def action
    ACTION(attributes[:action])
  end

  def attributes
    @attributes
  end

  # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
  def as_json(*args)
    attributes.dup.tap do |presence_message|
      presence_message['action'] = action.to_i
    end.as_json.reject { |key, val| val.nil? }
  rescue KeyError
    raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
  end

  def to_json(*args)
    as_json(*args).tap do |presence_message|
      decode_binary_data_before_to_json presence_message
    end.to_json
  end

  # Assign this presence message to a ProtocolMessage before delivery to the Ably system
  # @api private
  def assign_to_protocol_message(protocol_message)
    @protocol_message = protocol_message
  end

  # True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
  # @return [Boolean]
  # @api private
  def assigned_to_protocol_message?
    !!@protocol_message
  end

  # The optional ProtocolMessage this presence message is assigned to.  If ProtocolMessage is nil, an error will be raised.
  # @return [Ably::Models::ProtocolMessage]
  # @api private
  def protocol_message
    raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
    @protocol_message
  end

  # Create a static shallow clone of this object with the optional attributes to overide existing values
  # Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
  # Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
  def shallow_clone(new_attributes = {})
    new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

    self.class.new(attributes.to_hash.merge(
      id: new_attributes[:id] || id,
      connection_id: new_attributes[:connection_id] || connection_id,
      timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
    ).merge(new_attributes.to_hash))
  end

  private
  def raw_hash_object
    @raw_hash_object
  end

  def protocol_message_index
    protocol_message.presence.index(self)
  end

  def set_attributes_object(new_attributes)
    @attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
  end

  def logger
    return @logger if @logger
    protocol_message.logger if protocol_message
  end
end

#dataObject (readonly)

Returns Optional client-defined status or other event payload associated with this state

Returns:

  • (Object)

    Optional client-defined status or other event payload associated with this state


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ably/models/presence_message.rb', line 40

class PresenceMessage
  include Ably::Modules::Conversions
  include Ably::Modules::Encodeable
  include Ably::Modules::ModelCommon
  include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
  extend Ably::Modules::Enum

  ACTION = ruby_enum('ACTION',
    :absent,
    :present,
    :enter,
    :leave,
    :update
  )

  # Statically register a default set of encoders for this class
  Ably::Models::MessageEncoders.register_default_encoders self

  # {PresenceMessage} initializer
  #
  # @param  attributes  [Hash]            object with the underlying presence message key value attributes
  # @param  [Hash]      options           an options Hash for this initializer
  # @option options     [ProtocolMessage] :protocol_message  An optional protocol message to assocate the presence message with
  # @option options     [Logger]          :logger            An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
  #
  def initialize(attributes, options = {})
    @logger           = options[:logger] # Logger expected for SafeDeferrable
    @protocol_message = options[:protocol_message]
    @raw_hash_object  = attributes

    set_attributes_object attributes

    self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
    self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
    self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

    self.attributes.freeze
  end

  %w( client_id data encoding ).each do |attribute|
    define_method attribute do
      attributes[attribute.to_sym]
    end
  end

  def id
    attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
  end

  def connection_id
    attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
  end

  def member_key
    "#{connection_id}:#{client_id}"
  end

  def timestamp
    if attributes[:timestamp]
      as_time_from_epoch(attributes[:timestamp])
    else
      protocol_message.timestamp
    end
  end

  def action
    ACTION(attributes[:action])
  end

  def attributes
    @attributes
  end

  # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
  def as_json(*args)
    attributes.dup.tap do |presence_message|
      presence_message['action'] = action.to_i
    end.as_json.reject { |key, val| val.nil? }
  rescue KeyError
    raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
  end

  def to_json(*args)
    as_json(*args).tap do |presence_message|
      decode_binary_data_before_to_json presence_message
    end.to_json
  end

  # Assign this presence message to a ProtocolMessage before delivery to the Ably system
  # @api private
  def assign_to_protocol_message(protocol_message)
    @protocol_message = protocol_message
  end

  # True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
  # @return [Boolean]
  # @api private
  def assigned_to_protocol_message?
    !!@protocol_message
  end

  # The optional ProtocolMessage this presence message is assigned to.  If ProtocolMessage is nil, an error will be raised.
  # @return [Ably::Models::ProtocolMessage]
  # @api private
  def protocol_message
    raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
    @protocol_message
  end

  # Create a static shallow clone of this object with the optional attributes to overide existing values
  # Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
  # Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
  def shallow_clone(new_attributes = {})
    new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

    self.class.new(attributes.to_hash.merge(
      id: new_attributes[:id] || id,
      connection_id: new_attributes[:connection_id] || connection_id,
      timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
    ).merge(new_attributes.to_hash))
  end

  private
  def raw_hash_object
    @raw_hash_object
  end

  def protocol_message_index
    protocol_message.presence.index(self)
  end

  def set_attributes_object(new_attributes)
    @attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
  end

  def logger
    return @logger if @logger
    protocol_message.logger if protocol_message
  end
end

#encodingString (readonly)

Returns The encoding for the message data. Encoding and decoding of messages is handled automatically by the client library. Therefore, the `encoding` attribute should always be nil unless an Ably library decoding error has occurred.

Returns:

  • (String)

    The encoding for the message data. Encoding and decoding of messages is handled automatically by the client library. Therefore, the `encoding` attribute should always be nil unless an Ably library decoding error has occurred.


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ably/models/presence_message.rb', line 40

class PresenceMessage
  include Ably::Modules::Conversions
  include Ably::Modules::Encodeable
  include Ably::Modules::ModelCommon
  include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
  extend Ably::Modules::Enum

  ACTION = ruby_enum('ACTION',
    :absent,
    :present,
    :enter,
    :leave,
    :update
  )

  # Statically register a default set of encoders for this class
  Ably::Models::MessageEncoders.register_default_encoders self

  # {PresenceMessage} initializer
  #
  # @param  attributes  [Hash]            object with the underlying presence message key value attributes
  # @param  [Hash]      options           an options Hash for this initializer
  # @option options     [ProtocolMessage] :protocol_message  An optional protocol message to assocate the presence message with
  # @option options     [Logger]          :logger            An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
  #
  def initialize(attributes, options = {})
    @logger           = options[:logger] # Logger expected for SafeDeferrable
    @protocol_message = options[:protocol_message]
    @raw_hash_object  = attributes

    set_attributes_object attributes

    self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
    self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
    self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

    self.attributes.freeze
  end

  %w( client_id data encoding ).each do |attribute|
    define_method attribute do
      attributes[attribute.to_sym]
    end
  end

  def id
    attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
  end

  def connection_id
    attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
  end

  def member_key
    "#{connection_id}:#{client_id}"
  end

  def timestamp
    if attributes[:timestamp]
      as_time_from_epoch(attributes[:timestamp])
    else
      protocol_message.timestamp
    end
  end

  def action
    ACTION(attributes[:action])
  end

  def attributes
    @attributes
  end

  # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
  def as_json(*args)
    attributes.dup.tap do |presence_message|
      presence_message['action'] = action.to_i
    end.as_json.reject { |key, val| val.nil? }
  rescue KeyError
    raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
  end

  def to_json(*args)
    as_json(*args).tap do |presence_message|
      decode_binary_data_before_to_json presence_message
    end.to_json
  end

  # Assign this presence message to a ProtocolMessage before delivery to the Ably system
  # @api private
  def assign_to_protocol_message(protocol_message)
    @protocol_message = protocol_message
  end

  # True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
  # @return [Boolean]
  # @api private
  def assigned_to_protocol_message?
    !!@protocol_message
  end

  # The optional ProtocolMessage this presence message is assigned to.  If ProtocolMessage is nil, an error will be raised.
  # @return [Ably::Models::ProtocolMessage]
  # @api private
  def protocol_message
    raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
    @protocol_message
  end

  # Create a static shallow clone of this object with the optional attributes to overide existing values
  # Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
  # Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
  def shallow_clone(new_attributes = {})
    new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

    self.class.new(attributes.to_hash.merge(
      id: new_attributes[:id] || id,
      connection_id: new_attributes[:connection_id] || connection_id,
      timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
    ).merge(new_attributes.to_hash))
  end

  private
  def raw_hash_object
    @raw_hash_object
  end

  def protocol_message_index
    protocol_message.presence.index(self)
  end

  def set_attributes_object(new_attributes)
    @attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
  end

  def logger
    return @logger if @logger
    protocol_message.logger if protocol_message
  end
end

#member_keyString (readonly)

Returns A unique connection and client_id identifier ensuring multiple connected clients with the same client_id are unique

Returns:

  • (String)

    A unique connection and client_id identifier ensuring multiple connected clients with the same client_id are unique


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ably/models/presence_message.rb', line 40

class PresenceMessage
  include Ably::Modules::Conversions
  include Ably::Modules::Encodeable
  include Ably::Modules::ModelCommon
  include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
  extend Ably::Modules::Enum

  ACTION = ruby_enum('ACTION',
    :absent,
    :present,
    :enter,
    :leave,
    :update
  )

  # Statically register a default set of encoders for this class
  Ably::Models::MessageEncoders.register_default_encoders self

  # {PresenceMessage} initializer
  #
  # @param  attributes  [Hash]            object with the underlying presence message key value attributes
  # @param  [Hash]      options           an options Hash for this initializer
  # @option options     [ProtocolMessage] :protocol_message  An optional protocol message to assocate the presence message with
  # @option options     [Logger]          :logger            An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
  #
  def initialize(attributes, options = {})
    @logger           = options[:logger] # Logger expected for SafeDeferrable
    @protocol_message = options[:protocol_message]
    @raw_hash_object  = attributes

    set_attributes_object attributes

    self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
    self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
    self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

    self.attributes.freeze
  end

  %w( client_id data encoding ).each do |attribute|
    define_method attribute do
      attributes[attribute.to_sym]
    end
  end

  def id
    attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
  end

  def connection_id
    attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
  end

  def member_key
    "#{connection_id}:#{client_id}"
  end

  def timestamp
    if attributes[:timestamp]
      as_time_from_epoch(attributes[:timestamp])
    else
      protocol_message.timestamp
    end
  end

  def action
    ACTION(attributes[:action])
  end

  def attributes
    @attributes
  end

  # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
  def as_json(*args)
    attributes.dup.tap do |presence_message|
      presence_message['action'] = action.to_i
    end.as_json.reject { |key, val| val.nil? }
  rescue KeyError
    raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
  end

  def to_json(*args)
    as_json(*args).tap do |presence_message|
      decode_binary_data_before_to_json presence_message
    end.to_json
  end

  # Assign this presence message to a ProtocolMessage before delivery to the Ably system
  # @api private
  def assign_to_protocol_message(protocol_message)
    @protocol_message = protocol_message
  end

  # True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
  # @return [Boolean]
  # @api private
  def assigned_to_protocol_message?
    !!@protocol_message
  end

  # The optional ProtocolMessage this presence message is assigned to.  If ProtocolMessage is nil, an error will be raised.
  # @return [Ably::Models::ProtocolMessage]
  # @api private
  def protocol_message
    raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
    @protocol_message
  end

  # Create a static shallow clone of this object with the optional attributes to overide existing values
  # Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
  # Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
  def shallow_clone(new_attributes = {})
    new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

    self.class.new(attributes.to_hash.merge(
      id: new_attributes[:id] || id,
      connection_id: new_attributes[:connection_id] || connection_id,
      timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
    ).merge(new_attributes.to_hash))
  end

  private
  def raw_hash_object
    @raw_hash_object
  end

  def protocol_message_index
    protocol_message.presence.index(self)
  end

  def set_attributes_object(new_attributes)
    @attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
  end

  def logger
    return @logger if @logger
    protocol_message.logger if protocol_message
  end
end

#timestampTime (readonly)

Returns Timestamp when the message was received by the Ably the realtime service

Returns:

  • (Time)

    Timestamp when the message was received by the Ably the realtime service


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/ably/models/presence_message.rb', line 40

class PresenceMessage
  include Ably::Modules::Conversions
  include Ably::Modules::Encodeable
  include Ably::Modules::ModelCommon
  include Ably::Modules::SafeDeferrable if defined?(Ably::Realtime)
  extend Ably::Modules::Enum

  ACTION = ruby_enum('ACTION',
    :absent,
    :present,
    :enter,
    :leave,
    :update
  )

  # Statically register a default set of encoders for this class
  Ably::Models::MessageEncoders.register_default_encoders self

  # {PresenceMessage} initializer
  #
  # @param  attributes  [Hash]            object with the underlying presence message key value attributes
  # @param  [Hash]      options           an options Hash for this initializer
  # @option options     [ProtocolMessage] :protocol_message  An optional protocol message to assocate the presence message with
  # @option options     [Logger]          :logger            An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
  #
  def initialize(attributes, options = {})
    @logger           = options[:logger] # Logger expected for SafeDeferrable
    @protocol_message = options[:protocol_message]
    @raw_hash_object  = attributes

    set_attributes_object attributes

    self.attributes[:client_id] = ensure_utf_8(:client_id, client_id, allow_nil: true) if client_id
    self.attributes[:connection_id] = ensure_utf_8(:connection_id, connection_id, allow_nil: true) if connection_id
    self.attributes[:encoding] = ensure_utf_8(:encoding, encoding, allow_nil: true) if encoding

    self.attributes.freeze
  end

  %w( client_id data encoding ).each do |attribute|
    define_method attribute do
      attributes[attribute.to_sym]
    end
  end

  def id
    attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
  end

  def connection_id
    attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
  end

  def member_key
    "#{connection_id}:#{client_id}"
  end

  def timestamp
    if attributes[:timestamp]
      as_time_from_epoch(attributes[:timestamp])
    else
      protocol_message.timestamp
    end
  end

  def action
    ACTION(attributes[:action])
  end

  def attributes
    @attributes
  end

  # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
  def as_json(*args)
    attributes.dup.tap do |presence_message|
      presence_message['action'] = action.to_i
    end.as_json.reject { |key, val| val.nil? }
  rescue KeyError
    raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
  end

  def to_json(*args)
    as_json(*args).tap do |presence_message|
      decode_binary_data_before_to_json presence_message
    end.to_json
  end

  # Assign this presence message to a ProtocolMessage before delivery to the Ably system
  # @api private
  def assign_to_protocol_message(protocol_message)
    @protocol_message = protocol_message
  end

  # True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably
  # @return [Boolean]
  # @api private
  def assigned_to_protocol_message?
    !!@protocol_message
  end

  # The optional ProtocolMessage this presence message is assigned to.  If ProtocolMessage is nil, an error will be raised.
  # @return [Ably::Models::ProtocolMessage]
  # @api private
  def protocol_message
    raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
    @protocol_message
  end

  # Create a static shallow clone of this object with the optional attributes to overide existing values
  # Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated
  # Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present
  def shallow_clone(new_attributes = {})
    new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

    self.class.new(attributes.to_hash.merge(
      id: new_attributes[:id] || id,
      connection_id: new_attributes[:connection_id] || connection_id,
      timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
    ).merge(new_attributes.to_hash))
  end

  private
  def raw_hash_object
    @raw_hash_object
  end

  def protocol_message_index
    protocol_message.presence.index(self)
  end

  def set_attributes_object(new_attributes)
    @attributes = IdiomaticRubyWrapper(new_attributes.clone, stop_at: [:data])
  end

  def logger
    return @logger if @logger
    protocol_message.logger if protocol_message
  end
end

Instance Method Details

#as_json(*args) ⇒ Object

Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys


114
115
116
117
118
119
120
# File 'lib/ably/models/presence_message.rb', line 114

def as_json(*args)
  attributes.dup.tap do |presence_message|
    presence_message['action'] = action.to_i
  end.as_json.reject { |key, val| val.nil? }
rescue KeyError
  raise KeyError, ':action is missing or invalid, cannot generate a valid Hash for ProtocolMessage'
end

#assign_to_protocol_message(protocol_message) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Assign this presence message to a ProtocolMessage before delivery to the Ably system


130
131
132
# File 'lib/ably/models/presence_message.rb', line 130

def assign_to_protocol_message(protocol_message)
  @protocol_message = protocol_message
end

#assigned_to_protocol_message?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

True if this presence message is assigned to a ProtocolMessage for delivery to Ably, or received from Ably

Returns:

  • (Boolean)

137
138
139
# File 'lib/ably/models/presence_message.rb', line 137

def assigned_to_protocol_message?
  !!@protocol_message
end

#idObject


85
86
87
# File 'lib/ably/models/presence_message.rb', line 85

def id
  attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
end

#protocol_messageAbly::Models::ProtocolMessage

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The optional ProtocolMessage this presence message is assigned to. If ProtocolMessage is nil, an error will be raised.

Returns:

Raises:

  • (RuntimeError)

144
145
146
147
# File 'lib/ably/models/presence_message.rb', line 144

def protocol_message
  raise RuntimeError, 'Presence Message is not yet published with a ProtocolMessage. ProtocolMessage is nil' if @protocol_message.nil?
  @protocol_message
end

#shallow_clone(new_attributes = {}) ⇒ Object

Create a static shallow clone of this object with the optional attributes to overide existing values Shallow clones have no dependency on the originating ProtocolMessage as all field values are stored as opposed to calculated Clones are useful when the original PresenceMessage needs to be mutated, such as storing in a PresenceMap with action :present


152
153
154
155
156
157
158
159
160
# File 'lib/ably/models/presence_message.rb', line 152

def shallow_clone(new_attributes = {})
  new_attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])

  self.class.new(attributes.to_hash.merge(
    id: new_attributes[:id] || id,
    connection_id: new_attributes[:connection_id] || connection_id,
    timestamp: new_attributes[:timestamp] || as_since_epoch(timestamp)
  ).merge(new_attributes.to_hash))
end

#to_json(*args) ⇒ Object


122
123
124
125
126
# File 'lib/ably/models/presence_message.rb', line 122

def to_json(*args)
  as_json(*args).tap do |presence_message|
    decode_binary_data_before_to_json presence_message
  end.to_json
end