Skip to main content

tor_proto/relay/
channel_provider.rs

1//! Module exposing the [`ChannelProvider`] trait.
2//!
3//! Relay circuit reactors use a [`ChannelProvider`] to open outgoing channels.
4
5use crate::Result;
6use crate::channel::Channel;
7use crate::circuit::UniqId;
8
9use async_trait::async_trait;
10use futures::channel::mpsc;
11
12use std::sync::Arc;
13
14use tor_linkspec::HasRelayIds;
15
16/// A channel result returned by a [`ChannelProvider`].
17pub type ChannelResult = Result<Arc<Channel>>;
18
19/// A sender for returning an outgoing relay channel
20/// requested via [`ChannelProvider::get_or_launch`].
21//
22// Note: this channel is unbounded, because the limit should be imposed
23// by the [`ChannelProvider`].
24pub struct OutboundChanSender(pub(crate) mpsc::UnboundedSender<ChannelResult>);
25
26impl OutboundChanSender {
27    /// Create a new [`OutboundChanSender`] from an [`mpsc`] sender.
28    ///
29    /// This should remain crate-private, as these senders
30    /// should only ever be created by the relay circuit reactor
31    /// to request a new outbound channel.
32    #[allow(dead_code)] // TODO(relay)
33    pub(crate) fn new(tx: mpsc::UnboundedSender<ChannelResult>) -> Self {
34        Self(tx)
35    }
36
37    /// Send the specified channel result to the requester.
38    ///
39    /// See [`ChannelProvider::get_or_launch`].
40    pub fn send(self, result: ChannelResult) {
41        // Don't care if the receiver goes away
42        let _ = self.0.unbounded_send(result);
43    }
44}
45
46/// An object that can fulfill outbound channel requests
47/// issued by the relay circuit reactor.
48///
49/// The implementor is responsible for imposing a limit on the
50/// number of outbound channels that can be opened on a given circuit.
51#[async_trait]
52pub trait ChannelProvider {
53    /// Type that explains how to build an outgoing channel.
54    type BuildSpec: HasRelayIds;
55
56    /// Get a channel corresponding to the identities of `target`, for the circuit reactor with the
57    /// specified `reactor_id` which should only be used for logging purposes.
58    ///
59    /// Returns the requested channel via the specified [`OutboundChanSender`].
60    fn get_or_launch(
61        self: Arc<Self>,
62        reactor_id: UniqId,
63        target: Self::BuildSpec,
64        tx: OutboundChanSender,
65    ) -> Result<()>;
66}
67
68/// A no-op channel provider to be used in testing.
69///
70/// Always returns an error.
71#[cfg(test)]
72#[derive(Copy, Clone, Debug, Default)]
73pub(crate) struct NoOpChannelProvider;
74
75#[cfg(test)]
76impl ChannelProvider for NoOpChannelProvider {
77    // We choose this because it's needed by the relay circuit reactor constructor.
78    type BuildSpec = tor_linkspec::OwnedChanTarget;
79
80    fn get_or_launch(
81        self: Arc<Self>,
82        _reactor_id: UniqId,
83        _target: Self::BuildSpec,
84        _tx: OutboundChanSender,
85    ) -> Result<()> {
86        Err(tor_error::internal!("NoOpChannelProvider cannot launch channels").into())
87    }
88}