diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index 83f380d63a8..66f874203b9 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -19,7 +19,7 @@ use iroha_client::{ config::{path::Path as ConfigPath, Configuration as ClientConfiguration}, data_model::prelude::*, }; -use iroha_primitives::addr::SocketAddr; +use iroha_primitives::addr::{Ipv4Addr, Ipv6Addr, SocketAddr}; /// Metadata wrapper, which can be captured from cli arguments (from user supplied file). #[derive(Debug, Clone)] @@ -45,6 +45,24 @@ impl FromStr for Metadata { } } +#[derive(Debug, Clone)] +struct ValueArg(Value); + +impl FromStr for ValueArg { + type Err = Error; + + fn from_str(s: &str) -> Result { + s.parse::() + .map(Value::Bool) + .or_else(|_| s.parse::().map(Value::Ipv4Addr)) + .or_else(|_| s.parse::().map(Value::Ipv6Addr)) + .or_else(|_| s.parse::().map(Value::Numeric)) + .or_else(|_| s.parse::().map(Value::PublicKey)) + .or_else(|_| serde_json::from_str::(s).map_err(|e| e.into())) + .map(ValueArg) + } +} + /// Client configuration wrapper. Allows getting itself from arguments from cli (from user supplied file). #[derive(Debug, Clone)] struct Configuration(pub ClientConfiguration); @@ -663,14 +681,17 @@ mod account { } mod asset { - use iroha_client::client::{self, asset, Client}; + use iroha_client::{ + client::{self, asset, Client}, + data_model::{asset::AssetDefinition, name::Name}, + }; use super::*; /// Subcommand for dealing with asset #[derive(StructOpt, Debug)] pub enum Args { - /// Register subcommand of asset + /// Command for Registering a new asset Register(Register), /// Command for minting asset in existing Iroha account Mint(Mint), @@ -683,13 +704,19 @@ mod asset { /// List assets #[clap(subcommand)] List(List), + /// Put a key-value in a store Asset defintion + SetKeyValue(SetKeyValue), + /// Remove a key-value via key in a store Asset definition + RemoveKeyValue(RemoveKeyValue), + /// Get a value from store Asset definition via key + GetKeyValue(GetKeyValue), } impl RunArgs for Args { fn run(self, context: &mut dyn RunContext) -> Result<()> { match_all!( (self, context), - { Args::Register, Args::Mint, Args::Burn, Args::Transfer, Args::Get, Args::List } + { Args::Register, Args::Mint, Args::Burn, Args::Transfer, Args::Get, Args::List, Args::SetKeyValue, Args::RemoveKeyValue, Args::GetKeyValue} ) } } @@ -892,6 +919,72 @@ mod asset { Ok(()) } } + + #[derive(StructOpt, Debug)] + pub struct SetKeyValue { + /// AssetId for the Store asset (in form of `asset##account@domain_name') + #[structopt(long = "asset-id")] + pub asset_id: AssetId, + /// The key for the store value + #[structopt(long)] + pub key: Name, + /// The value to be associated with the key + #[structopt(long)] + pub value: ValueArg, + } + + impl RunArgs for SetKeyValue { + fn run(self, context: &mut dyn RunContext) -> Result<()> { + let Self { + asset_id, + key, + value: ValueArg(value), + } = self; + + let set = iroha_client::data_model::isi::SetKeyValue::asset(asset_id, key, value); + submit([set], UnlimitedMetadata::default(), context)?; + Ok(()) + } + } + #[derive(StructOpt, Debug)] + pub struct RemoveKeyValue { + #[structopt(long = "asset-id")] + pub asset_id: AssetId, + /// The key for the store value + #[structopt(long)] + pub key: Name, + } + + impl RunArgs for RemoveKeyValue { + fn run(self, context: &mut dyn RunContext) -> Result<()> { + let Self { asset_id, key } = self; + let remove = iroha_client::data_model::isi::RemoveKeyValue::asset(asset_id, key); + submit([remove], UnlimitedMetadata::default(), context)?; + Ok(()) + } + } + + #[derive(StructOpt, Debug)] + pub struct GetKeyValue { + #[structopt(long = "asset-id")] + pub asset_id: AssetId, + // The key for the store value + #[structopt(long)] + pub key: Name, + } + + impl RunArgs for GetKeyValue { + fn run(self, context: &mut dyn RunContext) -> Result<()> { + let Self { asset_id, key } = self; + let client = Client::new(context.configuration())?; + let find_key_value = FindAssetKeyValueByIdAndKey::new(asset_id, key.clone()); + let asset = client + .request(find_key_value) + .wrap_err("Failed to get key-value")?; + context.print_data(&asset)?; + Ok(()) + } + } } mod peer { diff --git a/data_model/src/asset.rs b/data_model/src/asset.rs index 25c19006e56..998341c83c4 100644 --- a/data_model/src/asset.rs +++ b/data_model/src/asset.rs @@ -494,7 +494,7 @@ impl FromStr for AssetId { })?, account_id.domain_id.clone()) } else { - return Err(ParseError { reason: "The `definition_id` part of the `asset_id` failed to parse. Ensure that you have it in the right format: `name#domain_of_asset#account_name@domain_of_account`." }); + return Err(ParseError { reason: "The `definition_id` part of the `asset_id` failed to parse. Ensure that you have it in the right format: `name#domain_of_asset#account_name@domain_of_account` or `name##account_name@domain_of_account` in case of same domain" }); } }; Ok(Self {