Skip to content

Commit

Permalink
feat(gcli): construct API on demand
Browse files Browse the repository at this point in the history
  • Loading branch information
clearloop committed Dec 10, 2023
1 parent a091916 commit a787dd9
Show file tree
Hide file tree
Showing 12 changed files with 71 additions and 64 deletions.
6 changes: 3 additions & 3 deletions gcli/examples/mycli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use gcli::{async_trait, App, Command, Parser, Signer};
use gcli::{async_trait, App, Command, Parser};

/// My customized sub commands.
#[derive(Debug, Parser)]
Expand All @@ -37,9 +37,9 @@ pub struct MyGCli {

#[async_trait]
impl App for MyGCli {
async fn exec(&self, signer: Signer) -> anyhow::Result<()> {
async fn exec(&self) -> anyhow::Result<()> {
match &self.command {
SubCommand::GCliCommands(command) => command.exec(signer).await,
SubCommand::GCliCommands(command) => command.exec(self).await,
SubCommand::Ping => {
println!("pong");
Ok(())
Expand Down
43 changes: 22 additions & 21 deletions gcli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use gsdk::{signer::Signer, Api};
/// Command line gear program application abstraction.
///
/// ```ignore
/// use gcli::{async_trait, App, Command, Parser, Signer};
/// use gcli::{async_trait, App, Command, Parser};
///
/// /// My customized sub commands.
/// #[derive(Debug, Parser)]
Expand All @@ -48,9 +48,9 @@ use gsdk::{signer::Signer, Api};
///
/// #[async_trait]
/// impl App for MyGCli {
/// async fn exec(&self, signer: Signer) -> anyhow::Result<()> {
/// async fn exec(&self) -> anyhow::Result<()> {
/// match &self.command {
/// SubCommand::GCliCommands(command) => command.exec(signer).await,
/// SubCommand::GCliCommands(command) => command.exec(self).await,
/// SubCommand::Ping => {
/// println!("pong");
/// Ok(())
Expand All @@ -65,7 +65,7 @@ use gsdk::{signer::Signer, Api};
/// }
/// ```
#[async_trait::async_trait]
pub trait App: Parser {
pub trait App: Parser + Sync {
/// Timeout of rpc requests.
fn timeout(&self) -> u64 {
60000
Expand All @@ -87,7 +87,23 @@ pub trait App: Parser {
}

/// Exec program from the parsed arguments.
async fn exec(&self, signer: Signer) -> anyhow::Result<()>;
async fn exec(&self) -> anyhow::Result<()>;

/// Get signer.
async fn signer(&self) -> anyhow::Result<Signer> {
let endpoint = self.endpoint().clone();
let timeout = self.timeout();
let passwd = self.passwd();

let api = Api::new_with_timeout(endpoint.as_deref(), Some(timeout)).await?;
let pair = if let Ok(s) = keystore::cache(passwd.as_deref()) {
s
} else {
keystore::keyring(passwd.as_deref())?
};

Ok((api, pair).into())
}

/// Run application.
///
Expand All @@ -112,22 +128,7 @@ pub trait App: Parser {
.format_timestamp(None);
builder.try_init()?;

let signer = {
let endpoint = self.endpoint().clone();
let timeout = self.timeout();
let passwd = self.passwd();

let api = Api::new_with_timeout(endpoint.as_deref(), Some(timeout)).await?;
let pair = if let Ok(s) = keystore::cache(passwd.as_deref()) {
s
} else {
keystore::keyring(passwd.as_deref())?
};

(api, pair).into()
};

self.exec(signer)
self.exec()
.await
.map_err(|e| eyre!("Failed to run app, {e}"))
}
Expand Down
23 changes: 11 additions & 12 deletions gcli/src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
//! commands
use crate::App;
use clap::Parser;
use gsdk::signer::Signer;

pub mod claim;
pub mod create;
Expand Down Expand Up @@ -54,20 +53,20 @@ pub enum Command {

impl Command {
/// Execute the command.
pub async fn exec(&self, signer: Signer) -> anyhow::Result<()> {
pub async fn exec(&self, app: &impl App) -> anyhow::Result<()> {
match self {
Command::Key(key) => key.exec()?,
Command::Login(login) => login.exec()?,
Command::New(new) => new.exec().await?,
Command::Program(program) => program.exec(signer.api().clone()).await?,
Command::Program(program) => program.exec(app).await?,
Command::Update(update) => update.exec().await?,
Command::Claim(claim) => claim.exec(signer).await?,
Command::Create(create) => create.exec(signer).await?,
Command::Info(info) => info.exec(signer).await?,
Command::Send(send) => send.exec(signer).await?,
Command::Upload(upload) => upload.exec(signer).await?,
Command::Transfer(transfer) => transfer.exec(signer).await?,
Command::Reply(reply) => reply.exec(signer).await?,
Command::Claim(claim) => claim.exec(app.signer().await?).await?,
Command::Create(create) => create.exec(app.signer().await?).await?,
Command::Info(info) => info.exec(app.signer().await?).await?,
Command::Send(send) => send.exec(app.signer().await?).await?,
Command::Upload(upload) => upload.exec(app.signer().await?).await?,
Command::Transfer(transfer) => transfer.exec(app.signer().await?).await?,
Command::Reply(reply) => reply.exec(app.signer().await?).await?,
}

Ok(())
Expand Down Expand Up @@ -114,8 +113,8 @@ impl App for Opt {
self.passwd.clone()
}

async fn exec(&self, signer: Signer) -> anyhow::Result<()> {
self.command.exec(signer).await
async fn exec(&self) -> anyhow::Result<()> {
self.command.exec(self).await
}
}

Expand Down
5 changes: 3 additions & 2 deletions gcli/src/cmd/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Command `program`.
use crate::{meta::Meta, result::Result};
use crate::{meta::Meta, result::Result, App};
use clap::Parser;
use gsdk::{ext::sp_core::H256, Api};
use std::{fs, path::PathBuf};
Expand Down Expand Up @@ -61,7 +61,7 @@ pub enum Program {

impl Program {
/// Run command program.
pub async fn exec(&self, api: Api) -> Result<()> {
pub async fn exec(&self, app: &impl App) -> Result<()> {
match self {
Program::State {
pid,
Expand All @@ -70,6 +70,7 @@ impl Program {
args,
at,
} => {
let api = app.signer().await?.api().clone();
if let (Some(wasm), Some(method)) = (wasm, method) {
// read state from wasm.
Self::wasm_state(api, *pid, wasm.to_vec(), method, args.clone(), *at).await?;
Expand Down
2 changes: 1 addition & 1 deletion gcli/tests/cmd/claim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

//! Integration tests for command `send`

use crate::common::{self, logs, traits::NodeExec, Args, Result, ALICE_SS58_ADDRESS as ADDRESS};
use crate::common::{self, logs, node::NodeExec, Args, Result, ALICE_SS58_ADDRESS as ADDRESS};
use gsdk::Api;

const REWARD_PER_BLOCK: u128 = 75_000; // 3_000 gas * 25 value per gas
Expand Down
2 changes: 1 addition & 1 deletion gcli/tests/cmd/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
//! Integration tests for command `deploy`
use crate::common::{
self, logs,
traits::{Convert, NodeExec},
node::{Convert, NodeExec},
Args, Result,
};

Expand Down
6 changes: 5 additions & 1 deletion gcli/tests/cmd/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Integration tests for command `key`
use crate::common::{self, traits::Convert, Result};
use crate::common::{self, node::Convert, Result};

const SIGNATURE_PATT: &str = "Signature:";
const SEED_PATT: &str = "Seed:";
Expand All @@ -27,6 +27,10 @@ const PUBLIC_PATT: &str = "Public key:";

fn parse_from<'s>(log: &'s str, patt: &'s str) -> &'s str {
let arr = log.split(patt).collect::<Vec<&str>>();
if arr.len() != 2 {
panic!("Failed to parse {patt}, log: {log}");
}

arr[1].split_whitespace().collect::<Vec<&str>>()[0]
}

Expand Down
15 changes: 5 additions & 10 deletions gcli/tests/cmd/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
//! Integration tests for command `program`
use crate::common::{
self, env, logs,
traits::{Convert, NodeExec},
node::{Convert, NodeExec},
Args, Result,
};
use demo_new_meta::{MessageInitIn, Wallet};
Expand Down Expand Up @@ -100,9 +100,8 @@ fn test_command_program_metadata_works() -> Result<()> {
let node = common::dev()?;
let meta = env::wasm_bin("demo_new_meta.meta.txt");
let args = Args::new("program").action("meta").meta(meta);
let result = node.run(args)?;
let stdout = node.stdout(args)?;

let stdout = result.stdout.convert();
assert_eq!(
stdout.trim(),
DEMO_NEW_META_METADATA.trim(),
Expand All @@ -121,9 +120,7 @@ fn test_command_program_metadata_derive_works() -> Result<()> {
.flag("--derive")
.derive("Person");

let result = node.run(args)?;
let stdout = result.stdout.convert();

let stdout = node.stdout(args)?;
let expected = "Person { surname: String, name: String }";
assert_eq!(
stdout.trim(),
Expand Down Expand Up @@ -158,9 +155,8 @@ fn test_command_program_metawasm_works() -> Result<()> {
let node = common::dev()?;
let meta = env::wasm_bin("demo_meta_state_v1.meta.wasm");
let args = Args::new("program").action("meta").meta(meta);
let result = node.run(args)?;
let stdout = node.stdout(args)?;

let stdout = result.stdout.convert();
assert_eq!(
stdout.trim(),
META_WASM_V1_OUTPUT.trim(),
Expand All @@ -179,8 +175,7 @@ fn test_command_program_metawasm_derive_works() -> Result<()> {
.flag("--derive")
.derive("Person");

let result = node.run(args)?;
let stdout = result.stdout.convert();
let stdout = node.stdout(args)?;

let expected = "Person { surname: String, name: String }";
assert_eq!(
Expand Down
2 changes: 1 addition & 1 deletion gcli/tests/cmd/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Integration tests for command `send`
use crate::common::{self, traits::NodeExec, Args, Result};
use crate::common::{self, node::NodeExec, Args, Result};
use gsdk::Api;
use scale_info::scale::Encode;

Expand Down
2 changes: 1 addition & 1 deletion gcli/tests/cmd/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
//! Integration tests for command `upload`
use crate::common::{
self, env, logs,
traits::{Convert, NodeExec},
node::{Convert, NodeExec},
Args, Result,
};
use gear_core::ids::CodeId;
Expand Down
14 changes: 4 additions & 10 deletions gcli/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
//! Common utils for integration tests
pub use self::{
args::Args,
node::{Convert, NodeExec},
result::{Error, Result},
traits::{Convert, NodeExec},
};
use anyhow::anyhow;
use gear_core::ids::{CodeId, ProgramId};
use gsdk::{
ext::{sp_core::crypto::Ss58Codec, sp_runtime::AccountId32},
testing::Node,
};
pub use scale_info::scale::Encode;
use std::{
iter::IntoIterator,
process::{Command, Output},
Expand All @@ -36,17 +37,10 @@ use std::{
mod args;
pub mod env;
pub mod logs;
pub mod node;
mod result;
pub mod traits;

mod prelude {
pub use scale_info::scale::Encode;

pub const ALICE_SS58_ADDRESS: &str = "kGkLEU3e3XXkJp2WK4eNpVmSab5xUNL9QtmLPh8QfCL2EgotW";
}

#[cfg(not(feature = "vara-testing"))]
pub use prelude::*;
pub const ALICE_SS58_ADDRESS: &str = "kGkLEU3e3XXkJp2WK4eNpVmSab5xUNL9QtmLPh8QfCL2EgotW";

impl NodeExec for Node {
fn ws(&self) -> String {
Expand Down
15 changes: 14 additions & 1 deletion gcli/tests/common/traits.rs → gcli/tests/common/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Shared traits.
//! Shared node.

use crate::common::{Args, Output, Result};
use anyhow::anyhow;

/// Convert self into `String`.
pub trait Convert<T> {
Expand Down Expand Up @@ -48,6 +49,18 @@ pub trait NodeExec {
/// ```
fn run(&self, args: Args) -> Result<Output>;

/// Execute command gcli with Node instance
/// and return stdout.
fn stdout(&self, args: Args) -> Result<String> {
let output = self.run(args)?;

if output.stdout.is_empty() {
return Err(anyhow!("stdout is empty, stderr: {}", output.stderr.convert()).into());
}

Ok(output.stdout.convert())
}

/// Formats websocket address to string.
///
/// This interface is used for constructing the `endpoint`
Expand Down

0 comments on commit a787dd9

Please sign in to comment.