Class: Ably::Realtime::Presence

Inherits:
Object
  • Object
show all
Extended by:
Modules::Enum
Includes:
Modules::AsyncWrapper, Modules::Conversions, Modules::EventEmitter, Modules::MessageEmitter, Modules::SafeYield, Modules::StateEmitter, Modules::UsesStateMachine
Defined in:
lib/ably/realtime/presence.rb,
lib/ably/realtime/presence/members_map.rb,
lib/ably/realtime/presence/presence_manager.rb,
lib/ably/realtime/presence/presence_state_machine.rb

Overview

Presence provides access to presence operations and state for the associated Channel

Defined Under Namespace

Classes: MembersMap, PresenceManager, PresenceStateMachine

Constant Summary collapse

STATE =
ruby_enum('STATE',
  :initialized,
  :entering,
  :entered,
  :leaving,
  :left,
  :failed
)

Instance Attribute Summary collapse

Attributes included from Modules::UsesStateMachine

#previous_state, #state_history

Instance Method Summary collapse

Methods included from Modules::UsesStateMachine

#synchronize_state_with_statemachine, #transition_state_machine, #transition_state_machine!

Methods included from Modules::StateEmitter

#once_or_if, #once_state_changed, #state, #state=, #state?, #unsafe_once_or_if, #unsafe_once_state_changed

Methods included from Modules::MessageEmitter

#emit_message

Methods included from Modules::EventEmitter

#emit, #off, #on, #once, #unsafe_on, #unsafe_once

Constructor Details

#initialize(channel) ⇒ Presence

Returns a new instance of Presence.



49
50
51
52
53
54
55
56
57
# File 'lib/ably/realtime/presence.rb', line 49

def initialize(channel)
  @channel       = channel
  @client_id     = client.client_id

  @state_machine = PresenceStateMachine.new(self)
  @state         = STATE(state_machine.current_state)
  @members       = MembersMap.new(self)
  @manager       = PresenceManager.new(self)
end

Instance Attribute Details

#__incoming_msgbus__Ably::Util::PubSub (readonly)

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.

Returns Client library internal channel incoming protocol message bus.

Returns:



294
295
296
297
298
# File 'lib/ably/realtime/presence.rb', line 294

def __incoming_msgbus__
  @__incoming_msgbus__ ||= Ably::Util::PubSub.new(
    coerce_into: Proc.new { |event| Ably::Models::ProtocolMessage::ACTION(event) }
  )
end

#channelAbly::Realtime::Channel (readonly)

Channel this Presence object is associated with



24
25
26
# File 'lib/ably/realtime/presence.rb', line 24

def channel
  @channel
end

#client_idString (readonly)

The client_id for the member present on this channel

Returns:

  • (String)


33
34
35
# File 'lib/ably/realtime/presence.rb', line 33

def client_id
  @client_id
end

#connection_idString (readonly)

A unique identifier for this channel client based on their connection, disambiguating situations where a given client_id is present on multiple connections simultaneously.

Returns:

  • (String)


29
30
31
# File 'lib/ably/realtime/presence.rb', line 29

def connection_id
  @connection_id
end

#dataString (readonly)

The data for the member present on this channel

Returns:

  • (String)


37
38
39
# File 'lib/ably/realtime/presence.rb', line 37

def data
  @data
end

#managerAbly::Realtime::Presence::PresenceManager (readonly)

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 Presence manager responsible for actions relating to state changes such as entering a channel



47
48
49
# File 'lib/ably/realtime/presence.rb', line 47

def manager
  @manager
end

#membersMembersMap (readonly)

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.

MembersMap containing an up to date list of members on this channel

Returns:



42
43
44
# File 'lib/ably/realtime/presence.rb', line 42

def members
  @members
end

Instance Method Details

#enter(data = nil) {|Ably::Realtime::Presence| ... } ⇒ Ably::Util::SafeDeferrable

Enter this client into this channel. This client will be added to the presence set and presence subscribers will see an enter message for this client.

Parameters:

  • data (String, Hash, nil) (defaults to: nil)

    optional data (eg a status message) for this member

Yields:

Returns:



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
# File 'lib/ably/realtime/presence.rb', line 67

def enter(data = nil, &success_block)
  deferrable = create_deferrable

  ensure_supported_payload data
  @data = data

  return deferrable_succeed(deferrable, &success_block) if state == STATE.Entered

  ensure_presence_publishable_on_connection
  ensure_channel_attached(deferrable) do
    if entering?
      once_or_if(STATE.Entered, else: proc { |args| deferrable_fail deferrable, *args }) do
        deferrable_succeed deferrable, &success_block
      end
    else
      change_state STATE.Entering
      send_protocol_message_and_transition_state_to(
        Ably::Models::PresenceMessage::ACTION.Enter,
        deferrable:   deferrable,
        target_state: STATE.Entered,
        data:         data,
        client_id:    client_id,
        failed_state: STATE.Failed,
        &success_block
      )
    end
  end
