Skip to content

Commit

Permalink
Merge branch 'feature/integration-protocol-2' into feature/protocol-2…
Browse files Browse the repository at this point in the history
…-tests

# Conflicts:
#	lib/ably/realtime/channel.rb
#	lib/ably/realtime/channel/channel_manager.rb
#	lib/ably/realtime/channel/channel_state_machine.rb
#	lib/ably/realtime/connection.rb
  • Loading branch information
sacOO7 committed Jul 5, 2024
2 parents 57f9d0b + 08877bf commit 2e71781
Show file tree
Hide file tree
Showing 15 changed files with 72 additions and 164 deletions.
30 changes: 19 additions & 11 deletions lib/ably/auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -414,13 +414,20 @@ def auth_header
#
# @return [Hash] headers
def extra_auth_headers
if client_id && using_basic_auth?
{ 'X-Ably-ClientId' => Base64.urlsafe_encode64(client_id) }
if client_id_for_request
{ 'X-Ably-ClientId' => Base64.urlsafe_encode64(client_id_for_request) }
else
{}
end
end

# ClientId that needs to be included with every rest/realtime request
# spec - RSA7e
# @return string
def client_id_for_request
options[:client_id] if options[:client_id] && using_basic_auth?
end

# Auth params used in URI endpoint for Realtime connections
# Will reauthorize implicitly if required and capable
#
Expand Down Expand Up @@ -482,15 +489,16 @@ def can_assume_client_id?(assumed_client_id)
#
# @api private
def configure_client_id(new_client_id)
# If new client ID from Ably is a wildcard, but preconfigured clientId is set, then keep the existing clientId
if has_client_id? && new_client_id == '*'
@client_id_validated = true
return
end

# If client_id is defined and not a wildcard, prevent it changing, this is not supported
if client_id && client_id != '*' && new_client_id != client_id
raise Ably::Exceptions::IncompatibleClientId.new("Client ID is immutable once configured for a client. Client ID cannot be changed to '#{new_client_id}'")
if has_client_id?
# If new client ID from Ably is a wildcard, but preconfigured clientId is set, then keep the existing clientId
if new_client_id == "*"
@client_id_validated = true
return
end
# If client_id is defined and not a wildcard, prevent it changing, this is not supported
if new_client_id != client_id
raise Ably::Exceptions::IncompatibleClientId.new("Client ID is immutable once configured for a client. Client ID cannot be changed to '#{new_client_id}'")
end
end
@client_id_validated = true
@client_id = new_client_id
Expand Down
4 changes: 4 additions & 0 deletions lib/ably/realtime/auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ def auth_header_sync
auth_sync.auth_header
end

def client_id_for_request_sync
auth_sync.client_id_for_request
end

# Auth params used in URI endpoint for Realtime connections
# Will reauthorize implicitly if required and capable
#
Expand Down
2 changes: 1 addition & 1 deletion lib/ably/realtime/channel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ def __incoming_msgbus__
# @return [Ably::Models::ChannelOptions]
def set_options(channel_options)
@options = Ably::Models::ChannelOptions(channel_options)

# RTL4i
manager.request_reattach if (need_reattach? and connection.state?(:connected))
end
alias options= set_options
Expand Down
19 changes: 10 additions & 9 deletions lib/ably/realtime/channel/channel_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def initialize(channel, connection)
def attach
if can_transition_to?(:attached)
connect_if_connection_initialized
send_attach_protocol_message if connection.state?(:connected)
send_attach_protocol_message if connection.state?(:connected) # RTL4i
end
end

Expand Down Expand Up @@ -49,8 +49,7 @@ def log_channel_error(error)
end

# Request channel to be reattached by sending an attach protocol message
# @param reason
# @option options [Ably::Models::ErrorInfo] :reason
# @param [Ably::Models::ErrorInfo] reason
def request_reattach(reason = nil)
channel.set_channel_error_reason(reason) if reason
channel.transition_state_machine! :attaching, reason: reason unless channel.attaching?
Expand Down Expand Up @@ -168,6 +167,12 @@ def start_attach_from_suspended_timer
end
end

