Skip to main content

tor_proto/circuit/reactor/
macros.rs

1//! Helper macros for the circuit reactors.
2
3derive_deftly::define_derive_deftly! {
4    /// Helper for deriving the boilerplate `run()` function of a circuit reactor.
5    ///
6    ///
7    /// ### Custom attributes
8    ///
9    ///  * **`#[deftly(reactor_name = "...")]`** (toplevel):
10    ///    The name of the reactor, for logging purposes.
11    ///    Must be a literal string.
12    ///
13    ///  * **`#[deftly(run_inner_fn = "FUNCTION")]`** (toplevel):
14    ///    The function to run from `run()`, possibly in a loop.
15    ///    `FUNCTION` is a function with the signature
16    ///    `async fn run_once(&mut Self) -> Result<(), ReactorError>`
17    ///
18    ///  * **`#[deftly(only_run_once)]`** (toplevel):
19    ///    Whether the `run()` function should only run `run_inner_fn` once
20    export CircuitReactor expect items:
21
22    impl<$tgens> $ttype where
23        $twheres
24    {
25        /// Launch the reactor, and run until the circuit closes or we
26        /// encounter an error.
27        ///
28        /// Once this method returns, the circuit is dead and cannot be
29        /// used again.
30        pub(crate) async fn run(mut self) -> $crate::Result<()> {
31            let unique_id = self.unique_id;
32
33            tracing::debug!(
34                circ_id = %unique_id,
35                "Running {}", ${tmeta(reactor_name) as str}
36            );
37
38            let result: $crate::Result<()> = loop {
39
40                match ${tmeta(run_inner_fn) as expr}(&mut self).await {
41
42                    Ok(()) => {
43                        ${if tmeta(only_run_once) {
44                            break Ok(());
45                        }}
46                    },
47                    Err(ReactorError::Shutdown) => break Ok(()),
48                    Err(ReactorError::Err(e)) => break Err(e),
49                }
50            };
51
52            // Log that the reactor stopped, possibly with the associated error as a report.
53            // May log at a higher level depending on the error kind.
54            let msg = format!("{} shut down", ${tmeta(reactor_name) as str});
55            match &result {
56                Ok(()) => tracing::trace!(circ_id = %unique_id, "{msg}"),
57                Err(e) => tor_error::debug_report!(e, circ_id = %unique_id, "{msg}"),
58            }
59
60            result
61        }
62    }
63}
64
65pub(crate) use derive_deftly_template_CircuitReactor;