Class: Ably::Realtime::Presence::MembersMap Private

Inherits:
Object
  • Object
show all
Extended by:
Modules::Enum
Includes:
Modules::EventEmitter, Modules::SafeYield, Modules::StateEmitter, Enumerable
Defined in:
lib/ably/realtime/presence/members_map.rb

Overview

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

A class encapsulating a map of the members of this presence channel, indexed by the unique Models::PresenceMessage#member_key

This map synchronises the membership of the presence set by handling SYNC messages from the service. Since sync messages can be out-of-order - e.g. a PRESENT sync event being received after that member has in fact left - this map keeps “witness” entries, with ABSENT Action, to remember the fact that a LEAVE event has been seen for a member. These entries are cleared once the last set of updates of a sync sequence have been received.

Constant Summary collapse

STATE =

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

ruby_enum('STATE',
  :initialized,
  :sync_starting, # Indicates the client is waiting for SYNC ProtocolMessages from Ably
  :sync_none, # Indicates the ATTACHED ProtocolMessage had no presence flag and thus no members on the channel
  :finalizing_sync,
  :in_sync,
  :failed
)

Instance Attribute Summary collapse

Instance Method Summary collapse

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::EventEmitter

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

Constructor Details

#initialize(presence) ⇒ MembersMap

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 a new instance of MembersMap


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/ably/realtime/presence/members_map.rb', line 31

def initialize(presence)
  @presence = presence

  @state = STATE(:initialized)

  # Two sets of members maintained
  # @members contains all members present on the channel
  # @local_members contains only this connection's members for the purpose of re-entering the member if channel continuity is lost
  reset_members
  reset_local_members

  @absent_member_cleanup_queue = []

  # Each SYNC session has a unique ID so that following SYNC
  # any members present in the map without this session ID are
  # not present according to Ably, see #RTP19
  @sync_session_id = -1

  setup_event_handlers
end

Instance Attribute Details

#lengthInteger (readonly) Also known as: count, size

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 number of present members known at this point in time, will not wait for sync operation to complete

Returns:

  • (Integer)

    number of present members known at this point in time, will not wait for sync operation to complete


142
143
144
# File 'lib/ably/realtime/presence/members_map.rb', line 142

def length
  present_members.length
end

Instance Method Details

#each(&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.

Note:

this method will not wait for the sync operation to complete so may return an incomplete set of members. Use #get instead.

Method to allow Ably::Realtime::Presence::MembersMap to be Enumerable


150
151
152
153
# File 'lib/ably/realtime/presence/members_map.rb', line 150

def each(&block)
  return to_enum(:each) unless block_given?
  present_members.each(&block)
end

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

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.

Get the list of presence members

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 true, if true the get method waits for the initial presence sync following channel attachment to complete before returning the members present, else it immediately returns the members present currently

Yields:

Returns:


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

def get(options = {}, &block)
  wait_for_sync = options.fetch(:wait_for_sync, true)
  deferrable    = Ably::Util::SafeDeferrable.new(logger)

  result_block = lambda do
    present_members.tap do |members|
      members.keep_if { |member| member.connection_id == options[:connection_id] } if options[:connection_id]
      members.keep_if { |member| member.client_id == options[:client_id] } if options[:client_id]
    end.tap do |members|
      safe_yield block, members if block_given?
      deferrable.succeed members
    end
  end

  if !wait_for_sync || sync_complete?
    result_block.call
  else
    # Must be defined before subsequent procs reference this callback
    reset_callbacks = nil

    in_sync_callback = lambda do
      reset_callbacks.call if reset_callbacks
      result_block.call
    end

    failed_callback = lambda do |error|
      reset_callbacks.call if reset_callbacks
      deferrable.fail error
    end

    reset_callbacks = lambda do
      off(&in_sync_callback)
      off(&failed_callback)
      channel.off(&failed_callback)
    end

    unsafe_once(:in_sync, &in_sync_callback)
    unsafe_once(:failed, &failed_callback)

    channel.unsafe_once(:detaching, :detached, :failed) do |error_reason|
      failed_callback.call error_reason
    end
  end

  deferrable
end

#local_membersArray<PresenceMessage>

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.

A copy of the local members present i.e. members entered from this connection and thus the responsibility of this library to re-enter on the channel automatically if the channel loses continuity

Returns:

  • (Array<PresenceMessage>)

161
162
163
# File 'lib/ably/realtime/presence/members_map.rb', line 161

def local_members
  @local_members
end

#sync_complete?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.

When attaching to a channel that has members present, the server initiates a sync automatically so that the client has a complete list of members.

Until this sync is complete, this method returns false

Returns:

  • (Boolean)

58
59
60
# File 'lib/ably/realtime/presence/members_map.rb', line 58

def sync_complete?
  in_sync?
end

#sync_serial_cursor_at_end?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.

When channel serial in ProtocolMessage SYNC is nil or an empty cursor appears after the ':' such as 'cf30e75054887:psl_7g:client:189'. That is an indication that there are no more SYNC messages.

Returns:

  • (Boolean)

78
79
80
# File 'lib/ably/realtime/presence/members_map.rb', line 78

def sync_serial_cursor_at_end?
  sync_serial.nil? || sync_serial.to_s.match(/^[\w-]+:?$/)
end

#update_sync_serial(serial) ⇒ void

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.

This method returns an undefined value.

Update the SYNC serial from the ProtocolMessage so that SYNC can be resumed. If the serial is nil, or the part after the first : is empty, then the SYNC is complete


68
69
70
# File 'lib/ably/realtime/presence/members_map.rb', line 68

def update_sync_serial(serial)
  @sync_serial = serial
end