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_uniq_id = %unique_id,
35                backward_circ_id = %self.circ_id,
36                "Running {}", ${tmeta(reactor_name) as str}
37            );
38
39            let result: $crate::Result<()> = loop {
40
41                match ${tmeta(run_inner_fn) as expr}(&mut self).await {
42
43                    Ok(()) => {
44                        ${if tmeta(only_run_once) {
45                            break Ok(());
46                        }}
47                    },
48                    Err(ReactorError::Shutdown) => break Ok(()),
49                    Err(ReactorError::Err(e)) => break Err(e),
50                }
51            };
52
53            // Log that the reactor stopped, possibly with the associated error as a report.
54            // May log at a higher level depending on the error kind.
55            let msg = format!("{} shut down", ${tmeta(reactor_name) as str});
56            match &result {
57                Ok(()) => tracing::trace!(
58                    circ_uniq_id = %unique_id,
59                    backward_circ_id = %self.circ_id,
60                    "{msg}"
61                ),
62                Err(e) => tor_error::debug_report!(
63                    e,
64                    circ_uniq_id = %unique_id,
65                    backward_circ_id = %self.circ_id,
66                    "{msg}"
67                ),
68            }
69
70            result
71        }
72    }
73}
74
75pub(crate) use derive_deftly_template_CircuitReactor;