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 b03bc7e
Show file tree
Hide file tree
Showing 15 changed files with 72 additions and 165 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
18 changes: 9 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 @@ -259,11 +264,6 @@ def send_detach_protocol_message(previous_state)
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
24 changes: 10 additions & 14 deletions spec/acceptance/realtime/channel_history_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -184,32 +184,28 @@ 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

context 'and two pages of messages' do
xit 'retrieves two pages of messages before channel was attached' do
it 'retrieves two pages of messages before channel was attached' do
10.times { rest_channel.publish event, message_before_attach }

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

This file was deleted.

Loading

0 comments on commit b03bc7e

Please sign in to comment.