hermes-cli-components 0.1.0

Implementation of an IBC Relayer in Rust, as a library
Documentation
use core::marker::PhantomData;
use std::path::PathBuf;

use cgp::prelude::*;
use hermes_error::traits::wrap::CanWrapError;
use hermes_logging_components::traits::has_logger::HasLogger;
use hermes_logging_components::traits::logger::CanLog;
use hermes_logging_components::types::level::LevelInfo;
use hermes_relayer_components::chain::traits::types::chain_id::HasChainId;
use hermes_runtime_components::traits::fs::file_path::HasFilePathType;
use hermes_runtime_components::traits::os::child_process::CanWaitChildProcess;
use hermes_runtime_components::traits::runtime::HasRuntime;
use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain;
use hermes_test_components::chain_driver::traits::chain_process::CanTakeChainProcess;
use hermes_test_components::chain_driver::traits::config::CanUpdateConfig;
use hermes_test_components::chain_driver::traits::types::chain::HasChain;

use crate::traits::bootstrap::CanLoadBootstrap;
use crate::traits::command::CommandRunner;
use crate::traits::config::config_path::HasConfigPath;
use crate::traits::config::load_config::CanLoadConfig;
use crate::traits::config::write_config::CanWriteConfig;
use crate::traits::output::CanProduceOutput;

pub struct RunBootstrapChainCommand;

impl<App, Args, Bootstrap, ChainDriver, Chain, Runtime> CommandRunner<App, Args>
    for RunBootstrapChainCommand
where
    App: HasLogger
        + CanProduceOutput<()>
        + CanLoadBootstrap<Args, Bootstrap = Bootstrap>
        + HasConfigPath
        + CanLoadConfig
        + CanWriteConfig
        + CanRaiseError<Bootstrap::Error>
        + CanRaiseError<Runtime::Error>
        + CanRaiseError<ChainDriver::Error>
        + CanWrapError<&'static str>,
    Bootstrap: CanBootstrapChain<ChainDriver = ChainDriver>,
    ChainDriver: HasChain<Chain = Chain>
        + HasRuntime<Runtime = Runtime>
        + CanTakeChainProcess
        + CanUpdateConfig<App::Config>,
    Chain: HasChainId,
    Runtime: CanWaitChildProcess + HasFilePathType<FilePath = PathBuf>,
    Args: Async + HasField<symbol!("chain_id"), Field = String>,
    App::Logger: CanLog<LevelInfo>,
{
    async fn run_command(app: &App, args: &Args) -> Result<App::Output, App::Error> {
        let logger = app.logger();
        let chain_id = args.get_field(PhantomData);

        let mut config = app.load_config().await?;
        let bootstrap = app.load_bootstrap(args).await?;

        let chain_driver = bootstrap
            .bootstrap_chain(chain_id)
            .await
            .map_err(App::raise_error)?;

        let chain = chain_driver.chain();

        logger
            .log(
                &format!(
                    "Bootstrapped a new chain with chain ID: {}",
                    chain.chain_id()
                ),
                &LevelInfo,
            )
            .await;

        let chain_config = chain_driver
            .update_config(&mut config)
            .map_err(App::raise_error)?;

        app.write_config(&config).await?;

        logger
            .log(
                &format!(
                    "Added the following chain config to the main config file:\n{}",
                    chain_config
                ),
                &LevelInfo,
            )
            .await;

        let m_chain_process = chain_driver.take_chain_process().await;

        if let Some(chain_process) = m_chain_process {
            logger.log(&format!("running chain {} running in the background. Press Ctrl+C to stop then chain...", chain.chain_id()), &LevelInfo).await;

            Runtime::wait_child_process(chain_process)
                .await
                .map_err(|e| {
                    App::wrap_error("chain process exited with error", App::raise_error(e))
                })?;

            logger
                .log("chain process exited with no error", &LevelInfo)
                .await;
        }

        Ok(app.produce_output(()))
    }
}