1use crate::{Cli, Commands};
2use eyre::{eyre, Result};
3use reth_cli::chainspec::ChainSpecParser;
4use reth_cli_commands::launcher::Launcher;
5use reth_cli_runner::CliRunner;
6use reth_node_metrics::recorder::install_prometheus_recorder;
7use reth_optimism_chainspec::OpChainSpec;
8use reth_optimism_consensus::OpBeaconConsensus;
9use reth_optimism_node::{OpExecutorProvider, OpNode};
10use reth_tracing::{FileWorkerGuard, Layers};
11use std::{fmt, sync::Arc};
12use tracing::info;
13
14#[derive(Debug)]
16pub struct CliApp<Spec: ChainSpecParser, Ext: clap::Args + fmt::Debug> {
17 cli: Cli<Spec, Ext>,
18 runner: Option<CliRunner>,
19 layers: Option<Layers>,
20 guard: Option<FileWorkerGuard>,
21}
22
23impl<C, Ext> CliApp<C, Ext>
24where
25 C: ChainSpecParser<ChainSpec = OpChainSpec>,
26 Ext: clap::Args + fmt::Debug,
27{
28 pub(crate) fn new(cli: Cli<C, Ext>) -> Self {
29 Self { cli, runner: None, layers: Some(Layers::new()), guard: None }
30 }
31
32 pub fn set_runner(&mut self, runner: CliRunner) {
36 self.runner = Some(runner);
37 }
38
39 pub fn access_tracing_layers(&mut self) -> Result<&mut Layers> {
44 self.layers.as_mut().ok_or_else(|| eyre!("Tracing already initialized"))
45 }
46
47 pub fn run(mut self, launcher: impl Launcher<C, Ext>) -> Result<()> {
52 let runner = match self.runner.take() {
53 Some(runner) => runner,
54 None => CliRunner::try_default_runtime()?,
55 };
56
57 if let Some(chain_spec) = self.cli.command.chain_spec() {
60 self.cli.logs.log_file_directory =
61 self.cli.logs.log_file_directory.join(chain_spec.chain.to_string());
62 }
63
64 self.init_tracing()?;
65 let _ = install_prometheus_recorder();
67
68 let components = |spec: Arc<OpChainSpec>| {
69 (OpExecutorProvider::optimism(spec.clone()), OpBeaconConsensus::new(spec))
70 };
71
72 match self.cli.command {
73 Commands::Node(command) => {
74 runner.run_command_until_exit(|ctx| command.execute(ctx, launcher))
75 }
76 Commands::Init(command) => {
77 runner.run_blocking_until_ctrl_c(command.execute::<OpNode>())
78 }
79 Commands::InitState(command) => {
80 runner.run_blocking_until_ctrl_c(command.execute::<OpNode>())
81 }
82 Commands::ImportOp(command) => {
83 runner.run_blocking_until_ctrl_c(command.execute::<OpNode>())
84 }
85 Commands::ImportReceiptsOp(command) => {
86 runner.run_blocking_until_ctrl_c(command.execute::<OpNode>())
87 }
88 Commands::DumpGenesis(command) => runner.run_blocking_until_ctrl_c(command.execute()),
89 Commands::Db(command) => runner.run_blocking_until_ctrl_c(command.execute::<OpNode>()),
90 Commands::Stage(command) => {
91 runner.run_command_until_exit(|ctx| command.execute::<OpNode, _>(ctx, components))
92 }
93 Commands::P2P(command) => runner.run_until_ctrl_c(command.execute::<OpNode>()),
94 Commands::Config(command) => runner.run_until_ctrl_c(command.execute()),
95 Commands::Recover(command) => {
96 runner.run_command_until_exit(|ctx| command.execute::<OpNode>(ctx))
97 }
98 Commands::Prune(command) => runner.run_until_ctrl_c(command.execute::<OpNode>()),
99 #[cfg(feature = "dev")]
100 Commands::TestVectors(command) => runner.run_until_ctrl_c(command.execute()),
101 Commands::ReExecute(command) => {
102 runner.run_until_ctrl_c(command.execute::<OpNode>(components))
103 }
104 }
105 }
106
107 pub fn init_tracing(&mut self) -> Result<()> {
111 if self.guard.is_none() {
112 let layers = self.layers.take().unwrap_or_default();
113 self.guard = self.cli.logs.init_tracing_with_layers(layers)?;
114 info!(target: "reth::cli", "Initialized tracing, debug log directory: {}", self.cli.logs.log_file_directory);
115 }
116 Ok(())
117 }
118}