Skip to main content

forest/daemon/
main.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use crate::cli_shared::cli::{CliOpts, HELP_MESSAGE};
5use crate::cli_shared::{
6    cli::{ConfigPath, check_for_unknown_keys},
7    logger,
8};
9use crate::utils::version::FOREST_VERSION_STRING;
10use anyhow::Context as _;
11use clap::Parser;
12use std::ffi::OsString;
13use std::time::Duration;
14use tracing::info;
15
16/// CLI structure generated when interacting with Forest binary
17#[derive(Parser)]
18#[command(name = env!("CARGO_PKG_NAME"), bin_name = "forest", author = env!("CARGO_PKG_AUTHORS"), version = FOREST_VERSION_STRING.as_str(), about = env!("CARGO_PKG_DESCRIPTION")
19)]
20#[command(help_template(HELP_MESSAGE))]
21pub struct Cli {
22    #[clap(flatten)]
23    pub opts: CliOpts,
24}
25
26pub fn main<ArgT>(args: impl IntoIterator<Item = ArgT>) -> anyhow::Result<()>
27where
28    ArgT: Into<OsString> + Clone,
29{
30    // Capture Cli inputs
31    let Cli { opts } = Cli::parse_from(args);
32
33    let (cfg, path) = opts.to_config().context("Error parsing config")?;
34
35    // Run forest as a daemon if no other subcommands are used. Otherwise, run the
36    // subcommand.
37
38    let background_tasks = logger::setup_logger(&opts);
39
40    if let Some(path) = &path {
41        match path {
42            ConfigPath::Env(path) => {
43                info!("FOREST_CONFIG_PATH loaded: {}", path.display())
44            }
45            ConfigPath::Project(path) => {
46                info!("Project config loaded: {}", path.display())
47            }
48            _ => (),
49        }
50        check_for_unknown_keys(path.to_path_buf(), &cfg);
51    } else {
52        info!("Using default {} config", cfg.chain());
53    }
54    if opts.dry_run {
55        return Ok(());
56    }
57
58    let rt = tokio::runtime::Builder::new_multi_thread()
59        .enable_all()
60        .build()?;
61
62    for task in background_tasks {
63        rt.spawn(task);
64    }
65
66    let ret = rt.block_on(super::start_interruptable(opts, cfg));
67    info!("Shutting down tokio...");
68    rt.shutdown_timeout(Duration::from_secs_f32(0.5));
69    info!("Forest finish shutdown");
70    ret
71}