From 9dbe92cd2ec6b45f0dcb44e183d1df07bf2d1611 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 6 Jun 2024 15:11:44 +0530 Subject: [PATCH 1/6] renamed in_sync enum to sync_complete, updated as per spec --- lib/ably/realtime/presence/members_map.rb | 42 +++++++++-------------- spec/acceptance/realtime/presence_spec.rb | 20 +++++------ 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/lib/ably/realtime/presence/members_map.rb b/lib/ably/realtime/presence/members_map.rb index ef2d8df32..dfa3d73ad 100644 --- a/lib/ably/realtime/presence/members_map.rb +++ b/lib/ably/realtime/presence/members_map.rb @@ -23,7 +23,7 @@ class MembersMap :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, + :sync_complete, # Indicates completion of server initiated sync :failed ) include Ably::Modules::StateEmitter @@ -49,16 +49,6 @@ def initialize(presence) setup_event_handlers end - # 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 - # - # @return [Boolean] - def sync_complete? - in_sync? - end - # 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 # @@ -110,27 +100,27 @@ def get(options = {}, &block) # Must be defined before subsequent procs reference this callback reset_callbacks = nil - in_sync_callback = lambda do + sync_complete_callback = lambda do reset_callbacks.call if reset_callbacks result_block.call end - failed_callback = lambda do |error| + sync_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) + off(&sync_complete_callback) + off(&sync_failed_callback) + channel.off(&sync_failed_callback) end - unsafe_once(:in_sync, &in_sync_callback) - unsafe_once(:failed, &failed_callback) + unsafe_once(:sync_complete, &sync_complete_callback) + unsafe_once(:failed, &sync_failed_callback) channel.unsafe_once(:detaching, :detached, :failed) do |error_reason| - failed_callback.call error_reason + sync_failed_callback.call error_reason end end @@ -227,7 +217,7 @@ def setup_event_handlers connection.on_resume(&resume_sync_proc) end - unsafe_once(:in_sync, :failed) do + unsafe_once(:sync_complete, :failed) do connection.off_resume(&resume_sync_proc) end end @@ -240,11 +230,11 @@ def setup_event_handlers unsafe_on(:finalizing_sync) do clean_up_absent_members - clean_up_members_not_present_in_sync - change_state :in_sync + clean_up_members_not_present_after_sync + change_state :sync_complete end - unsafe_on(:in_sync) do + unsafe_on(:sync_complete) do update_local_member_state end end @@ -375,7 +365,7 @@ def add_presence_member(presence_message) def remove_presence_member(presence_message) logger.debug { "#{self.class.name}: Member '#{presence_message.member_key}' removed.\n#{presence_message.to_json}" } - if in_sync? + if sync_complete? member_set_delete presence_message else member_set_upsert presence_message, false @@ -401,7 +391,7 @@ def member_set_upsert(presence_message, present) def member_set_delete(presence_message) members.delete presence_message.member_key - if in_sync? + if sync_complete? # If not in SYNC, then local members missing may need to be re-entered # Let #update_local_member_state handle missing members local_members.delete presence_message.member_key @@ -431,7 +421,7 @@ def clean_up_absent_members end end - def clean_up_members_not_present_in_sync + def clean_up_members_not_present_after_sync members.select do |member_key, member| member.fetch(:sync_session_id) != sync_session_id end.each do |member_key, member| diff --git a/spec/acceptance/realtime/presence_spec.rb b/spec/acceptance/realtime/presence_spec.rb index 8f3a5e54c..ac87036e5 100644 --- a/spec/acceptance/realtime/presence_spec.rb +++ b/spec/acceptance/realtime/presence_spec.rb @@ -516,11 +516,11 @@ def presence_action(method_name, data) stop_reactor end - it 'will emit an :in_sync event when synchronisation is complete' do + it 'will emit an :sync_complete event when synchronisation is complete' do presence_client_one.enter presence_client_two.enter - presence_anonymous_client.members.once(:in_sync) do + presence_anonymous_client.members.once(:sync_complete) do stop_reactor end @@ -545,7 +545,7 @@ def presence_action(method_name, data) entered += 1 next unless entered == 2 - presence_anonymous_client.members.once(:in_sync) do + presence_anonymous_client.members.once(:sync_complete) do expect(presence_anonymous_client.members.count).to eql(2) member_ids = presence_anonymous_client.members.map(&:member_key) expect(member_ids.count).to eql(2) @@ -848,7 +848,7 @@ def setup_members_on(presence) # Hacky accessing a private method, but absent members are intentionally not exposed to any public APIs expect(presence_anonymous_client.members.send(:absent_members).length).to eql(1) - presence_anonymous_client.members.once(:in_sync) do + presence_anonymous_client.members.once(:sync_complete) do # Check that members count is exact indicating the members with LEAVE action after sync are removed expect(presence_anonymous_client).to be_sync_complete expect(presence_anonymous_client.members.length).to eql(enter_expected_count - 1) @@ -1004,7 +1004,7 @@ def setup_members_on(presence) channel_anonymous_client.attach do presence_anonymous_client.get(wait_for_sync: false) do |members| - expect(presence_anonymous_client.members).to_not be_in_sync + expect(presence_anonymous_client.members).to_not be_sync_complete expect(members.count).to eql(0) stop_reactor end @@ -1211,7 +1211,7 @@ def setup_members_on(presence) presence_client_one.subscribe(:enter) do presence_client_one.unsubscribe :enter EventMachine.add_timer(0.5) do - expect(presence_client_one.members).to be_in_sync + expect(presence_client_one.members).to be_sync_complete expect(presence_client_one.members.send(:members).count).to eql(1) presence_client_one.leave data end @@ -2525,7 +2525,7 @@ def cripple_websocket_transport let(:member_data) { random_str } it 'immediately resends all local presence members (#RTP5c2, #RTP19a)' do - in_sync_confirmed_no_local_members = false + sync_complete_confirmed_no_local_members = false local_member_leave_event_fired = false presence_client_one.enter(member_data) @@ -2546,16 +2546,16 @@ def cripple_websocket_transport EventMachine.next_tick do expect(presence_client_one.members.length).to eql(1) expect(presence_client_one.members.local_members.length).to eql(1) - expect(in_sync_confirmed_no_local_members).to be_truthy + expect(sync_complete_confirmed_no_local_members).to be_truthy stop_reactor end end - presence_client_one.members.once(:in_sync) do + presence_client_one.members.once(:sync_complete) do # Immediately after SYNC (no sync actually occurred, but this event fires immediately after a channel SYNCs or is not expecting to SYNC) expect(presence_client_one.members.length).to eql(0) expect(presence_client_one.members.local_members.length).to eql(0) - in_sync_confirmed_no_local_members = true + sync_complete_confirmed_no_local_members = true end # ATTACHED ProtocolMessage with no presence flag will clear the presence set immediately, #RTP19a From 5b0a006f2726cc1edab4b7f5e8314b85842287bc Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 6 Jun 2024 15:34:02 +0530 Subject: [PATCH 2/6] Implemented onAttach channel presence 1. Added private onAttach method to presence_manager 2. Depending on the has_presence_flag, sync is marked either as started or none 3. Entering local members when onAttach is called 4. Removed client initiated sync from presence code ( as per spec ) 5. Removed entering local members at the end of the sync --- lib/ably/realtime/channel/channel_manager.rb | 19 +--- lib/ably/realtime/presence.rb | 17 +++- lib/ably/realtime/presence/members_map.rb | 91 ++++++------------- .../realtime/presence/presence_manager.rb | 28 +++--- 4 files changed, 56 insertions(+), 99 deletions(-) diff --git a/lib/ably/realtime/channel/channel_manager.rb b/lib/ably/realtime/channel/channel_manager.rb index d10bc66ce..9c0fdc02a 100644 --- a/lib/ably/realtime/channel/channel_manager.rb +++ b/lib/ably/realtime/channel/channel_manager.rb @@ -34,9 +34,9 @@ def detach(error, previous_state) # Channel is attached, notify presence if sync is expected def attached(attached_protocol_message) # If no attached ProtocolMessage then this attached request was triggered by the client - # library, such as returning to attached whne detach has failed + # library, such as returning to attached when detach has failed if attached_protocol_message - update_presence_sync_state_following_attached attached_protocol_message + channel.presence.manager.on_attach attached_protocol_message.has_presence_flag? channel.properties.set_attach_serial(attached_protocol_message.channel_serial) channel.options.set_modes_from_flags(attached_protocol_message.flags) channel.options.set_params(attached_protocol_message.params) @@ -60,6 +60,7 @@ def request_reattach(options = {}) end def duplicate_attached_received(protocol_message) + logger.debug { "Server initiated ATTACHED message received for channel '#{channel.name}' with state #{channel.state}" } if protocol_message.error channel.set_channel_error_reason protocol_message.error log_channel_error protocol_message.error @@ -68,9 +69,7 @@ def duplicate_attached_received(protocol_message) channel.properties.set_attach_serial(protocol_message.channel_serial) channel.options.set_modes_from_flags(protocol_message.flags) - if protocol_message.has_channel_resumed_flag? - logger.debug { "ChannelManager: Additional resumed ATTACHED message received for #{channel.state} channel '#{channel.name}'" } - else + unless protocol_message.has_channel_resumed_flag? channel.emit :update, Ably::Models::ChannelStateChange.new( current: channel.state, previous: channel.state, @@ -78,7 +77,7 @@ def duplicate_attached_received(protocol_message) reason: protocol_message.error, resumed: false, ) - update_presence_sync_state_following_attached protocol_message + channel.presence.manager.on_attach protocol_message.has_presence_flag? end end @@ -254,14 +253,6 @@ def send_state_change_protocol_message(new_state, state_if_failed, message_optio ) end - def update_presence_sync_state_following_attached(attached_protocol_message) - if attached_protocol_message.has_presence_flag? - channel.presence.manager.sync_expected - else - channel.presence.manager.sync_not_expected - end - end - def logger connection.logger end diff --git a/lib/ably/realtime/presence.rb b/lib/ably/realtime/presence.rb index 0c4fcd3cd..cdaba2efe 100644 --- a/lib/ably/realtime/presence.rb +++ b/lib/ably/realtime/presence.rb @@ -110,6 +110,14 @@ def enter_client(client_id, data = nil, &success_block) send_presence_action_for_client(Ably::Models::PresenceMessage::ACTION.Enter, client_id, data, &success_block) end + # @api private + 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 + # 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. # @@ -338,8 +346,11 @@ def sync_complete? private # @return [Ably::Models::PresenceMessage] presence message is returned allowing callbacks to be added - def send_presence_protocol_message(presence_action, client_id, data) + def send_presence_protocol_message(presence_action, client_id, data, id = nil) presence_message = create_presence_message(presence_action, client_id, data) + unless id.nil? + presence_message.id = id + end unless presence_message.client_id raise Ably::Exceptions::Standard.new('Unable to enter create presence message without a client_id', 400, Ably::Exceptions::Codes::UNABLE_TO_ENTER_PRESENCE_CHANNEL_NO_CLIENTID) end @@ -433,13 +444,13 @@ def deferrable_fail(deferrable, *args, &block) deferrable end - def send_presence_action_for_client(action, client_id, data, &success_block) + def send_presence_action_for_client(action, client_id, data, id = nil, &success_block) requirements_failed_deferrable = ensure_presence_publishable_on_connection_deferrable return requirements_failed_deferrable if requirements_failed_deferrable deferrable = create_deferrable ensure_channel_attached(deferrable) do - send_presence_protocol_message(action, client_id, data).tap do |protocol_message| + send_presence_protocol_message(action, client_id, data, id).tap do |protocol_message| protocol_message.callback { |message| deferrable_succeed deferrable, &success_block } protocol_message.errback { |error| deferrable_fail deferrable, error } end diff --git a/lib/ably/realtime/presence/members_map.rb b/lib/ably/realtime/presence/members_map.rb index dfa3d73ad..49b006f6f 100644 --- a/lib/ably/realtime/presence/members_map.rb +++ b/lib/ably/realtime/presence/members_map.rb @@ -146,7 +146,7 @@ def each(&block) # and thus the responsibility of this library to re-enter on the channel automatically if the # channel loses continuity # - # @return [Array] + # @return [Hash] # @api private def local_members @local_members @@ -203,23 +203,14 @@ def setup_event_handlers update_members_and_emit_events presence_message end + # RTP5a channel.unsafe_on(:failed, :detached) do reset_members reset_local_members end - resume_sync_proc = method(:resume_sync).to_proc - unsafe_on(:sync_starting) do @sync_session_id += 1 - - channel.unsafe_once(:attached) do - connection.on_resume(&resume_sync_proc) - end - - unsafe_once(:sync_complete, :failed) do - connection.off_resume(&resume_sync_proc) - end end unsafe_on(:sync_none) do @@ -233,60 +224,31 @@ def setup_event_handlers clean_up_members_not_present_after_sync change_state :sync_complete end - - unsafe_on(:sync_complete) do - update_local_member_state - end end - # Listen for events that change the PresenceMap state and thus - # need to be replicated to the local member set - def update_local_member_state - new_local_members = members.select do |member_key, member| - member.fetch(:message).connection_id == connection.id - end.each_with_object({}) do |(member_key, member), hash_object| - hash_object[member_key] = member.fetch(:message) - end - - @local_members.reject do |member_key, message| - new_local_members.keys.include?(member_key) - end.each do |member_key, message| - re_enter_local_member_missing_from_presence_map message - end - - @local_members = new_local_members - end - - def re_enter_local_member_missing_from_presence_map(presence_message) - local_client_id = presence_message.client_id || client.auth.client_id - logger.debug { "#{self.class.name}: Manually re-entering local presence member, client ID: #{local_client_id} with data: #{presence_message.data}" } - presence.enter_client(local_client_id, presence_message.data).tap do |deferrable| - deferrable.errback do |error| - presence_message_client_id = presence_message.client_id || client.auth.client_id - re_enter_error = Ably::Models::ErrorInfo.new( - message: "unable to automatically re-enter presence channel for client_id '#{presence_message_client_id}'. Source error code #{error.code} and message '#{error.message}'", - code: Ably::Exceptions::Codes::UNABLE_TO_AUTOMATICALLY_REENTER_PRESENCE_CHANNEL - ) - channel.emit :update, Ably::Models::ChannelStateChange.new( - current: channel.state, - previous: channel.state, - event: Ably::Realtime::Channel::EVENT(:update), - reason: re_enter_error, - resumed: true - ) + def enter_local_members + local_members.values.each do |member| + local_client_id = member.client_id || client.auth.client_id + logger.debug { "#{self.class.name}: Manually re-entering local presence member, client ID: #{local_client_id} with data: #{member.data}" } + presence.enter_client_with_id(member.id, local_client_id, member.data).tap do |deferrable| + deferrable.errback do |error| + presence_message_client_id = member.client_id || client.auth.client_id + re_enter_error = Ably::Models::ErrorInfo.new( + message: "unable to automatically re-enter presence channel for client_id '#{presence_message_client_id}'. Source error code #{error.code} and message '#{error.message}'", + code: Ably::Exceptions::Codes::UNABLE_TO_AUTOMATICALLY_REENTER_PRESENCE_CHANNEL + ) + channel.emit :update, Ably::Models::ChannelStateChange.new( + current: channel.state, + previous: channel.state, + event: Ably::Realtime::Channel::EVENT(:update), + reason: re_enter_error, + resumed: true + ) + end end end end - # Trigger a manual SYNC operation to resume member synchronisation from last known cursor position - def resume_sync - connection.send_protocol_message( - action: Ably::Models::ProtocolMessage::ACTION.Sync.to_i, - channel: channel.name, - channel_serial: sync_serial - ) if channel.attached? - end - def update_members_and_emit_events(presence_message) return unless ensure_presence_message_is_valid(presence_message) @@ -384,17 +346,16 @@ def touch_presence_member(presence_message) def member_set_upsert(presence_message, present) members[presence_message.member_key] = { present: present, message: presence_message, sync_session_id: sync_session_id } if presence_message.connection_id == connection.id - local_members[presence_message.member_key] = presence_message - logger.debug { "#{self.class.name}: Local member '#{presence_message.member_key}' added" } + local_members[presence_message.client_id] = presence_message + logger.debug { "#{self.class.name}: Local member '#{presence_message.client_id}' added" } end end def member_set_delete(presence_message) members.delete presence_message.member_key - if sync_complete? - # If not in SYNC, then local members missing may need to be re-entered - # Let #update_local_member_state handle missing members - local_members.delete presence_message.member_key + if sync_complete? and presence_message.connection_id == connection.id + local_members.delete presence_message.client_id + logger.debug { "#{self.class.name}: Local member '#{presence_message.client_id}' deleted" } end end diff --git a/lib/ably/realtime/presence/presence_manager.rb b/lib/ably/realtime/presence/presence_manager.rb index 54c27f9bf..f5d5ca01a 100644 --- a/lib/ably/realtime/presence/presence_manager.rb +++ b/lib/ably/realtime/presence/presence_manager.rb @@ -19,13 +19,18 @@ def initialize(presence) setup_channel_event_handlers end - # Expect SYNC ProtocolMessages from the server with a list of current members on this channel - # - # @return [void] - # # @api private - def sync_expected - presence.members.change_state :sync_starting + def on_attach(has_presence_flag) + if has_presence_flag + # Expect SYNC ProtocolMessages from the server with a list of current members on this channel + presence.members.change_state :sync_starting + else + # There server has indicated that there are no SYNC ProtocolMessages to come because + # there are no members on this channel + logger.debug { "#{self.class.name}: Emitting leave events for all members as a SYNC is not expected and thus there are no members on the channel" } + presence.members.change_state :sync_none + end + presence.members.send(:enter_local_members) end # Process presence messages from SYNC messages. Sync can be server-initiated or triggered following ATTACH @@ -47,17 +52,6 @@ def sync_process_messages(serial, presence_messages) presence.members.change_state :finalizing_sync if presence.members.sync_serial_cursor_at_end? end - # There server has indicated that there are no SYNC ProtocolMessages to come because - # there are no members on this channel - # - # @return [void] - # - # @api private - def sync_not_expected - logger.debug { "#{self.class.name}: Emitting leave events for all members as a SYNC is not expected and thus there are no members on the channel" } - presence.members.change_state :sync_none - end - private def_delegators :presence, :members, :channel From 4022ab83ea4f2071e04ce1fa5659a4157064e27c Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Mon, 24 Jun 2024 17:30:00 +0530 Subject: [PATCH 3/6] Removed unused references to resume_callbacks used for client initiated presence sync --- lib/ably/realtime/connection.rb | 22 -------------- .../realtime/connection/connection_manager.rb | 1 - spec/unit/realtime/connection_spec.rb | 30 ------------------- 3 files changed, 53 deletions(-) diff --git a/lib/ably/realtime/connection.rb b/lib/ably/realtime/connection.rb index bab01ed89..f5df38b28 100644 --- a/lib/ably/realtime/connection.rb +++ b/lib/ably/realtime/connection.rb @@ -531,24 +531,6 @@ def set_connection_details(connection_details) @details = connection_details end - # Executes registered callbacks for a successful connection resume event - # @api private - def trigger_resumed - resume_callbacks.each(&:call) - end - - # Provides a simple hook to inject a callback when a connection is successfully resumed - # @api private - def on_resume(&callback) - resume_callbacks << callback - end - - # Remove a registered connection resume callback - # @api private - def off_resume(&callback) - resume_callbacks.delete(callback) - end - # Returns false if messages cannot be published as a result of message queueing being disabled # @api private def can_publish_messages? @@ -619,10 +601,6 @@ def client_msg_serial @client_msg_serial end - def resume_callbacks - @resume_callbacks ||= [] - end - def create_pub_sub_message_bus Ably::Util::PubSub.new( coerce_into: lambda do |event| diff --git a/lib/ably/realtime/connection/connection_manager.rb b/lib/ably/realtime/connection/connection_manager.rb index 6cd1419b5..ad0970bb1 100644 --- a/lib/ably/realtime/connection/connection_manager.rb +++ b/lib/ably/realtime/connection/connection_manager.rb @@ -125,7 +125,6 @@ def connected(protocol_message) if connection.key if protocol_message.connection_id == connection.id logger.debug { "ConnectionManager: Connection resumed successfully - ID #{connection.id} and key #{connection.key}" } - EventMachine.next_tick { connection.trigger_resumed } resend_pending_message_ack_queue else nack_messages_on_all_channels protocol_message.error diff --git a/spec/unit/realtime/connection_spec.rb b/spec/unit/realtime/connection_spec.rb index deac7432e..9c227af0a 100644 --- a/spec/unit/realtime/connection_spec.rb +++ b/spec/unit/realtime/connection_spec.rb @@ -34,36 +34,6 @@ it_behaves_like 'an incoming protocol message bus' it_behaves_like 'an outgoing protocol message bus' - describe 'connection resume callbacks', api_private: true do - let(:callbacks) { [] } - - describe '#trigger_resumed' do - it 'executes the callbacks' do - subject.on_resume { callbacks << true } - subject.trigger_resumed - expect(callbacks.count).to eql(1) - end - end - - describe '#on_resume' do - it 'registers a callback' do - subject.on_resume { callbacks << true } - subject.trigger_resumed - expect(callbacks.count).to eql(1) - end - end - - describe '#off_resume' do - it 'registers a callback' do - subject.on_resume { callbacks << true } - additional_proc = lambda { raise 'This should not be called' } - subject.off_resume(&additional_proc) - subject.trigger_resumed - expect(callbacks.count).to eql(1) - end - end - end - after(:all) do sleep 1 # let realtime library shut down any open clients end From c328c6c0571ec9379ee8a9a25ada6991a5068887 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Mon, 24 Jun 2024 17:30:38 +0530 Subject: [PATCH 4/6] Fixed impl for creating presence message using id --- lib/ably/realtime/presence.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/ably/realtime/presence.rb b/lib/ably/realtime/presence.rb index cdaba2efe..5d66b7e99 100644 --- a/lib/ably/realtime/presence.rb +++ b/lib/ably/realtime/presence.rb @@ -347,10 +347,7 @@ def sync_complete? private # @return [Ably::Models::PresenceMessage] presence message is returned allowing callbacks to be added def send_presence_protocol_message(presence_action, client_id, data, id = nil) - presence_message = create_presence_message(presence_action, client_id, data) - unless id.nil? - presence_message.id = id - end + presence_message = create_presence_message(presence_action, client_id, data, id) unless presence_message.client_id raise Ably::Exceptions::Standard.new('Unable to enter create presence message without a client_id', 400, Ably::Exceptions::Codes::UNABLE_TO_ENTER_PRESENCE_CHANNEL_NO_CLIENTID) end @@ -366,12 +363,13 @@ def send_presence_protocol_message(presence_action, client_id, data, id = nil) presence_message end - def create_presence_message(action, client_id, data) + def create_presence_message(action, client_id, data, id = nil) model = { action: Ably::Models::PresenceMessage.ACTION(action).to_i, clientId: client_id, - data: data + data: data, } + model[:id] = id unless id.nil? Ably::Models::PresenceMessage.new(model, logger: logger).tap do |presence_message| presence_message.encode(client.encoders, channel.options) do |encode_error, error_message| From e77e6baac6c5c26407f327ace845ca21370a1a9b Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Mon, 24 Jun 2024 17:31:10 +0530 Subject: [PATCH 5/6] Added missing spec annotations for presence_manager --- lib/ably/realtime/presence/presence_manager.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ably/realtime/presence/presence_manager.rb b/lib/ably/realtime/presence/presence_manager.rb index f5d5ca01a..75cc60b61 100644 --- a/lib/ably/realtime/presence/presence_manager.rb +++ b/lib/ably/realtime/presence/presence_manager.rb @@ -21,6 +21,7 @@ def initialize(presence) # @api private def on_attach(has_presence_flag) + # RTP1 if has_presence_flag # Expect SYNC ProtocolMessages from the server with a list of current members on this channel presence.members.change_state :sync_starting @@ -30,7 +31,7 @@ def on_attach(has_presence_flag) logger.debug { "#{self.class.name}: Emitting leave events for all members as a SYNC is not expected and thus there are no members on the channel" } presence.members.change_state :sync_none end - presence.members.send(:enter_local_members) + presence.members.send(:enter_local_members) # RTP17f end # Process presence messages from SYNC messages. Sync can be server-initiated or triggered following ATTACH From 446a16fabb036ff135b765f0bcce5a88bf09b11e Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Tue, 25 Jun 2024 17:36:58 +0530 Subject: [PATCH 6/6] Marked enter_local_members public instead of private --- lib/ably/realtime/presence/members_map.rb | 46 +++++++++---------- .../realtime/presence/presence_manager.rb | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/ably/realtime/presence/members_map.rb b/lib/ably/realtime/presence/members_map.rb index 49b006f6f..5d3c46c29 100644 --- a/lib/ably/realtime/presence/members_map.rb +++ b/lib/ably/realtime/presence/members_map.rb @@ -152,6 +152,29 @@ def local_members @local_members end + def enter_local_members + local_members.values.each do |member| + local_client_id = member.client_id || client.auth.client_id + logger.debug { "#{self.class.name}: Manually re-entering local presence member, client ID: #{local_client_id} with data: #{member.data}" } + presence.enter_client_with_id(member.id, local_client_id, member.data).tap do |deferrable| + deferrable.errback do |error| + presence_message_client_id = member.client_id || client.auth.client_id + re_enter_error = Ably::Models::ErrorInfo.new( + message: "unable to automatically re-enter presence channel for client_id '#{presence_message_client_id}'. Source error code #{error.code} and message '#{error.message}'", + code: Ably::Exceptions::Codes::UNABLE_TO_AUTOMATICALLY_REENTER_PRESENCE_CHANNEL + ) + channel.emit :update, Ably::Models::ChannelStateChange.new( + current: channel.state, + previous: channel.state, + event: Ably::Realtime::Channel::EVENT(:update), + reason: re_enter_error, + resumed: true + ) + end + end + end + end + private attr_reader :sync_session_id @@ -226,29 +249,6 @@ def setup_event_handlers end end - def enter_local_members - local_members.values.each do |member| - local_client_id = member.client_id || client.auth.client_id - logger.debug { "#{self.class.name}: Manually re-entering local presence member, client ID: #{local_client_id} with data: #{member.data}" } - presence.enter_client_with_id(member.id, local_client_id, member.data).tap do |deferrable| - deferrable.errback do |error| - presence_message_client_id = member.client_id || client.auth.client_id - re_enter_error = Ably::Models::ErrorInfo.new( - message: "unable to automatically re-enter presence channel for client_id '#{presence_message_client_id}'. Source error code #{error.code} and message '#{error.message}'", - code: Ably::Exceptions::Codes::UNABLE_TO_AUTOMATICALLY_REENTER_PRESENCE_CHANNEL - ) - channel.emit :update, Ably::Models::ChannelStateChange.new( - current: channel.state, - previous: channel.state, - event: Ably::Realtime::Channel::EVENT(:update), - reason: re_enter_error, - resumed: true - ) - end - end - end - end - def update_members_and_emit_events(presence_message) return unless ensure_presence_message_is_valid(presence_message) diff --git a/lib/ably/realtime/presence/presence_manager.rb b/lib/ably/realtime/presence/presence_manager.rb index 75cc60b61..3a32a5e0e 100644 --- a/lib/ably/realtime/presence/presence_manager.rb +++ b/lib/ably/realtime/presence/presence_manager.rb @@ -31,7 +31,7 @@ def on_attach(has_presence_flag) logger.debug { "#{self.class.name}: Emitting leave events for all members as a SYNC is not expected and thus there are no members on the channel" } presence.members.change_state :sync_none end - presence.members.send(:enter_local_members) # RTP17f + presence.members.enter_local_members # RTP17f end # Process presence messages from SYNC messages. Sync can be server-initiated or triggered following ATTACH