From e1d90819e01b800cea6f9147ad41b34bdb6d0eb2 Mon Sep 17 00:00:00 2001 From: Hugo Trentesaux <hugo@trentesaux.fr> Date: Tue, 6 Jun 2023 15:10:12 +0200 Subject: [PATCH] WIP refac argument parsing --- src/commands/collective.rs | 23 +++----- src/commands/expire.rs | 25 ++------- src/commands/identity.rs | 17 ++---- src/commands/net_test.rs | 4 +- src/commands/oneshot.rs | 8 +-- src/commands/smith.rs | 34 +++++------- src/commands/transfer.rs | 4 +- src/conf.rs | 43 ++++++++------- src/data.rs | 30 ++++++++--- src/main.rs | 106 ++++++++++++++++++------------------- 10 files changed, 133 insertions(+), 161 deletions(-) diff --git a/src/commands/collective.rs b/src/commands/collective.rs index 724a2d0..d95d9df 100644 --- a/src/commands/collective.rs +++ b/src/commands/collective.rs @@ -1,30 +1,19 @@ -use crate::indexer::*; use crate::*; use anyhow::Result; use sp_core::{sr25519::Pair, H256}; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; -pub async fn technical_committee_members(client: Client, args: &Args) -> Result<()> { +pub async fn technical_committee_members(data: &Data) -> Result<()> { + let client = data.client(); + let indexer = data.indexer.clone(); + let parent_hash = client .storage() .fetch(&runtime::storage().system().parent_hash(), None) .await? .unwrap(); - let gql_client = reqwest::Client::builder() - .user_agent("gcli/0.1.0") - .build()?; - - let indexer = if args.no_indexer { - None - } else { - Some(Indexer { - gql_client, - gql_url: args.indexer.clone(), - }) - }; - for account_id in client .storage() .fetch( @@ -64,7 +53,7 @@ pub async fn technical_committee_members(client: Client, args: &Args) -> Result< // TODO: // * better formatting (format pubkeys to SS58 and add usernames) // * display proposals indices -pub async fn technical_committee_proposals(client: Client) -> Result<()> { +pub async fn technical_committee_proposals(client: &Client) -> Result<()> { let parent_hash = client .storage() .fetch(&runtime::storage().system().parent_hash(), None) @@ -92,7 +81,7 @@ pub async fn technical_committee_proposals(client: Client) -> Result<()> { pub async fn technical_committee_vote( pair: Pair, - client: Client, + client: &Client, proposal_hash: H256, proposal_index: u32, vote: bool, diff --git a/src/commands/expire.rs b/src/commands/expire.rs index 7cc9647..96004ed 100644 --- a/src/commands/expire.rs +++ b/src/commands/expire.rs @@ -1,19 +1,12 @@ -use crate::indexer::*; use crate::*; use anyhow::Result; use futures::join; use std::collections::BTreeMap; -pub async fn monitor_expirations( - client: Client, - blocks: u32, - sessions: u32, - args: &Args, -) -> Result<()> { - let gql_client = reqwest::Client::builder() - .user_agent("gcli/0.1.0") - .build()?; +pub async fn monitor_expirations(data: &Data, blocks: u32, sessions: u32) -> Result<()> { + let client = data.client(); + let indexer = data.indexer.clone(); let parent_hash = client .storage() @@ -36,17 +29,7 @@ pub async fn monitor_expirations( let end_block = current_block + blocks; let end_session = current_session + sessions; - let mut identity_cache = cache::IdentityCache::new( - client.clone(), - if args.no_indexer { - None - } else { - Some(Indexer { - gql_client, - gql_url: args.indexer.clone(), - }) - }, - ); + let mut identity_cache = cache::IdentityCache::new(client.clone(), indexer); // Rotate keys let mut must_rotate_keys_before_iter = client diff --git a/src/commands/identity.rs b/src/commands/identity.rs index 61e617a..b1e9d11 100644 --- a/src/commands/identity.rs +++ b/src/commands/identity.rs @@ -1,4 +1,3 @@ -use crate::indexer::*; use crate::*; use crate::commands::revocation::generate_revoc_doc; @@ -12,23 +11,13 @@ use std::str::FromStr; use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; pub async fn get_identity( - client: &Client, + data: &Data, mut account_id: Option<AccountId32>, mut identity_id: Option<u32>, mut username: Option<String>, - args: &Args, ) -> Result<()> { - // build indexer if not disabled - let indexer = if args.no_indexer { - None - } else { - Some(Indexer { - gql_client: reqwest::Client::builder() - .user_agent("gcli/0.1.0") - .build()?, - gql_url: args.indexer.clone(), - }) - }; + let client = data.client(); + let indexer = data.indexer.clone(); // fetch missing information match (&account_id, identity_id, &username) { diff --git a/src/commands/net_test.rs b/src/commands/net_test.rs index 9a2c73b..228469c 100644 --- a/src/commands/net_test.rs +++ b/src/commands/net_test.rs @@ -9,7 +9,7 @@ use subxt::{ pub async fn repart( pair: Pair, - client: Client, + client: &Client, target: u32, actual_repart: Option<u32>, ) -> Result<()> { @@ -48,7 +48,7 @@ pub async fn repart( Ok(()) } -pub async fn spam_roll(pair: Pair, client: Client, actual_repart: usize) -> Result<()> { +pub async fn spam_roll(pair: Pair, client: &Client, actual_repart: usize) -> Result<()> { let mut nonce = 0; let mut pairs = Vec::<(PairSigner<Runtime, Pair>, AccountId32)>::with_capacity(actual_repart); for i in 0..actual_repart { diff --git a/src/commands/oneshot.rs b/src/commands/oneshot.rs index c6d4fb9..15c53c3 100644 --- a/src/commands/oneshot.rs +++ b/src/commands/oneshot.rs @@ -6,7 +6,7 @@ use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; pub async fn create_oneshot_account( pair: Pair, - client: Client, + client: &Client, balance: u64, dest: AccountId32, ) -> Result<()> { @@ -26,7 +26,7 @@ pub async fn create_oneshot_account( pub async fn consume_oneshot_account( pair: Pair, - client: Client, + client: &Client, dest: AccountId32, dest_oneshot: bool, ) -> Result<()> { @@ -60,7 +60,7 @@ pub async fn consume_oneshot_account( pub async fn consume_oneshot_account_with_remaining( pair: Pair, - client: Client, + client: &Client, balance: u64, dest: AccountId32, dest_oneshot: bool, @@ -107,7 +107,7 @@ pub async fn consume_oneshot_account_with_remaining( Ok(()) } -pub async fn oneshot_account_balance(client: Client, account: AccountId32) -> Result<()> { +pub async fn oneshot_account_balance(client: &Client, account: AccountId32) -> Result<()> { log::info!( "{}", client diff --git a/src/commands/smith.rs b/src/commands/smith.rs index b45d49b..a5f7a76 100644 --- a/src/commands/smith.rs +++ b/src/commands/smith.rs @@ -1,4 +1,3 @@ -use crate::indexer::Indexer; use crate::*; use anyhow::{anyhow, Result}; @@ -18,7 +17,11 @@ pub async fn rotate_keys(client: &Client) -> Result<SessionKeys> { .map_err(|e| anyhow!("Session keys have wrong length: {:?}", e)) } -pub async fn set_session_keys(pair: Pair, client: Client, session_keys: SessionKeys) -> Result<()> { +pub async fn set_session_keys( + pair: Pair, + client: &Client, + session_keys: SessionKeys, +) -> Result<()> { client .tx() .sign_and_submit_then_watch( @@ -33,12 +36,12 @@ pub async fn set_session_keys(pair: Pair, client: Client, session_keys: SessionK Ok(()) } -pub async fn update_session_keys(pair: Pair, client: Client) -> Result<()> { +pub async fn update_session_keys(pair: Pair, client: &Client) -> Result<()> { let session_keys = rotate_keys(&client).await?; set_session_keys(pair, client, session_keys).await } -pub async fn go_online(pair: Pair, client: Client) -> Result<()> { +pub async fn go_online(pair: Pair, client: &Client) -> Result<()> { if client .storage() .fetch( @@ -65,7 +68,7 @@ pub async fn go_online(pair: Pair, client: Client) -> Result<()> { Ok(()) } -pub async fn go_offline(pair: Pair, client: Client) -> Result<()> { +pub async fn go_offline(pair: Pair, client: &Client) -> Result<()> { client .tx() .sign_and_submit_then_watch( @@ -78,7 +81,10 @@ pub async fn go_offline(pair: Pair, client: Client) -> Result<()> { Ok(()) } -pub async fn online(client: Client, args: &Args) -> Result<()> { +pub async fn online(data: &Data) -> Result<()> { + let client = data.client(); + let indexer = data.indexer.clone(); + let parent_hash = client .clone() .storage() @@ -86,21 +92,7 @@ pub async fn online(client: Client, args: &Args) -> Result<()> { .await? .unwrap(); - let gql_client = reqwest::Client::builder() - .user_agent("gcli/0.1.0") - .build()?; - - let mut identity_cache = cache::IdentityCache::new( - client.clone(), - if args.no_indexer { - None - } else { - Some(Indexer { - gql_client, - gql_url: args.indexer.clone(), - }) - }, - ); + let mut identity_cache = cache::IdentityCache::new(client.clone(), indexer); let online_authorities = client .storage() diff --git a/src/commands/transfer.rs b/src/commands/transfer.rs index b3cefa6..f9f7820 100644 --- a/src/commands/transfer.rs +++ b/src/commands/transfer.rs @@ -10,7 +10,7 @@ type BalancesCall = runtime::runtime_types::pallet_balances::pallet::Call; pub async fn transfer( pair: Pair, - client: Client, + client: &Client, balance: u64, dest: AccountId32, keep_alive: bool, @@ -42,7 +42,7 @@ pub async fn transfer( pub async fn transfer_multiple( pair: Pair, - client: Client, + client: &Client, amount: u64, dests: Vec<AccountId32>, ) -> Result<()> { diff --git a/src/conf.rs b/src/conf.rs index d292c8a..a1628a3 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -5,39 +5,39 @@ const APP_NAME: &str = "gcli"; #[derive(Serialize, Deserialize, Debug)] pub struct Config { - duniter_endpoint: String, - indexer_endpoint: String, + pub duniter_endpoint: String, + pub indexer_endpoint: String, } impl std::default::Default for Config { fn default() -> Self { Self { - duniter_endpoint: String::from("ws://localhost:9944"), - indexer_endpoint: String::from("http://localhost:8080/v1/graphql"), + duniter_endpoint: String::from("ws://localhost:9944"), + indexer_endpoint: String::from("http://localhost:8080/v1/graphql"), } } } /// load config file and manage error if could not pub fn load_conf() -> Config { - match confy::load(APP_NAME, None) { - Ok(cfg) => cfg, - Err(e) => { - log::warn!("met error while loading config file"); - log::error!("{}", e); - log::info!("removing the old conf file and creating a new one"); - let cfg = Config::default(); - confy::store(APP_NAME, None, &cfg).expect("unable to write default config"); - cfg - } - } + match confy::load(APP_NAME, None) { + Ok(cfg) => cfg, + Err(e) => { + log::warn!("met error while loading config file"); + log::error!("{}", e); + log::info!("removing the old conf file and creating a new one"); + let cfg = Config::default(); + confy::store(APP_NAME, None, &cfg).expect("unable to write default config"); + cfg + } + } } #[derive(Clone, Default, Debug, clap::Parser)] pub enum Subcommand { #[default] - /// Show config path - Where, + /// Show config path + Where, /// Show config Show, } @@ -47,9 +47,12 @@ pub fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<()> { // match subcommand match command { Subcommand::Where => { - println!("{}", confy::get_configuration_file_path(APP_NAME, None)?.display()); - } - Subcommand::Show => { + println!( + "{}", + confy::get_configuration_file_path(APP_NAME, None)?.display() + ); + } + Subcommand::Show => { println!("{:?}", data.cfg); } }; diff --git a/src/data.rs b/src/data.rs index d3b1afe..2e2c399 100644 --- a/src/data.rs +++ b/src/data.rs @@ -50,6 +50,7 @@ impl Data { token_symbol: "tokens".into(), ..Default::default() } + .overwrite_from_args() } // --- getters --- // the "unwrap" should not fail if data is well prepared @@ -78,6 +79,16 @@ impl Data { ) } // --- mutators --- + /// use arguments to overwrite config + pub fn overwrite_from_args(mut self) -> Self { + if let Some(duniter_endpoint) = self.args.url.clone() { + self.cfg.duniter_endpoint = duniter_endpoint; + } + if let Some(indexer_endpoint) = self.args.indexer.clone() { + self.cfg.indexer_endpoint = indexer_endpoint + } + self + } /// force an address if needed pub fn build_address(mut self) -> Self { self.address = Some( @@ -109,12 +120,17 @@ impl Data { /// build a client from url // TODO get client from a pre-defined list pub async fn build_client(mut self) -> Self { - self.client = Some(Client::from_url(&self.args.url).await.unwrap_or_else(|_| { - panic!( - "could not establish connection with the server {}", - self.args.url - ) - })); + let duniter_endpoint = self.cfg.duniter_endpoint.clone(); + self.client = Some( + Client::from_url(&duniter_endpoint) + .await + .unwrap_or_else(|_| { + panic!( + "could not establish connection with the server {}", + duniter_endpoint + ) + }), + ); self } /// build an indexer if not disabled @@ -127,7 +143,7 @@ impl Data { gql_client: reqwest::Client::builder() .user_agent("gcli/0.1.0") .build()?, - gql_url: self.args.indexer.clone(), + gql_url: self.cfg.indexer_endpoint.clone(), }) }; Ok(self) diff --git a/src/main.rs b/src/main.rs index 196cde2..82baddb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,8 +76,8 @@ pub struct Args { #[clap(subcommand)] pub subcommand: Subcommand, /// Overwrite indexer endpoint - #[clap(short, long, default_value = "")] - indexer: String, + #[clap(short, long)] + indexer: Option<String>, /// Do not use indexer #[clap(long)] no_indexer: bool, @@ -92,8 +92,8 @@ pub struct Args { #[clap(short, long)] address: Option<String>, /// Overwrite duniter websocket RPC endpoint - #[clap(short, long, default_value = "")] - url: String, + #[clap(short, long)] + url: Option<String>, } /// track progress of transaction on the network @@ -312,6 +312,7 @@ async fn main() -> Result<(), GcliError> { track_progress(progress).await? } Subcommand::CreateOneshot { balance, dest } => { + data = data.build_client().await; commands::oneshot::create_oneshot_account( get_keys( args.secret_format, @@ -321,13 +322,14 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), balance, dest, ) .await? } Subcommand::ConsumeOneshot { dest, dest_oneshot } => { + data = data.build_client().await; commands::oneshot::consume_oneshot_account( get_keys( args.secret_format, @@ -337,7 +339,7 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), dest, dest_oneshot, ) @@ -350,6 +352,7 @@ async fn main() -> Result<(), GcliError> { remaining_to, remaining_to_oneshot, } => { + data = data.build_client().await; commands::oneshot::consume_oneshot_account_with_remaining( get_keys( args.secret_format, @@ -359,7 +362,7 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), balance, dest, dest_oneshot, @@ -369,13 +372,8 @@ async fn main() -> Result<(), GcliError> { .await? } Subcommand::Expire { blocks, sessions } => { - commands::expire::monitor_expirations( - Client::from_url(&args.url).await.unwrap(), - blocks, - sessions, - &args, - ) - .await? + data = data.build_client().await; + commands::expire::monitor_expirations(&data, blocks, sessions).await? } Subcommand::Identity { ref account_id, @@ -384,11 +382,10 @@ async fn main() -> Result<(), GcliError> { } => { data = data.build_client().await; commands::identity::get_identity( - data.client(), + &data, account_id.clone(), identity_id, username.clone(), - &args, ) .await? } @@ -404,6 +401,7 @@ async fn main() -> Result<(), GcliError> { commands::revocation::print_revoc_sig(&data) } Subcommand::GoOffline => { + data = data.build_client().await; commands::smith::go_offline( get_keys( args.secret_format, @@ -413,11 +411,12 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), ) .await? } Subcommand::GoOnline => { + data = data.build_client().await; commands::smith::go_online( get_keys( args.secret_format, @@ -427,24 +426,23 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), ) .await? } Subcommand::OneshotBalance { account } => { - commands::oneshot::oneshot_account_balance( - Client::from_url(&args.url).await.unwrap(), - account, - ) - .await? + data = data.build_client().await; + commands::oneshot::oneshot_account_balance(data.client(), account).await? } Subcommand::Online => { - commands::smith::online(Client::from_url(&args.url).await.unwrap(), &args).await? + data = data.build_client().await; + commands::smith::online(&data).await? } Subcommand::Repart { target, actual_repart, } => { + data = data.build_client().await; commands::net_test::repart( get_keys( args.secret_format, @@ -454,13 +452,14 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), target, actual_repart, ) .await? } Subcommand::SpamRoll { actual_repart } => { + data = data.build_client().await; commands::net_test::spam_roll( get_keys( args.secret_format, @@ -470,7 +469,7 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), actual_repart, ) .await? @@ -489,19 +488,15 @@ async fn main() -> Result<(), GcliError> { commands::smith::cert(data.client(), data.keypair(), data.idty_index(), to).await? } Subcommand::TechMembers => { - commands::collective::technical_committee_members( - Client::from_url(&args.url).await.unwrap(), - &args, - ) - .await? + data = data.build_client().await; + commands::collective::technical_committee_members(&data).await? } Subcommand::TechProposals => { - commands::collective::technical_committee_proposals( - Client::from_url(&args.url).await.unwrap(), - ) - .await? + data = data.build_client().await; + commands::collective::technical_committee_proposals(data.client()).await? } Subcommand::TechVote { hash, index, vote } => { + data = data.build_client().await; let vote = match vote { 0 => false, 1 => true, @@ -516,7 +511,7 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), hash, //H256::from_str(&hash).expect("Invalid hash formatting"), index, vote, @@ -528,6 +523,7 @@ async fn main() -> Result<(), GcliError> { dest, keep_alive, } => { + data = data.build_client().await; commands::transfer::transfer( get_keys( args.secret_format, @@ -537,7 +533,7 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), amount, dest, keep_alive, @@ -545,6 +541,7 @@ async fn main() -> Result<(), GcliError> { .await? } Subcommand::TransferMultiple { amount, dests } => { + data = data.build_client().await; commands::transfer::transfer_multiple( get_keys( args.secret_format, @@ -554,25 +551,28 @@ async fn main() -> Result<(), GcliError> { )? .1 .unwrap(), - Client::from_url(&args.url).await.unwrap(), + data.client(), amount, dests, ) .await? } - Subcommand::UpdateKeys => commands::smith::update_session_keys( - get_keys( - args.secret_format, - &args.address, - &args.secret, - NeededKeys::Secret, - )? - .1 - .unwrap(), - Client::from_url(&args.url).await.unwrap(), - ) - .await - .unwrap(), + Subcommand::UpdateKeys => { + data = data.build_client().await; + commands::smith::update_session_keys( + get_keys( + args.secret_format, + &args.address, + &args.secret, + NeededKeys::Secret, + )? + .1 + .unwrap(), + data.client(), + ) + .await + .unwrap() + } Subcommand::RuntimeInfo => { data = data.build_client().await.fetch_system_properties().await?; commands::runtime::runtime_info(data).await; @@ -600,14 +600,14 @@ async fn main() -> Result<(), GcliError> { if data.genesis_hash == data.indexer_genesis_hash { println!( "{} and {} have the same genesis hash: {}", - data.args.url, + data.cfg.duniter_endpoint, data.indexer().gql_url, data.genesis_hash ); } else { println!( "âš ï¸ {} ({}) and {} ({}) do not share same genesis", - data.args.url, + data.cfg.duniter_endpoint, data.genesis_hash, data.indexer().gql_url, data.indexer_genesis_hash -- GitLab