end

#enter_client(client_id, data = nil) {|Ably::Realtime::Presence| ... } ⇒ Ably::Util::SafeDeferrable

Enter the specified client_id into this channel. The given client will be added to the presence set and presence subscribers will see a corresponding presence message. This method is provided to support connections (e.g. connections from application server instances) that act on behalf of multiple client_ids. In order to be able to enter the channel with this method, the client library must have been instanced either with a key, or with a token bound to the wildcard client_id

Parameters:

  • client_id (String)

    id of the client

  • data (String, Hash, nil) (defaults to: nil)

    optional data (eg a status message) for this member

Yields:

Returns:



109
110
111
112
113
114
# File 'lib/ably/realtime/presence.rb', line 109

def enter_client(client_id, data = nil, &success_block)
  ensure_supported_client_id client_id
  ensure_supported_payload data

  send_presence_action_for_client(Ably::Models::PresenceMessage::ACTION.Enter, client_id, data, &success_block)
end

#get(options = {}) {|Array<Ably::Models::PresenceMessage>| ... } ⇒ Ably::Util::SafeDeferrable

Get the presence state for this Channel.

Parameters:

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

    an options Hash to filter members

Options Hash (options):

  • :client_id (String)

    optional client_id filter for the member

  • :connection_id (String)

    optional connection_id filter for the member

  • :wait_for_sync (String)

    defaults to false, if true the get method waits for the initial presence sync following channel attachment to complete before returning the members present

Yields:

Returns:



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/ably/realtime/presence.rb', line 224

def get(options = {}, &block)
  deferrable = create_deferrable

  ensure_channel_attached(deferrable) do
    members.get(options).tap do |members_map_deferrable|
      members_map_deferrable.callback do |*args|
        safe_yield(block, *args) if block_given?
        deferrable.succeed(*args)
      end
      members_map_deferrable.errback do |*args|
        deferrable.fail(*args)
      end
    end
  end
end

#history(options = {}) {|Ably::Models::PaginatedResult<Ably::Models::PresenceMessage>| ... } ⇒ Ably::Util::SafeDeferrable

Return the presence messages history for the channel

Once attached to a channel, you can retrieve presence message history on the channel before the channel was attached with the option until_attach: true. This is very useful for developers who wish to capture new presence events as well as retrieve historical presence state with the guarantee that no presence history has been missed.

Parameters:

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

    the options for the message history request

Options Hash (options):

  • :until_attach (Boolean)

    When true, request for history will be limited only to messages published before the associated channel was attached. The associated channel must be attached.

  • :start (Integer, Time)

    Ensure earliest time or millisecond since epoch for any presence messages retrieved is :start

  • :end (Integer, Time)

    Ensure latest time or millisecond since epoch for any presence messages retrieved is :end

  • :direction (Symbol)

    :forwards or :backwards, defaults to :backwards

  • :limit (Integer)

    Maximum number of messages to retrieve up to 1,000, defaults to 100

Yields:

Returns:



280
281
282
283
284
285
286
287
288
289
# File 'lib/ably/realtime/presence.rb', line 280

def history(options = {}, &callback)
  if options.delete(:until_attach)
    raise ArgumentError, 'option :until_attach cannot be specified if the channel is not attached' unless channel.attached?
    options[:from_serial] = channel.attached_serial
  end

  async_wrap(callback) do
    rest_presence.history(options.merge(async_blocking_operations: true))
  end
end

#leave(data = nil) {|Ably::Realtime::Presence| ... } ⇒ Ably::Util::SafeDeferrable

Leave this client from this channel. This client will be removed from the presence set and presence subscribers will see a leave message for this client.

Parameters:

  • data (String, Hash, nil) (defaults to: nil)

    optional data (eg a status message) for this member

Yields:

Returns:

Raises:



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
# File 'lib/ably/realtime/presence.rb', line 124

