diff --git a/src/chain.rs b/src/chain.rs index 568c2a6..f391ab2 100644 --- a/src/chain.rs +++ b/src/chain.rs @@ -14,6 +14,7 @@ use colored::*; use dialoguer::{FuzzySelect, Input}; use serde::{Deserialize, Serialize}; use std::fmt::{Debug, Display}; +use std::sync::Arc; pub const DEFAULT_KEY_NAME: &str = "default"; @@ -28,13 +29,30 @@ pub struct ChainDefinition { pub key_name: String, } +#[derive(Clone)] pub struct ChainInstance { pub definition: ChainDefinition, - pub provider: Box>, + pub provider: Arc>, pub rpc_url: String, pub key: Key, } +impl ChainInstance { + pub fn new(definition: ChainDefinition, provider: Box>, rpc_url: String, key: Key) -> Self { + Self { + definition, + provider: Arc::from(provider), + rpc_url, + key, + } + } + + pub fn with_key(mut self, key: Key) -> Self { + self.key = key; + self + } +} + pub struct Rpc { pub rpc_url: String, pub provider: Box>, diff --git a/src/config.rs b/src/config.rs index 9f3c2fa..b2d2c46 100644 --- a/src/config.rs +++ b/src/config.rs @@ -43,7 +43,7 @@ impl Chainz { }) } - pub async fn get_chain(&mut self, name_or_id: &str) -> Result<&ChainInstance> { + pub async fn get_chain(&mut self, name_or_id: &str) -> Result { let definition = self.config.get_chain(name_or_id)?; let name = definition.name.clone(); @@ -51,19 +51,19 @@ impl Chainz { let instance = self.instantiate_chain(&definition).await?; self.active_chains.insert(name.clone(), instance); } - Ok(&self.active_chains[&name]) + Ok(self.active_chains.get(&name).unwrap().clone()) } async fn instantiate_chain(&self, def: &ChainDefinition) -> Result { let rpc = def.get_rpc(&self.config.globals).await?; - let key = self.get_key(&def.key_name.clone())?; + let key = self.get_key(&def.key_name)?; - Ok(ChainInstance { - definition: def.clone(), - provider: rpc.provider, - rpc_url: rpc.rpc_url, + Ok(ChainInstance::new( + def.clone(), + rpc.provider, + rpc.rpc_url, key, - }) + )) } // Key management methods diff --git a/src/main.rs b/src/main.rs index 537537b..b1c8467 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,10 +8,12 @@ pub mod config; pub mod init; pub mod key; pub mod opt; +pub mod util; pub mod variables; use config::Chainz; use opt::Opt; +use util::Pipe; use variables::ChainVariables; #[tokio::main] @@ -48,10 +50,19 @@ async fn main() -> Result<()> { name_or_id, print, export, + key, } => { - let chain = chainz.get_chain(&name_or_id).await?; + let chain = chainz + .get_chain(&name_or_id) + .await? + .pipe(|chain| -> Result<_> { + Ok(match key { + Some(key_name) => chain.with_key(chainz.get_key(&key_name)?), + None => chain, + }) + })?; eprintln!("{}", chain); - let variables = ChainVariables::new(chain)?; + let variables = ChainVariables::new(&chain)?; if export { print!("{}", variables.as_exports()); } else { @@ -64,12 +75,21 @@ async fn main() -> Result<()> { opt::Command::Exec { name_or_id, command, + key, } => { if command.is_empty() { anyhow::bail!("No command specified"); } - let chain = chainz.get_chain(&name_or_id).await?; - let variables = ChainVariables::new(chain)?; + let chain = chainz + .get_chain(&name_or_id) + .await? + .pipe(|chain| -> Result<_> { + Ok(match key { + Some(key_name) => chain.with_key(chainz.get_key(&key_name)?), + None => chain, + }) + })?; + let variables = ChainVariables::new(&chain)?; let expanded_command = variables.expand(command); let status = ProcessCommand::new(&expanded_command[0]) diff --git a/src/opt.rs b/src/opt.rs index b986dec..89aad35 100644 --- a/src/opt.rs +++ b/src/opt.rs @@ -44,6 +44,7 @@ pub enum Command { /// Flags: /// -p, --print : Print variables to stdout instead of writing to .env /// -e, --export : Include 'export' prefix in output + /// -k, --key : Override the key to use for this command /// /// Example: chainz use ethereum --print Use { @@ -55,6 +56,9 @@ pub enum Command { /// Include 'export' prefix in output #[structopt(short, long)] export: bool, + /// Override the key to use for this command + #[structopt(short, long)] + key: Option, }, /// List all configured chains @@ -84,6 +88,9 @@ pub enum Command { /// Command to execute (after --) #[structopt(last = true)] command: Vec, + /// Override the key to use for this command + #[structopt(short, long)] + key: Option, }, /// Manage private keys diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..43ffdec --- /dev/null +++ b/src/util.rs @@ -0,0 +1,10 @@ +pub trait Pipe: Sized { + fn pipe(self, f: F) -> B + where + F: FnOnce(Self) -> B, + { + f(self) + } +} + +impl Pipe for T {} \ No newline at end of file