Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lift events subcommand to the toplevel #893

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ license = 'Apache-2.0'
name = 'tonos-cli'
readme = 'README.md'
repository = 'https://github.com/tonlabs/tonos-cli'
version = '0.29.1'
version = '0.30.0'

[features]
sold = ["dep:sold"]
Expand Down
115 changes: 1 addition & 114 deletions src/depool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ use crate::helpers::{
now,
TonClient,
answer_filter,
events_filter,
print_message,
};
use crate::multisig::{send_with_body, MSIG_ABI};
use clap::{App, ArgMatches, SubCommand, Arg, AppSettings};

use ton_client::abi::{ParamsOfEncodeMessageBody, CallSet, ParamsOfDecodeMessageBody};
use ton_client::abi::{ParamsOfEncodeMessageBody, CallSet};
use ton_client::net::{OrderBy, ParamsOfQueryCollection, ParamsOfWaitForCollection, SortDirection};
use crate::call::{process_message};

Expand Down Expand Up @@ -188,18 +187,6 @@ pub fn create_depool_command<'a, 'b>() -> App<'a, 'b> {
.arg(wallet_arg.clone())
.arg(wait_answer.clone())
.arg(keys_arg.clone())))
.subcommand(SubCommand::with_name("events")
.about("Prints depool events.")
.setting(AppSettings::AllowLeadingHyphen)
.arg(Arg::with_name("SINCE")
.takes_value(true)
.long("--since")
.short("-s")
.help("Prints events since this unixtime."))
.arg(Arg::with_name("WAITONE")
.long("--wait-one")
.short("-w")
.help("Waits until new event will be emitted.")) )
}

struct CommandData<'a> {
Expand Down Expand Up @@ -313,9 +300,6 @@ pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<(
return set_withdraw_command(&config, &depool, &wallet, &keys, enable_withdraw).await;
}
}
if let Some(m) = m.subcommand_matches("events") {
return events_command(m, &config, &depool).await
}
if let Some(m) = m.subcommand_matches("answers") {
return answer_command(m, &config, &depool).await
}
Expand Down Expand Up @@ -372,103 +356,6 @@ async fn print_answer(ton: TonClient, message: &serde_json::Value) -> Result <()
Ok(())
}

/*
* Events command
*/

