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:



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

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

#enter_client_with_id(id, client_id, data = nil, &success_block) ⇒ 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.



114
115
116
117
118
119
# File 'lib/ably/realtime/presence.rb', line 114

def enter_client_with_id(id, 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, id, &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.



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/ably/realtime/presence.rb', line 242

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.



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

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:



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

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.



173
174
175
176
177
178
# File 'lib/ably/realtime/presence.rb', line 173

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



332
333
334
# File 'lib/ably/realtime/presence.rb', line 332

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:



283
284
285
286
# File 'lib/ably/realtime/presence.rb', line 283

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)


343
344
345
# File 'lib/ably/realtime/presence.rb', line 343

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:



297
298
299
# File 'lib/ably/realtime/presence.rb', line 297

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.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/ably/realtime/presence.rb', line 190

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:



224
225
226
227
228
229
# File 'lib/ably/realtime/presence.rb', line 224

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