cargo_tangle/command/run/
tangle.rs

1use alloy_signer_local::PrivateKeySigner;
2use blueprint_crypto::tangle_pair_signer::TanglePairSigner;
3use blueprint_manager::config::{BlueprintManagerConfig, DEFAULT_DOCKER_HOST, SourceType};
4use blueprint_manager::executor::run_blueprint_manager;
5use blueprint_runner::config::BlueprintEnvironment;
6use color_eyre::eyre::{Result, eyre};
7use dialoguer::console::style;
8use indicatif::{ProgressBar, ProgressStyle};
9use sp_core::sr25519;
10use std::path::PathBuf;
11use std::time::Duration;
12use tokio::signal;
13use url::Url;
14
15#[derive(Clone)]
16pub struct RunOpts {
17    /// The HTTP RPC URL of the Tangle Network
18    pub http_rpc_url: String,
19    /// The WS RPC URL of the Tangle Network
20    pub ws_rpc_url: String,
21    /// The signer for Tangle operations
22    pub signer: Option<TanglePairSigner<sr25519::Pair>>,
23    /// The signer for EVM operations
24    pub signer_evm: Option<PrivateKeySigner>,
25    /// The blueprint ID to run
26    pub blueprint_id: Option<u64>,
27    /// The keystore path
28    pub keystore_path: Option<String>,
29    /// The data directory path
30    pub data_dir: Option<PathBuf>,
31    /// The Podman host to use for containerized blueprints
32    pub podman_host: Option<Url>,
33}
34
35/// Runs a blueprint using the blueprint manager
36///
37/// # Arguments
38///
39/// * `opts` - Options for running the blueprint
40///
41/// # Errors
42///
43/// Returns an error if:
44/// * Blueprint ID is not provided
45/// * Failed to create or configure the blueprint manager
46/// * Failed to run the blueprint
47#[allow(clippy::missing_panics_doc)]
48pub async fn run_blueprint(opts: RunOpts) -> Result<()> {
49    let blueprint_id = opts
50        .blueprint_id
51        .ok_or_else(|| eyre!("Blueprint ID is required"))?;
52
53    let mut gadget_config = BlueprintEnvironment::default();
54    gadget_config.http_rpc_endpoint = opts.http_rpc_url.clone();
55    gadget_config.ws_rpc_endpoint = opts.ws_rpc_url.clone();
56
57    if let Some(keystore_path) = opts.keystore_path {
58        gadget_config.keystore_uri = keystore_path;
59    }
60
61    gadget_config.keystore_uri = std::path::absolute(&gadget_config.keystore_uri)?
62        .display()
63        .to_string();
64
65    gadget_config.data_dir = opts.data_dir;
66
67    let blueprint_manager_config = BlueprintManagerConfig {
68        gadget_config: None,
69        keystore_uri: gadget_config.keystore_uri.clone(),
70        data_dir: gadget_config
71            .data_dir
72            .clone()
73            .unwrap_or_else(|| PathBuf::from("./data")),
74        verbose: 2,
75        pretty: true,
76        instance_id: Some(format!("Blueprint-{}", blueprint_id)),
77        test_mode: false,
78        preferred_source: SourceType::default(),
79        podman_host: opts.podman_host.unwrap_or(DEFAULT_DOCKER_HOST.clone()),
80    };
81
82    println!(
83        "{}",
84        style(format!(
85            "Starting blueprint manager for blueprint ID: {}",
86            blueprint_id
87        ))
88        .cyan()
89        .bold()
90    );
91
92    let shutdown_signal = async move {
93        let _ = signal::ctrl_c().await;
94        println!(
95            "{}",
96            style("Received shutdown signal, stopping blueprint manager")
97                .yellow()
98                .bold()
99        );
100    };
101
102    println!(
103        "{}",
104        style("Preparing Blueprint to run, this may take a few minutes...").cyan()
105    );
106
107    let pb = ProgressBar::new_spinner();
108    pb.set_style(
109        ProgressStyle::default_spinner()
110            .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ ")
111            .template("{spinner:.blue} {msg}")
112            .unwrap(),
113    );
114    pb.set_message("Initializing Blueprint");
115    pb.enable_steady_tick(Duration::from_millis(100));
116
117    let mut handle =
118        run_blueprint_manager(blueprint_manager_config, gadget_config, shutdown_signal).await?;
119
120    pb.finish_with_message("Blueprint initialized successfully!");
121
122    println!(
123        "{}",
124        style("Starting blueprint execution...").green().bold()
125    );
126    handle.start()?;
127
128    println!(
129        "{}",
130        style("Blueprint is running. Press Ctrl+C to stop.").cyan()
131    );
132    handle.await?;
133
134    println!("{}", style("Blueprint manager has stopped").green());
135    Ok(())
136}