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

Enables the presence set to be entered and subscribed to, and the historic presence set to be retrieved for a channel.

Defined Under Namespace

Classes: MembersMap, PresenceManager, PresenceStateMachine

Constant Summary collapse

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

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_off, #unsafe_on, #unsafe_once

Constructor Details

#initialize(channel) ⇒ Presence

Returns a new instance of Presence.



44
45
46
47
48
49
50
51
52
# File 'lib/ably/realtime/presence.rb', line 44

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:



316
317
318
319
320
# File 'lib/ably/realtime/presence.rb', line 316

def __incoming_msgbus__
  @__incoming_msgbus__ ||= Ably::Util::PubSub.new(
    coerce_into: lambda { |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)


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

def client_id
  @client_id
end

#dataString (readonly)

The data for the member present on this channel

Returns:

  • (String)


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

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



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

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:



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

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:



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

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

  requirements_failed_deferrable = ensure_presence_publishable_on_connection_deferrable
  return requirements_failed_deferrable if requirements_failed_deferrable

  ensure_channel_attached(deferrable) do
    if entering?
      once_or_if(STATE.Entered, else: lambda { |args| deferrable_fail deferrable, *args }) do
        deferrable_succeed deferrable, &success_block
      end
    else
      current_state = state
      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: current_state, # return to current state if enter fails
        &success_block
      )
    end
  end
end

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

Enters the presence set of the channel for a given clientId. Enables a single client to update presence on behalf of any number of clients using a single connection. The library must have been instantiated with an API key or a token bound to a wildcard clientId. An optional callback may be provided to notify of the success or failure of the operation.

Parameters:

  • client_id (String)

    id of the client

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

    The payload associated with the presence member. A JSON object of arbitrary key-value pairs that may contain metadata, and/or ancillary payloads.

Yields:

Returns:



106
107
108
109
110
111
# File 'lib/ably/realtime/presence.rb', line 106

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 = {}, &block) ⇒ Object

Retrieves the current members present on the channel and the metadata for each member, such as their Models::ProtocolMessage::ACTION and ID. Returns an array of Models::PresenceMessage objects.



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/ably/realtime/presence.rb', line 234

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

  # #RTP11d Don't return PresenceMap when wait for sync is true
  #   if the map is stale
  wait_for_sync = options.fetch(:wait_for_sync, true)
  if wait_for_sync && channel.suspended?
    EventMachine.next_tick do
      deferrable.fail Ably::Exceptions::InvalidState.new(
        'Presence state is out of sync as channel is SUSPENDED. Presence#get on a SUSPENDED channel is only supported with option wait_for_sync: false',
        nil,
        Ably::Exceptions::Codes::PRESENCE_STATE_IS_OUT_OF_SYNC
      )
    end
    return deferrable
  end

  ensure_channel_attached(deferrable, allow_suspended: true) do
    members.get(options).tap do |members_map_deferrable|
      members_map_deferrable.callback do |members|
        safe_yield(block, members) if block_given?
        deferrable.succeed(members)
      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

Retrieves a Models::PaginatedResult object, containing an array of historical Models::PresenceMessage objects for the channel. If the channel is configured to persist messages, then presence messages can be retrieved from history for up to 72 hours in the past. If not, presence messages can only be retrieved from history for up to two minutes in the past.



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

def history(options = {}, &callback)
  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:



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

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

  ensure_supported_payload data

  @data = data

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

  requirements_failed_deferrable = ensure_presence_publishable_on_connection_deferrable
  return requirements_failed_deferrable if requirements_failed_deferrable

  ensure_channel_attached(deferrable) do
    if leaving?
      once_or_if(STATE.Left, else: lambda { |error|deferrable_fail deferrable, *args }) do
        deferrable_succeed deferrable, &success_block
      end
    else
      current_state = state
      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: current_state, # return to current state if leave fails
        &success_block
      )
    end
  end
end

#leave_client(client_id, data = nil, &success_block) ⇒ Object

Leaves the presence set of the channel for a given clientId. Enables a single client to update presence on behalf of any number of clients using a single connection. The library must have been instantiated with an API key or a token bound to a wildcard clientId. An optional callback may be provided to notify of the success or failure of the operation.



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

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



324
325
326
# File 'lib/ably/realtime/presence.rb', line 324

def logger
  client.logger
end

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

This method returns an undefined value.

Registers a listener that is called each time a Models::PresenceMessage is received on the channel, such as a new member entering the presence set. A callback may optionally be passed in to this call to be notified of success or failure of the channel Channel#attach operation.

Parameters:

Yields:



275
276
277
278
# File 'lib/ably/realtime/presence.rb', line 275

def subscribe(*actions, &callback)
  implicit_attach
  super
end

#sync_complete?Boolean

Indicates whether the presence set synchronization between Ably and the clients on the channel has been completed. Set to true when the sync is complete.

return [Boolean]

Returns:

  • (Boolean)


335
336
337
# File 'lib/ably/realtime/presence.rb', line 335

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 Models::PresenceMessage for the channel.

Parameters:



289
290
291
# File 'lib/ably/realtime/presence.rb', line 289

def unsubscribe(*actions, &callback)
  super
end

#update(data = nil, &success_block) ⇒ Object

Updates the data payload for a presence member. If called before entering the presence set, this is treated as an Ably::Realtime::Presence::STATE.Entered event. An optional callback may be provided to notify of the success or failure of the operation.



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/ably/realtime/presence.rb', line 182

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

  ensure_supported_payload data

  @data = data

  requirements_failed_deferrable = ensure_presence_publishable_on_connection_deferrable
  return requirements_failed_deferrable if requirements_failed_deferrable

  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

Updates the data payload for a presence member using a given clientId. Enables a single client to update presence on behalf of any number of clients using a single connection. The library must have been instantiated with an API key or a token bound to a wildcard clientId. An optional callback may be provided to notify of the success or failure of the operation.

Parameters:

  • client_id (String)

    id of the client

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

    The payload associated with the presence member. A JSON object of arbitrary key-value pairs that may contain metadata, and/or ancillary payloads.

Yields:

Returns:



216
217
218
219
220
221
# File 'lib/ably/realtime/presence.rb', line 216

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