def leave(data = nil, &success_block)
  deferrable = create_deferrable

  ensure_supported_payload data
  raise Ably::Exceptions::Standard.new('Unable to leave presence channel that is not entered', 400, 91002) unless able_to_leave?

  @data = data

  return deferrable_succeed(deferrable, &success_block) if state == STATE.Left

  ensure_presence_publishable_on_connection
  ensure_channel_attached(deferrable) do
    if leaving?
      once_or_if(STATE.Left, else: proc { |error|deferrable_fail deferrable, *args }) do
        deferrable_succeed deferrable, &success_block
      end
    else
      change_state STATE.Leaving
      send_protocol_message_and_transition_state_to(
        Ably::Models::PresenceMessage::ACTION.Leave,
        deferrable:   deferrable,
        target_state: STATE.Left,
        data:         data,
        client_id:    client_id,
        failed_state: STATE.Failed,
        &success_block
      )
    end
  end
end

#leave_client(client_id, data = nil) {|Ably::Realtime::Presence| ... } ⇒ Ably::Util::SafeDeferrable

Leave a given client_id from this channel. This client will be removed from the presence set and presence subscribers will see a leave message for this client.

Parameters:

  • client_id (String)

    id of the client

  • data (String, Hash, nil) (defaults to: nil)

    optional data (eg a status message) for this member

Yields:

Returns:



163
164
165
166
167
168
# File 'lib/ably/realtime/presence.rb', line 163

def leave_client(client_id, data = nil, &success_block)
  ensure_supported_client_id client_id
  ensure_supported_payload data

  send_presence_action_for_client(Ably::Models::PresenceMessage::ACTION.Leave, client_id, data, &success_block)
end

#loggerObject

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.

Used by Modules::StateEmitter to debug action changes



309
310
311
# File 'lib/ably/realtime/presence.rb', line 309

def logger
  client.logger
end

#set_connection_id(new_connection_id) ⇒ 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.

Configure the connection ID for this presence channel. Typically configured only once when a user first enters a presence channel.



303
304
305
# File 'lib/ably/realtime/presence.rb', line 303

def set_connection_id(new_connection_id)
  @connection_id = new_connection_id
end

#subscribe(*actions) {|Ably::Models::PresenceMessage| ... } ⇒ void

This method returns an undefined value.

Subscribe to presence events on the associated Channel. This implicitly attaches the Channel if it is not already attached.

Parameters:

Yields:



248
249
250
251
252
# File 'lib/ably/realtime/presence.rb', line 248

def subscribe(*actions, &callback)
  ensure_channel_attached do
    super
  end
end

#sync_complete?Boolean

Returns true when the initial member SYNC following channel attach is completed

Returns:

  • (Boolean)


314
315
316
# File 'lib/ably/realtime/presence.rb', line 314

def sync_complete?
  members.sync_complete?
end

#unsubscribe(*actions, &callback) ⇒ void

This method returns an undefined value.

Unsubscribe the matching block for presence events on the associated Channel. If a block is not provided, all subscriptions will be unsubscribed

Parameters:



261
262
263
# File 'lib/ably/realtime/presence.rb', line 261

def unsubscribe(*actions, &callback)
  super
end

#update(data = nil) {|Ably::Realtime::Presence| ... } ⇒ Ably::Util::SafeDeferrable

Update the presence data for this client. If the client is not already a member of the presence set it will be added, and presence subscribers will see an enter or update message for this client.

Parameters:

  • data (String, Hash, nil) (defaults to: nil)

    optional data (eg a status message) for this member

Yields:

Returns:



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/ably/realtime/presence.rb', line 179

def update(data = nil, &success_block)
  deferrable = create_deferrable

  ensure_supported_payload data

  @data = data

  ensure_presence_publishable_on_connection
  ensure_channel_attached(deferrable) do
    send_protocol_message_and_transition_state_to(
      Ably::Models::PresenceMessage::ACTION.Update,
      deferrable:   deferrable,
      target_state: STATE.Entered,
      client_id:    client_id,
      data:         data,
      &success_block
    )
  end
end

#update_client(client_id, data = nil) {|Ably::Realtime::Presence| ... } ⇒ Ably::Util::SafeDeferrable

Update the presence data for a specified client_id into this channel. If the client is not already a member of the presence set it will be added, and presence subscribers will see an enter or update message for this client. As with #enter_client, the connection must be authenticated in a way that enables it to represent an arbitrary clientId.

Parameters:

  • client_id (String)

    id of the client

  • data (String, Hash, nil) (defaults to: nil)

    optional data (eg a status message) for this member

Yields:

Returns:



210
211
212
213
214
215
# File 'lib/ably/realtime/presence.rb', line 210

def update_client(client_id, data = nil, &success_block)
  ensure_supported_client_id client_id
  ensure_supported_payload data

  send_presence_action_for_client(Ably::Models::PresenceMessage::ACTION.Update, client_id, data, &success_block)
end