Skip to content

Commit b67f56e

Browse files
author
Hans
authored
Merge pull request #39 from dfinity-lab/hansl/canister-call
Canister query and call commands
2 parents e9c6eab + fa6d0bb commit b67f56e

File tree

13 files changed

+220
-101
lines changed

13 files changed

+220
-101
lines changed

dfx/Cargo.lock

Lines changed: 10 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dfx/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ console = "0.7.7"
1919
flate2 = "1.0.11"
2020
futures = "0.1.28"
2121
indicatif = "0.12.0"
22+
rand = "0.7.2"
2223
reqwest = "0.9.20"
2324
serde = "1.0"
2425
serde_bytes = "0.11.2"

dfx/src/commands/call.rs

Lines changed: 0 additions & 61 deletions
This file was deleted.

dfx/src/commands/canister/call.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use crate::lib::api_client::{call, Blob};
2+
use crate::lib::env::ClientEnv;
3+
use crate::lib::error::DfxResult;
4+
use crate::lib::CanisterId;
5+
use crate::util::clap::validators;
6+
use clap::{App, Arg, ArgMatches, SubCommand};
7+
use tokio::runtime::Runtime;
8+
9+
pub fn construct() -> App<'static, 'static> {
10+
SubCommand::with_name("call")
11+
.about("Call a canister.")
12+
.arg(
13+
Arg::with_name("canister")
14+
.takes_value(true)
15+
.help("The canister ID (a number) to call.")
16+
.required(true)
17+
.validator(validators::is_canister_id),
18+
)
19+
.arg(
20+
Arg::with_name("method_name")
21+
.help("The method name file to use.")
22+
.required(true),
23+
)
24+
.arg(
25+
Arg::with_name("arguments")
26+
.help("Arguments to pass to the method.")
27+
.takes_value(true)
28+
.multiple(true),
29+
)
30+
}
31+
32+
pub fn exec<T>(env: &T, args: &ArgMatches<'_>) -> DfxResult
33+
where
34+
T: ClientEnv,
35+
{
36+
// Read the config.
37+
let canister_id = args.value_of("canister").unwrap().parse::<CanisterId>()?;
38+
let method_name = args.value_of("method_name").unwrap();
39+
let arguments: Option<Vec<&str>> = args.values_of("arguments").map(|args| args.collect());
40+
41+
let client = env.get_client();
42+
let install = call(
43+
client,
44+
canister_id,
45+
method_name.to_owned(),
46+
arguments.map(|args| Blob(Vec::from(args[0]))),
47+
);
48+
49+
let mut runtime = Runtime::new().expect("Unable to create a runtime");
50+
runtime.block_on(install)?;
51+
52+
Ok(())
53+
}

dfx/src/commands/canister/install.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
use crate::lib::api_client::{install_code, Blob};
22
use crate::lib::env::{ClientEnv, ProjectConfigEnv};
33
use crate::lib::error::DfxResult;
4+
use crate::lib::CanisterId;
5+
use crate::util::clap::validators;
46
use clap::{App, Arg, ArgMatches, SubCommand};
57
use std::path::PathBuf;
68
use tokio::runtime::Runtime;
79

8-
fn is_number(v: String) -> Result<(), String> {
9-
v.parse::<u64>()
10-
.map_err(|_| String::from("The value must be a number."))
11-
.map(|_| ())
12-
}
13-
1410
pub fn construct() -> App<'static, 'static> {
1511
SubCommand::with_name("install")
1612
.about("Install a canister.")
@@ -19,7 +15,7 @@ pub fn construct() -> App<'static, 'static> {
1915
.takes_value(true)
2016
.help("The canister ID (a number).")
2117
.required(true)
22-
.validator(is_number),
18+
.validator(validators::is_canister_id),
2319
)
2420
.arg(
2521
Arg::with_name("wasm")
@@ -36,7 +32,7 @@ where
3632
let config = env.get_config().unwrap();
3733
let project_root = config.get_path().parent().unwrap();
3834

39-
let canister_id = args.value_of("canister").unwrap().parse::<u64>()?;
35+
let canister_id = args.value_of("canister").unwrap().parse::<CanisterId>()?;
4036
let wasm_path = args.value_of("wasm").unwrap();
4137
let wasm_path = PathBuf::from(project_root).join(wasm_path);
4238

dfx/src/commands/canister/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@ use crate::lib::env::{ClientEnv, ProjectConfigEnv};
33
use crate::lib::error::{DfxError, DfxResult};
44
use clap::{App, ArgMatches, SubCommand};
55

6+
mod call;
67
mod install;
8+
mod query;
79

810
fn builtins<T>() -> Vec<CliCommand<T>>
911
where
1012
T: ClientEnv + ProjectConfigEnv,
1113
{
12-
vec![CliCommand::new(install::construct(), install::exec)]
14+
vec![
15+
CliCommand::new(call::construct(), call::exec),
16+
CliCommand::new(install::construct(), install::exec),
17+
CliCommand::new(query::construct(), query::exec),
18+
]
1319
}
1420

1521
pub fn construct<T>() -> App<'static, 'static>

dfx/src/commands/canister/query.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use crate::lib::api_client::{query, Blob, QueryResponseReply, ReadResponse};
2+
use crate::lib::env::ClientEnv;
3+
use crate::lib::error::{DfxError, DfxResult};
4+
use crate::lib::CanisterId;
5+
use crate::util::clap::validators;
6+
use clap::{App, Arg, ArgMatches, SubCommand};
7+
use tokio::runtime::Runtime;
8+
9+
pub fn construct() -> App<'static, 'static> {
10+
SubCommand::with_name("query")
11+
.about("Query a canister.")
12+
.arg(
13+
Arg::with_name("canister")
14+
.takes_value(true)
15+
.help("The canister ID (a number) to query.")
16+
.required(true)
17+
.validator(validators::is_canister_id),
18+
)
19+
.arg(
20+
Arg::with_name("method_name")
21+
.help("The name of the method to query.")
22+
.required(true),
23+
)
24+
.arg(
25+
Arg::with_name("arguments")
26+
.help("Arguments to pass to the method.")
27+
.takes_value(true)
28+
.multiple(true),
29+
)
30+
}
31+
32+
pub fn exec<T>(env: &T, args: &ArgMatches<'_>) -> DfxResult
33+
where
34+
T: ClientEnv,
35+
{
36+
// Read the config.
37+
let canister_id = args.value_of("canister").unwrap().parse::<CanisterId>()?;
38+
let method_name = args.value_of("method_name").unwrap();
39+
let arguments: Option<Vec<&str>> = args.values_of("arguments").map(|args| args.collect());
40+
41+
let client = env.get_client();
42+
let install = query(
43+
client,
44+
canister_id,
45+
method_name.to_owned(),
46+
arguments.map(|args| Blob(Vec::from(args[0]))),
47+
);
48+
49+
let mut runtime = Runtime::new().expect("Unable to create a runtime");
50+
match runtime.block_on(install) {
51+
Ok(ReadResponse::Pending) => {
52+
println!("Pending");
53+
Ok(())
54+
}
55+
Ok(ReadResponse::Replied {
56+
reply: QueryResponseReply { arg: Blob(blob) },
57+
}) => {
58+
println!("{}", String::from_utf8_lossy(&blob));
59+
Ok(())
60+
}
61+
Ok(ReadResponse::Rejected {
62+
reject_code,
63+
reject_message,
64+
}) => Err(DfxError::ClientError(reject_code, reject_message)),
65+
// TODO: remove this when moving to ic_http_api.
66+
Ok(ReadResponse::Unknown) => Err(DfxError::Unknown("Unknown response".to_owned())),
67+
Err(x) => Err(x),
68+
}
69+
}

dfx/src/commands/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::lib::error::DfxResult;
55
use clap::ArgMatches;
66

77
mod build;
8-
mod call;
98
mod canister;
109
mod new;
1110
mod start;
@@ -41,7 +40,6 @@ where
4140
{
4241
vec![
4342
CliCommand::new(build::construct(), build::exec),
44-
CliCommand::new(call::construct(), call::exec),
4543
CliCommand::new(canister::construct::<T>(), canister::exec),
4644
CliCommand::new(new::construct(), new::exec),
4745
CliCommand::new(start::construct(), start::exec),

0 commit comments

Comments
 (0)