# RTL13c
def notify_state_change
@pending_state_change_timer.cancel if @pending_state_change_timer
@pending_state_change_timer = nil
end

private
attr_reader :pending_state_change_timer

Expand Down Expand Up @@ -211,13 +216,13 @@ def send_attach_protocol_message

state_at_time_of_request = channel.state
attach_action = Ably::Models::ProtocolMessage::ACTION.Attach
# RTL4f
@pending_state_change_timer = EventMachine::Timer.new(realtime_request_timeout) do
if channel.state == state_at_time_of_request
error = Ably::Models::ErrorInfo.new(code: Ably::Exceptions::Codes::CHANNEL_OPERATION_FAILED_NO_RESPONSE_FROM_SERVER, message: "Channel #{attach_action} operation failed (timed out)")
channel.transition_state_machine :suspended, reason: error # return to suspended state if failed
end
end

# Shouldn't queue attach message as per RTL4i, so message is added top of the queue
# to be sent immediately while processing next message
connection.send_protocol_message_immediately(
Expand Down Expand Up @@ -255,15 +260,11 @@ def send_detach_protocol_message(previous_state)
channel: channel.name
)
end
resend_if_disconnected_and_connected.call

send_detach_message.call
end

def notify_state_change
@pending_state_change_timer.cancel if @pending_state_change_timer
@pending_state_change_timer = nil
end

def logger
connection.logger
end
Expand Down
2 changes: 1 addition & 1 deletion lib/ably/realtime/channel/channel_state_machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ChannelStateMachine
transition :from => :failed, :to => [:attaching, :initialized]

after_transition do |channel, transition|
channel.manager.send(:notify_state_change)
channel.manager.notify_state_change # RTL13c
channel.synchronize_state_with_statemachine
end

Expand Down
23 changes: 11 additions & 12 deletions lib/ably/realtime/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -431,28 +431,27 @@ def logger
# @api private
def send_protocol_message(protocol_message)
add_message_serial_if_ack_required_to(protocol_message) do
Ably::Models::ProtocolMessage.new(protocol_message, logger: logger).tap do |message|
add_message_to_outgoing_queue message
notify_message_dispatcher_of_new_message message
logger.debug { "Connection: Prot msg queued =>: #{message.action} #{message}" }
end
message = Ably::Models::ProtocolMessage.new(protocol_message, logger: logger)
add_message_to_outgoing_queue(message)
notify_message_dispatcher_of_new_message message
end
end

def send_protocol_message_immediately(protocol_message)
Ably::Models::ProtocolMessage.new(protocol_message, logger: logger).tap do |message|
add_message_to_outgoing_queue(message, true)
notify_message_dispatcher_of_new_message message
logger.debug { "Connection: Prot msg pushed at the top =>: #{message.action} #{message}" }
end
message = Ably::Models::ProtocolMessage.new(protocol_message, logger: logger)
add_message_to_outgoing_queue(message, true)
notify_message_dispatcher_of_new_message message
end

# @api private
def add_message_to_outgoing_queue(protocol_message, send_immediately = false)
if send_immediately
# Adding msg at the top of the queue to get processed immediately while connection is CONNECTED
__outgoing_message_queue__.prepend(protocol_message)
logger.debug { "Connection: protocol msg pushed at the top =>: #{message.action} #{message}" }
else
__outgoing_message_queue__ << protocol_message
logger.debug { "Connection: protocol msg queued =>: #{message.action} #{message}" }
end
end

Expand Down Expand Up @@ -481,8 +480,8 @@ def create_websocket_transport
else
'false'
end

url_params['clientId'] = client.auth.client_id if client.auth.has_client_id?
# RSA7e1
url_params['clientId'] = client.auth.client_id_for_request_sync if client.auth.client_id_for_request_sync
url_params.merge!(client.transport_params)

if !key.nil_or_empty? and connection_state_available?
Expand Down
8 changes: 3 additions & 5 deletions lib/ably/realtime/presence/members_map.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,11 @@ def local_members

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|
logger.debug { "#{self.class.name}: Manually re-entering local presence member, client ID: #{member.client_id} with data: #{member.data}" }
presence.enter_client_with_id(member.id, member.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}'",
message: "unable to automatically re-enter presence channel for client_id '#{member.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(
Expand Down
27 changes: 0 additions & 27 deletions lib/ably/realtime/push.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,6 @@ def initialize(client)
def admin
@admin ||= Admin.new(self)
end

