blob: 8b1525f0dded4c359722f656299d1d99ba64323b [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
module Qpid::Proton
# The base for both Sender and Receiver, providing common functionality
# between both ends.
#
# A Link has a single parent Qpid::Proton::Session instance.
#
class Link < Endpoint
# @private
PROTON_METHOD_PREFIX = "pn_link"
# @private
include Util::Wrapper
# The sender will send all deliveries initially unsettled.
SND_UNSETTLED = Cproton::PN_SND_UNSETTLED
# The sender will send all deliveries settled to the receiver.
SND_SETTLED = Cproton::PN_SND_SETTLED
# The sender may send a mixture of settled and unsettled deliveries.
SND_MIXED = Cproton::PN_SND_MIXED
# The receiver will settle deliveries regardless of what the sender does.
RCV_FIRST = Cproton::PN_RCV_FIRST
# The receiver will only settle deliveries after the sender settles.
RCV_SECOND = Cproton::PN_RCV_SECOND
# @!attribute [r] state
#
# Returns the endpoint state flags.
#
proton_caller :state
# @deprecated Use {Sender#open} or {Receiver#open}
proton_caller :open
# Close the local end of the link. The remote end may or may not be closed.
# @param error [Condition] Optional error condition to send with the close.
def close(error=nil)
Condition.assign(_local_condition, error)
Cproton.pn_link_close(@impl)
end
# @!method detach
#
# Detaches the link.
proton_caller :detach
# Advance the current delivery to the next on the link.
#
# For sending links, this operation is used to finish sending message data
# for the current outgoing delivery and move on to the next outgoing
# delivery (if any).
#
# For receiving links, this operatoin is used to finish accessing message
# data from the current incoming delivery and move on to the next incoming
# delivery (if any).
#
# @return [Boolean] True if the current delivery was changed.
#
# @see #current
#
proton_caller :advance
proton_caller :unsettled
# @!attribute [r] credit
#
# Returns the credit balance for a link.
#
# Links use a credit based flow control scheme. Every receiver maintains a
# credit balance that corresponds to the number of deliveries that the
# receiver can accept at any given moment.
#
# As more capacity becomes available at the receiver, it adds credit to this
# balance and communicates the new balance to the sender. Whenever a
# delivery is sent/received, the credit balance maintained by the link is
# decremented by one.
#
# Once the credit balance at the sender reaches zero, the sender must pause
# sending until more credit is obtained from the receiver.
#
# NOte that a sending link may still be used to send deliveries eve if
# credit reaches zero. However those deliveries will end up being buffer by
# the link until enough credit is obtained from the receiver to send them
# over the wire. In this case the balance reported will go negative.
#
# @return [Integer] The credit balance.
#
# @see #flow
#
proton_caller :credit
# @!attribute [r] remote_credit
#
# Returns the remote view of the credit.
#
# The remote view of the credit for a link differs from the local view of
# credit for a link by the number of queued deliveries. In other words,
# remote credit is defined as credit - queued.
#
# @see #queued
# @see #credit
#
# @return [Integer] The remove view of the credit.
#
proton_caller :remote_credit
# @!attribute [r] available
#
# Returns the available deliveries hint for a link.
#
# The available count for a link provides a hint as to the number of
# deliveries that might be able to be sent if sufficient credit were issued
# by the receiving link endpoint.
#
# @return [Integer] The available deliveries hint.
#
# @see Sender#offered
#
proton_caller :available
# @!attribute [r] queued
#
# Returns the number of queued deliveries for a link.
#
# Links may queue deliveries for a number of reasons. For example, there may
# be insufficient credit to send them to the receiver, or they simply may
# not have yet had a chance to be written to the wire.
#
# @return [Integer] The number of queued deliveries.
#
# @see #credit
#
proton_caller :queued
# @!attribute [r] name
#
# Returns the name of the link.
#
# @return [String] The name.
#
proton_caller :name
# @!attribute [r] sender?
#
# Returns if the link is a sender.
#
# @return [Boolean] True if the link is a sender.
#
proton_is :sender
# @!attribute [r] receiver?
#
# Returns if the link is a receiver.
#
# @return [Boolean] True if the link is a receiver.
#
proton_is :receiver
# @private
proton_get :attachments
# Drains excess credit.
#
# When a link is in drain mode, the sender must use all excess credit
# immediately and release any excess credit back to the receiver if there
# are no deliveries available to send.
#
# When invoked on a Sender that is in drain mode, this operation will
# release all excess credit back to the receiver and return the number of
# credits released back to the sender. If the link is not in drain mode,
# this operation is a noop.
#
# When invoked on a Receiver, this operation will return and reset the
# number of credits the sender has released back to it.
#
# @return [Integer] The number of credits drained.
#
proton_caller :drained
# @private
def self.wrap(impl)
return unless impl
return fetch_instance(impl, :pn_link_attachments) ||
(Cproton.pn_link_is_sender(impl) ? Sender : Receiver).new(impl)
end
# @private
def initialize(impl)
@impl = impl
self.class.store_instance(self, :pn_link_attachments)
end
# Returns additional error information.
#
# Whenever a link operation fails (i.e., returns an error code) additional
# error details can be obtained from this method. Ther error object that is
# returned may also be used to clear the error condition.
#
# @return [Error] The error.
#
def error
Cproton.pn_link_error(@impl)
end
# @deprecated use {Session#each_link, Connection#each_link}
def next(state_mask)
deprecated __method__, "Session#each_link, Connection#each_link"
return Link.wrap(Cproton.pn_link_next(@impl, state_mask))
end
# Returns the locally defined source terminus.
#
# @return [Terminus] The terminus
def source
Terminus.new(Cproton.pn_link_source(@impl))
end
# Returns the locally defined target terminus.
#
# @return [Terminus] The terminus.
#
def target
Terminus.new(Cproton.pn_link_target(@impl))
end
# Returns a representation of the remotely defined source terminus.
#
# @return [Terminus] The terminus.
#
def remote_source
Terminus.new(Cproton.pn_link_remote_source(@impl))
end
# Returns a representation of the remotely defined target terminus.
#
# @return [Terminus] The terminus.
#
def remote_target
Terminus.new(Cproton.pn_link_remote_target(@impl))
end
# Returns the parent session.
#
# @return [Session] The session.
#
def session
Session.wrap(Cproton.pn_link_session(@impl))
end
# Returns the parent connection.
#
# @return [Connection] The connection.
#
def connection
self.session.connection
end
# @deprecated use {Sender#send}
def delivery(tag)
deprecated __method__, "Sender#send"
Delivery.new(Cproton.pn_delivery(@impl, tag))
end
# Returns the current delivery.
#
# Each link maintains a sequence of deliveries in the order they were
# created, along with a reference to the *current* delivery. All send and
# receive operations on a link take place on the *current* delivery. If a
# link has no current delivery, the current delivery is automatically
# pointed to the *next* delivery created on the link.
#
# Once initialized, the current delivery remains the same until it is
# changed by advancing, or until it is settled.
#
# @see #next
# @see Delivery#settle
#
# @return [Delivery] The current delivery.
#
def current
Delivery.wrap(Cproton.pn_link_current(@impl))
end
# Sets the local sender settle mode.
#
# @param mode [Integer] The settle mode.
#
# @see #SND_UNSETTLED
# @see #SND_SETTLED
# @see #SND_MIXED
#
def snd_settle_mode=(mode)
Cproton.pn_link_set_snd_settle_mode(@impl, mode)
end
# Returns the local sender settle mode.
#
# @return [Integer] The local sender settle mode.
#
# @see #snd_settle_mode
#
def snd_settle_mode
Cproton.pn_link_snd_settle_mode(@impl)
end
# Sets the local receiver settle mode.
#
# @param mode [Integer] The settle mode.
#
# @see #RCV_FIRST
# @see #RCV_SECOND
#
def rcv_settle_mode=(mode)
Cproton.pn_link_set_rcv_settle_mode(@impl, mode)
end
# Returns the local receiver settle mode.
#
# @return [Integer] The local receiver settle mode.
#
def rcv_settle_mode
Cproton.pn_link_rcv_settle_mode(@impl)
end
# @private
def _local_condition
Cproton.pn_link_condition(@impl)
end
# @private
def _remote_condition
Cproton.pn_link_remote_condition(@impl)
end
def ==(other)
other.respond_to?(:impl) &&
(Cproton.pni_address_of(other.impl) == Cproton.pni_address_of(@impl))
end
end
end