Skip to main content

sentry_core/transport/
mod.rs

1use std::sync::Arc;
2use std::time::Duration;
3
4use crate::{ClientOptions, Envelope};
5
6mod options;
7
8pub use self::options::TransportOptions;
9
10/// The trait for transports.
11///
12/// A transport is responsible for sending events to Sentry.  Custom implementations
13/// can be created to use a different abstraction to send events.  This is for instance
14/// used for the test system.
15pub trait Transport: Send + Sync + 'static {
16    /// Sends an [`Envelope`].
17    ///
18    /// [`Envelope`]: struct.Envelope.html
19    fn send_envelope(&self, envelope: Envelope);
20
21    /// Flushes the transport queue if there is one.
22    ///
23    /// If the queue was successfully drained, the return value should be
24    /// `true` or `false` if events were left in it.
25    fn flush(&self, timeout: Duration) -> bool {
26        let _timeout = timeout;
27        true
28    }
29
30    /// Instructs the Transport to shut down.
31    fn shutdown(&self, timeout: Duration) -> bool {
32        self.flush(timeout)
33    }
34}
35
36/// A factory creating transport instances.
37///
38/// Because options are potentially reused between different clients the
39/// [`ClientOptions`] do not actually contain a transport but a factory object that
40/// can create transports instead.
41///
42/// This factory has two methods. Although both methods have default implementations, the default
43/// implementations call each other, so to avoid an infinitely recursive loop, types implementing
44/// this trait **must implement at least one of these methods**. We recommend that implementors
45/// implement only [`TransportFactory::create_transport_with_options`] because the other method,
46/// [`TransportFactory::create_transport`] only exists for backwards compatibility.
47///
48/// Both factory methods create a new transport wrapped in an [`Arc`]. Because transports can be
49/// wrapped in `Arc`s and those are clonable, `Arc<Transport>` is also a valid transport factory.
50/// This for instance lets you put a `Arc<TestTransport>` directly into the options.
51pub trait TransportFactory: Send + Sync {
52    /// Create a transport with the given `options`.
53    ///
54    /// Although a default implementation is provided for this trait method, we recommend that all
55    /// custom transport factories implement this method, as it is the way the SDK constructs the
56    /// transport. The default implementaton calls [`TransportFactory::create_transport`] as a
57    /// fallback.
58    fn create_transport_with_options(&self, options: TransportOptions) -> Arc<dyn Transport> {
59        #[expect(deprecated, reason = "need to call deprecated method for back-compat")]
60        self.create_transport(&options.into_client_options())
61    }
62
63    /// The legacy method for creating a transport.
64    ///
65    /// This method exists for backwards compatiblity with custom transport factories, which were
66    /// created before [`TransportFactory::create_transport_with_options`] was added, and thus only
67    /// implement this method.
68    ///
69    /// New custom transport factories **should not** implement this method, as it is not called
70    /// from the SDK. A sensible default implementation, which forwards to
71    /// [`TransportFactory::create_transport_with_options`] is provided.
72    #[deprecated = "use and implement `create_transport_with_options` instead"]
73    fn create_transport(&self, options: &ClientOptions) -> Arc<dyn Transport> {
74        TransportOptions::try_from_client_options(options).map_or_else(
75            || {
76                let no_op: Arc<dyn Transport> = Arc::new(NoOpTransport);
77                no_op
78            },
79            |options| self.create_transport_with_options(options),
80        )
81    }
82}
83
84/// A no-op transport.
85///
86/// This is returned by [`TransportFactory::create_transport`] when called without a `dsn` in the
87/// [`ClientOptions`], rendering the transport disabled.
88struct NoOpTransport;
89
90/// This implementor is **deprecated**, as the closure is used as the deprecated
91/// [`TransportFactory::create_transport`] method.
92///
93/// Use or create a [`TransportFactory`] which provides
94/// [`TransportFactory::create_transport_with_options`], instead.
95impl<F> TransportFactory for F
96where
97    F: Fn(&ClientOptions) -> Arc<dyn Transport> + Clone + Send + Sync + 'static,
98{
99    fn create_transport(&self, options: &ClientOptions) -> Arc<dyn Transport> {
100        (*self)(options)
101    }
102}
103
104impl<T: Transport> Transport for Arc<T> {
105    fn send_envelope(&self, envelope: Envelope) {
106        (**self).send_envelope(envelope)
107    }
108
109    fn shutdown(&self, timeout: Duration) -> bool {
110        (**self).shutdown(timeout)
111    }
112}
113
114impl<T: Transport> TransportFactory for Arc<T> {
115    fn create_transport_with_options(&self, _: TransportOptions) -> Arc<dyn Transport> {
116        self.clone()
117    }
118}
119
120impl Transport for NoOpTransport {
121    fn send_envelope(&self, envelope: Envelope) {
122        let _ = envelope;
123    }
124}