+/// [`OnionMessage`]s buffered to be sent.
+enum OnionMessageRecipient {
+ /// Messages for a node connected as a peer.
+ ConnectedPeer(VecDeque<OnionMessage>),
+
+ /// Messages for a node that is not yet connected, which are dropped after [`MAX_TIMER_TICKS`]
+ /// and tracked here.
+ PendingConnection(VecDeque<OnionMessage>, Option<Vec<SocketAddress>>, usize),
+}
+
+impl OnionMessageRecipient {
+ fn pending_connection(addresses: Vec<SocketAddress>) -> Self {
+ Self::PendingConnection(VecDeque::new(), Some(addresses), 0)
+ }
+
+ fn pending_messages(&self) -> &VecDeque<OnionMessage> {
+ match self {
+ OnionMessageRecipient::ConnectedPeer(pending_messages) => pending_messages,
+ OnionMessageRecipient::PendingConnection(pending_messages, _, _) => pending_messages,
+ }
+ }
+
+ fn enqueue_message(&mut self, message: OnionMessage) {
+ let pending_messages = match self {
+ OnionMessageRecipient::ConnectedPeer(pending_messages) => pending_messages,
+ OnionMessageRecipient::PendingConnection(pending_messages, _, _) => pending_messages,
+ };
+
+ pending_messages.push_back(message);
+ }
+
+ fn dequeue_message(&mut self) -> Option<OnionMessage> {
+ let pending_messages = match self {
+ OnionMessageRecipient::ConnectedPeer(pending_messages) => pending_messages,
+ OnionMessageRecipient::PendingConnection(pending_messages, _, _) => {
+ debug_assert!(false);
+ pending_messages
+ },
+ };
+
+ pending_messages.pop_front()
+ }
+
+ #[cfg(test)]
+ fn release_pending_messages(&mut self) -> VecDeque<OnionMessage> {
+ let pending_messages = match self {
+ OnionMessageRecipient::ConnectedPeer(pending_messages) => pending_messages,
+ OnionMessageRecipient::PendingConnection(pending_messages, _, _) => pending_messages,
+ };
+
+ core::mem::take(pending_messages)
+ }
+
+ fn mark_connected(&mut self) {
+ if let OnionMessageRecipient::PendingConnection(pending_messages, _, _) = self {
+ let mut new_pending_messages = VecDeque::new();
+ core::mem::swap(pending_messages, &mut new_pending_messages);
+ *self = OnionMessageRecipient::ConnectedPeer(new_pending_messages);
+ }
+ }
+
+ fn is_connected(&self) -> bool {
+ match self {
+ OnionMessageRecipient::ConnectedPeer(..) => true,
+ OnionMessageRecipient::PendingConnection(..) => false,
+ }
+ }
+}
+
+
+/// The `Responder` struct creates an appropriate [`ResponseInstruction`]
+/// for responding to a message.
+pub struct Responder {
+ /// The path along which a response can be sent.
+ reply_path: BlindedPath,
+ path_id: Option<[u8; 32]>
+}
+
+impl Responder {
+ /// Creates a new [`Responder`] instance with the provided reply path.
+ fn new(reply_path: BlindedPath, path_id: Option<[u8; 32]>) -> Self {
+ Responder {
+ reply_path,
+ path_id,
+ }
+ }
+
+ /// Creates the appropriate [`ResponseInstruction`] for a given response.
+ pub fn respond<T: OnionMessageContents>(self, response: T) -> ResponseInstruction<T> {
+ ResponseInstruction::WithoutReplyPath(OnionMessageResponse {
+ message: response,
+ reply_path: self.reply_path,
+ path_id: self.path_id,
+ })
+ }
+}
+
+/// This struct contains the information needed to reply to a received message.
+pub struct OnionMessageResponse<T: OnionMessageContents> {
+ message: T,
+ reply_path: BlindedPath,
+ path_id: Option<[u8; 32]>,
+}
+
+/// `ResponseInstruction` represents instructions for responding to received messages.
+pub enum ResponseInstruction<T: OnionMessageContents> {
+ /// Indicates that a response should be sent without including a reply path
+ /// for the recipient to respond back.
+ WithoutReplyPath(OnionMessageResponse<T>),
+ /// Indicates that there's no response to send back.
+ NoResponse,
+}
+
+/// An [`OnionMessage`] for [`OnionMessenger`] to send.
+///
+/// These are obtained when released from [`OnionMessenger`]'s handlers after which they are
+/// enqueued for sending.
+#[cfg(not(c_bindings))]
+pub struct PendingOnionMessage<T: OnionMessageContents> {
+ /// The message contents to send in an [`OnionMessage`].
+ pub contents: T,
+
+ /// The destination of the message.
+ pub destination: Destination,
+
+ /// A reply path to include in the [`OnionMessage`] for a response.
+ pub reply_path: Option<BlindedPath>,
+}
+
+#[cfg(c_bindings)]
+/// An [`OnionMessage`] for [`OnionMessenger`] to send.