async fn events_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Result<(), String> {
let since = m.value_of("SINCE");
let wait_for = m.is_present("WAITONE");
let depool = Some(depool);
print_args!(depool, since);
if !wait_for {
let since = since.map(|s| {
u32::from_str_radix(s, 10)
.map_err(|e| format!(r#"cannot parse "since" option: {}"#, e))
})
.transpose()?
.unwrap_or(0);
get_events(config, depool.unwrap(), since).await
} else {
wait_for_event(config, depool.unwrap()).await
}
}

async fn print_event(ton: TonClient, event: &serde_json::Value) -> Result<(), String> {
println!("event {}", event["id"].as_str()
.ok_or("failed to serialize event id")?);

let body = event["body"].as_str()
.ok_or("failed to serialize event body")?;
let def_config = Config::default();
let result = ton_client::abi::decode_message_body(
ton.clone(),
ParamsOfDecodeMessageBody {
abi: load_abi(DEPOOL_ABI, &def_config).await.map_err(|e| format!("failed to load depool abi: {}", e))?,
body: body.to_owned(),
is_internal: false,
..Default::default()
},
).await;
let (name, args) = if result.is_err() {
("unknown".to_owned(), "{}".to_owned())
} else {
let result = result.unwrap();
(result.name, serde_json::to_string(&result.value)
.map_err(|e| format!("failed to serialize the result: {}", e))?)
};

println!("{} {} ({})\n{}\n",
name,
event["created_at"].as_u64().ok_or("failed to serialize event field")?,
event["created_at_string"].as_str().ok_or("failed to serialize event field")?,
args
);
Ok(())
}

async fn get_events(config: &Config, depool: &str, since: u32) -> Result<(), String> {
let ton = create_client_verbose(&config)?;
let _addr = load_ton_address(depool, &config)?;

let events = ton_client::net::query_collection(
ton.clone(),
ParamsOfQueryCollection {
collection: "messages".to_owned(),
filter: Some(events_filter(depool, since)),
result: "id body created_at created_at_string".to_owned(),
order: Some(vec![OrderBy{ path: "created_at".to_owned(), direction: SortDirection::DESC }]),
..Default::default()
},
).await.map_err(|e| format!("failed to query depool events: {}", e))?;
println!("{} events found", events.result.len());
for event in &events.result {
print_event(ton.clone(), event).await?;
}
println!("Done");
Ok(())
}

async fn wait_for_event(config: &Config, depool: &str) -> Result<(), String> {
let ton = create_client_verbose(&config)?;
let _addr = load_ton_address(depool, &config)?;
println!("Waiting for a new event...");
let event = ton_client::net::wait_for_collection(
ton.clone(),
ParamsOfWaitForCollection {
collection: "messages".to_owned(),
filter: Some(events_filter(depool, now()?)),
result: "id body created_at created_at_string".to_owned(),
timeout: Some(config.timeout),
..Default::default()
},

).await.map_err(|e| println!("failed to query event: {}", e));
if event.is_ok() {
print_event(ton.clone(), &event.unwrap().result).await?;
}
Ok(())
}
/*
* Stake commands
*/
Expand Down
126 changes: 126 additions & 0 deletions src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright 2022 TON DEV SOLUTIONS LTD.
*
* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use
* this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific TON DEV software governing permissions and
* limitations under the License.
*/

use crate::config::Config;
use crate::helpers::{
create_client_verbose,
load_abi,
load_ton_address,
now,
TonClient,
events_filter, abi_from_matches_or_config,
};
use clap::ArgMatches;

use ton_client::abi::{ParamsOfDecodeMessageBody, Abi};
use ton_client::net::{OrderBy, ParamsOfQueryCollection, ParamsOfWaitForCollection, SortDirection};

pub async fn events_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> {
let addr = m.value_of("ADDRESS")
.map(|s| s.to_string())
.or(config.addr.clone())
.ok_or("ADDRESS is not defined. Supply it in the config file or command line."
.to_string())?;
let abi_path = abi_from_matches_or_config(m, config)?;
let abi = load_abi(&abi_path, config).await?;

let since = m.value_of("SINCE");
let wait_for = m.is_present("WAITONE");

if !wait_for {
let since = since.map(|s| {
u32::from_str_radix(s, 10)
.map_err(|e| format!(r#"cannot parse "since" option: {}"#, e))
})
.transpose()?
.unwrap_or(0);
get_events(config, abi, &addr, since).await
} else {
wait_for_event(config, abi, &addr).await
}
}

async fn print_event(ton: TonClient, abi: &Abi, event: &serde_json::Value) -> Result<(), String> {
println!("event {}", event["id"].as_str()
.ok_or("failed to serialize event id")?);

let body = event["body"].as_str()
.ok_or("failed to serialize event body")?;
let result = ton_client::abi::decode_message_body(
ton.clone(),
ParamsOfDecodeMessageBody {
abi: abi.clone(),
body: body.to_owned(),
is_internal: false,
..Default::default()
},
).await;
let (name, args) = if result.is_err() {
("unknown".to_owned(), "{}".to_owned())
} else {
let result = result.unwrap();
(result.name, serde_json::to_string(&result.value)
.map_err(|e| format!("failed to serialize the result: {}", e))?)
};

println!("{} {} ({})\n{}\n",
name,
event["created_at"].as_u64().ok_or("failed to serialize event field")?,
event["created_at_string"].as_str().ok_or("failed to serialize event field")?,
args
);
Ok(())
}

async fn get_events(config: &Config, abi: Abi, addr: &str, since: u32) -> Result<(), String> {
let ton = create_client_verbose(&config)?;
let _addr = load_ton_address(addr, &config)?;

let events = ton_client::net::query_collection(
ton.clone(),
ParamsOfQueryCollection {
collection: "messages".to_owned(),
filter: Some(events_filter(addr, since)),
result: "id body created_at created_at_string".to_owned(),
order: Some(vec![OrderBy{ path: "created_at".to_owned(), direction: SortDirection::DESC }]),
..Default::default()
},
).await.map_err(|e| format!("failed to query account events: {}", e))?;
println!("{} events found", events.result.len());
for event in &events.result {
print_event(ton.clone(), &abi, event).await?;
}
println!("Done");
Ok(())
}

async fn wait_for_event(config: &Config, abi: Abi, addr: &str) -> Result<(), String> {
let ton = create_client_verbose(&config)?;
let _addr = load_ton_address(addr, &config)?;
println!("Waiting for a new event...");
let event = ton_client::net::wait_for_collection(
ton.clone(),
ParamsOfWaitForCollection {
collection: "messages".to_owned(),
filter: Some(events_filter(addr, now()?)),
result: "id body created_at created_at_string".to_owned(),
timeout: Some(config.timeout),
..Default::default()
},

).await.map_err(|e| println!("failed to query event: {}", e));
if event.is_ok() {
print_event(ton.clone(), &abi, &event.unwrap().result).await?;
}
Ok(())
}
20 changes: 20 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mod debot;
mod deploy;
mod depool;
mod depool_abi;
mod events;
mod genaddr;
mod getconfig;
mod helpers;
Expand All @@ -53,6 +54,7 @@ use decode::{create_decode_command, decode_command};
use debug::{create_debug_command, debug_command};
use deploy::{deploy_contract, generate_deploy_message};
use depool::{create_depool_command, depool_command};
use events::events_command;
use helpers::{load_ton_address, load_abi, create_client_local, query_raw,
contract_data_from_matches_or_config_alias};
use genaddr::generate_address;
Expand Down Expand Up @@ -864,6 +866,20 @@ async fn main_internal() -> Result <(), String> {
.long("--default_config")
.short("-e")
.conflicts_with("CONFIG_TXNS"));
let events_cmd = SubCommand::with_name("events")
.about("Prints account events.")
.setting(AppSettings::AllowLeadingHyphen)
.arg(abi_arg.clone())
.arg(address_arg.clone())
.arg(Arg::with_name("SINCE")
.takes_value(true)
.long("--since")
.short("-s")
.help("Prints events since this unixtime."))
.arg(Arg::with_name("WAITONE")
.long("--wait-one")
.short("-w")
.help("Waits until new event will be emitted."));

let version = format!("{}\nCOMMIT_ID: {}\nBUILD_DATE: {}\nCOMMIT_DATE: {}\nGIT_BRANCH: {}",
env!("CARGO_PKG_VERSION"),
Expand Down Expand Up @@ -925,6 +941,7 @@ async fn main_internal() -> Result <(), String> {
.subcommand(deployx_cmd)
.subcommand(runx_cmd)
.subcommand(update_config_param_cmd)
.subcommand(events_cmd)
.setting(AppSettings::SubcommandRequired);
#[cfg(feature = "sold")]
let matches = matches.subcommand(create_compile_command());
Expand Down Expand Up @@ -1100,6 +1117,9 @@ async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(),
if let Some(m) = matches.subcommand_matches("replay") {
return replay_command(m, config).await;
}
if let Some(m) = matches.subcommand_matches("events") {
return events_command(m, &config).await
}
#[cfg(feature = "sold")]
if let Some(m) = matches.subcommand_matches("compile") {
return compile_command(m, &config).await;
Expand Down
Loading