# Activates the device for push notifications with FCM or APNS, obtaining a unique identifier from them.
# Subsequently registers the device with Ably and stores the deviceIdentityToken in local storage.
#
# @spec RSH2a
#
# @note This is unsupported in the Ruby library
#
def activate(*arg)
raise_unsupported
end

# Deactivates the device from receiving push notifications with Ably and FCM or APNS.
#
# @spec RSH2b
#
# @note This is unsupported in the Ruby library
#
def deactivate(*arg)
raise_unsupported
end

private

def raise_unsupported
raise Ably::Exceptions::PushNotificationsNotSupported, 'This device does not support receiving or subscribing to push notifications. All PushChannel methods are unavailable'
end
end
end
end
2 changes: 1 addition & 1 deletion lib/ably/rest/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ def send_request(method, path, params, options)
end
unless options[:send_auth_header] == false
request.headers[:authorization] = auth.auth_header

# RSA7e2
options[:headers].to_h.merge(auth.extra_auth_headers).map do |key, val|
request.headers[key] = val
end
Expand Down
19 changes: 0 additions & 19 deletions lib/ably/rest/push.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,6 @@ def initialize(client)
def admin
@admin ||= Admin.new(self)
end

# Activate this device for push notifications by registering with the push transport such as GCM/APNS
#
# @note This is unsupported in the Ruby library
def activate(*arg)
raise_unsupported
end

# Deactivate this device for push notifications by removing the registration with the push transport such as GCM/APNS
#
# @note This is unsupported in the Ruby library
def deactivate(*arg)
raise_unsupported
end

private
def raise_unsupported
raise Ably::Exceptions::PushNotificationsNotSupported, 'This device does not support receiving or subscribing to push notifications. All PushChannel methods are unavailable'
end
end
end
end
2 changes: 1 addition & 1 deletion lib/ably/rest/push/admin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def initialize(push)

# Publish a push message directly to a single recipient
#
# @param recipient [Hash] A recipient device, client_id or raw APNS/GCM target. Refer to push documentation
# @param recipient [Hash] A recipient device, client_id or raw APNS/FCM/web target. Refer to push documentation
# @param data [Hash] The notification payload data and fields. Refer to push documentation
#
# @return [void]
Expand Down
22 changes: 9 additions & 13 deletions spec/acceptance/realtime/channel_history_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -184,26 +184,22 @@ def ensure_message_history_direction_and_paging_is_correct(direction)
end

context 'when channel receives update event after an attachment' do
old_attach_serial = ""
new_attach_serial = "xxxx-xxxx-1"
before do
channel.on(:attached) do
channel.publish(event, message_after_attach) do
subsequent_serial = channel.properties.attach_serial.dup.tap { |serial| serial[-1] = '1' }
attached_message = Ably::Models::ProtocolMessage.new(action: 11, channel: channel_name, flags: 0, channel_serial: subsequent_serial)
client.connection.__incoming_protocol_msgbus__.publish :protocol_message, attached_message
end
old_attach_serial = channel.properties.attach_serial
attached_message = Ably::Models::ProtocolMessage.new(action: 11, channel: channel_name, flags: 0, channel_serial: new_attach_serial)
client.connection.__incoming_protocol_msgbus__.publish :protocol_message, attached_message
end
end

xit 'updates attach_serial' do
rest_channel.publish event, message_before_attach

it 'updates attach_serial' do
channel.on(:update) do
channel.history(until_attach: true) do |messages|
expect(messages.items.count).to eql(2)
stop_reactor
end
expect(channel.properties.attach_serial).not_to eq(old_attach_serial)
expect(channel.properties.attach_serial).to eq(new_attach_serial)
stop_reactor
end

channel.attach
end
end
Expand Down
27 changes: 0 additions & 27 deletions spec/acceptance/realtime/push_spec.rb

This file was deleted.

Loading

0 comments on commit 2e71781

Please sign in to comment.