diff --git a/api-private/src/lib.rs b/api-private/src/lib.rs index 82b2fd7c487..7fa6cf68f4b 100644 --- a/api-private/src/lib.rs +++ b/api-private/src/lib.rs @@ -29,11 +29,6 @@ pub struct ApiMassaPrivate { /// Private Massa-RPC "manager mode" endpoints #[rpc(server)] pub trait MassaPrivate { - /// Starts the node and waits for node to start. - /// Signals if the node is already running. - #[rpc(name = "start_node")] - fn start_node(&self) -> Result<(), PrivateApiError>; - /// Gracefully stop the node. #[rpc(name = "stop_node")] fn stop_node(&self) -> BoxFuture>; @@ -48,17 +43,20 @@ pub trait MassaPrivate { /// Add a vec of new private keys for the node to use to stake. /// No confirmation to expect. - #[rpc(name = "add_staking_keys")] - fn add_staking_keys(&self, _: Vec) -> BoxFuture>; + #[rpc(name = "add_staking_private_keys")] + fn add_staking_private_keys( + &self, + _: Vec, + ) -> BoxFuture>; /// Remove a vec of addresses used to stake. /// No confirmation to expect. - #[rpc(name = "remove_staking_keys")] - fn remove_staking_keys(&self, _: Vec
) -> BoxFuture>; + #[rpc(name = "remove_staking_addresses")] + fn remove_staking_addresses(&self, _: Vec
) -> BoxFuture>; /// Return hashset of staking addresses. - #[rpc(name = "list_staking_keys")] - fn list_staking_keys(&self) -> BoxFuture>; + #[rpc(name = "get_staking_addresses")] + fn get_staking_addresses(&self) -> BoxFuture>; /// Bans given node id /// No confirmation to expect. @@ -109,10 +107,6 @@ impl ApiMassaPrivate { } impl MassaPrivate for ApiMassaPrivate { - fn start_node(&self) -> Result<(), PrivateApiError> { - todo!() - } - fn stop_node(&self) -> BoxFuture> { let stop = self.stop_node_channel.clone(); let closure = async move || { @@ -134,13 +128,19 @@ impl MassaPrivate for ApiMassaPrivate { Box::pin(closure()) } - fn add_staking_keys(&self, keys: Vec) -> BoxFuture> { + fn add_staking_private_keys( + &self, + keys: Vec, + ) -> BoxFuture> { let cmd_sender = self.consensus_command_sender.clone(); let closure = async move || Ok(cmd_sender.register_staking_private_keys(keys).await?); Box::pin(closure()) } - fn remove_staking_keys(&self, keys: Vec
) -> BoxFuture> { + fn remove_staking_addresses( + &self, + keys: Vec
, + ) -> BoxFuture> { let cmd_sender = self.consensus_command_sender.clone(); let closure = async move || { Ok(cmd_sender @@ -150,7 +150,7 @@ impl MassaPrivate for ApiMassaPrivate { Box::pin(closure()) } - fn list_staking_keys(&self) -> BoxFuture> { + fn get_staking_addresses(&self) -> BoxFuture> { let cmd_sender = self.consensus_command_sender.clone(); let closure = async move || Ok(cmd_sender.get_staking_addresses().await?); Box::pin(closure()) @@ -166,8 +166,9 @@ impl MassaPrivate for ApiMassaPrivate { let network_command_sender = self.network_command_sender.clone(); let closure = async move || { for ip in ips { - Ok(network_command_sender.unban(ip).await?) + network_command_sender.unban(ip).await? } + Ok(()) }; Box::pin(closure()) } diff --git a/rpc-client/src/cmds.rs b/rpc-client/src/cmds.rs index 751281ae876..40f1b5e2d1f 100644 --- a/rpc-client/src/cmds.rs +++ b/rpc-client/src/cmds.rs @@ -31,6 +31,9 @@ pub enum Command { )] ban, + #[strum(ascii_case_insensitive, message = "start a node")] + node_start, + #[strum(ascii_case_insensitive, message = "stops the node")] node_stop, @@ -127,16 +130,30 @@ pub enum Command { send_transaction, } -macro_rules! repl_error { +macro_rules! repl_err { ($err: expr) => { style(format!("Error: {}", $err)).red().to_string() }; } +macro_rules! repl_ok { + ($ok: expr) => { + $ok.to_string() + }; +} + // TODO: Commands could also not be APIs calls (like Wallet ones) impl Command { pub(crate) fn not_found() -> String { - repl_error!("Command not found!\ntype \"help\" to get the list of commands") + repl_err!("Command not found!\ntype \"help\" to get the list of commands") + } + + pub(crate) fn wrong_parameters(&self) -> String { + repl_err!(format!( + "{} given is not well formed...\ntype \"help {}\" to more info", + self.get_str("args").unwrap(), + self.to_string() + )) } pub(crate) fn help(&self) -> String { @@ -153,64 +170,131 @@ impl Command { ) } - // TODO: should run(...) be impl on Command or on some struct containing clients? - pub(crate) async fn run(&self, client: &Client, parameters: &Vec, json: bool) { + // TODO: Return type should be something like: + // use std::fmt::Display; + // use serde_json::ser::Formatter; + // pub(crate) async fn run(&self, client: &Client, parameters: &Vec) -> T + pub(crate) async fn run(&self, client: &Client, parameters: &Vec) -> String { match self { Command::exit => process::exit(0), + Command::help => { if !parameters.is_empty() { if let Ok(c) = parameters[0].parse::() { - println!("{}", c.help()); + c.help() } else { - println!("{}", Command::not_found()); + Command::not_found() } } else { - cli_help(); + format!( + "HELP of Massa client (list of available commands):\n{}", + Command::iter() + .map(|c| c.help()) + .collect::>() + .join("\n") + ) } } - Command::unban => println!( - "{}", - // TODO: (de)serialize input/output from/to JSON with serde should be less verbose - match IpAddr::from_str(¶meters[0]) { - Ok(ip) => match &client.private.unban(&vec![ip]).await { - Ok(output) => - if json { - serde_json::to_string(output) - .expect("Failed to serialized command output ...") - } else { - "IP successfully unbanned!".to_string() - }, - Err(e) => repl_error!(e), - }, - Err(_) => repl_error!( - "IP given is not well formed...\ntype \"help unban\" to more info" - ), + + Command::unban => match IpAddr::from_str(¶meters[0]) { + Ok(ip) => match &client.private.unban(&vec![ip]).await { + Ok(_) => repl_ok!("Request of unbanning successfully sent!"), + Err(e) => repl_err!(e), + }, + Err(_) => self.wrong_parameters(), + }, + + Command::ban => match serde_json::from_str(¶meters[0]) { + Ok(node_id) => match &client.private.ban(node_id).await { + Ok(_) => repl_ok!("Request of banning successfully sent!"), + Err(e) => repl_err!(e), + }, + Err(_) => self.wrong_parameters(), + }, + + Command::node_start => match process::Command::new("massa-node").spawn() { + Ok(_) => repl_ok!("Node successfully started!"), + Err(e) => repl_err!(e), + }, + + Command::node_stop => match &client.private.stop_node().await { + Ok(_) => repl_ok!("Request of stopping the Node successfully sent"), + Err(e) => repl_err!(e), + }, + + Command::node_get_staking_addresses => { + match &client.private.get_staking_addresses().await { + Ok(output) => serde_json::to_string(output) + .expect("Failed to serialized command output ..."), + Err(e) => repl_err!(e), } - ), - Command::ban => {} - Command::node_stop => {} - Command::node_get_staking_addresses => {} - Command::node_remove_staking_addresses => {} - Command::node_add_staking_private_keys => {} - Command::node_testnet_rewards_program_ownership_proof => {} - Command::get_status => {} - Command::get_addresses_info => {} - Command::get_blocks_info => {} - Command::get_endorsements_info => {} - Command::get_operations_info => {} - Command::wallet_info => {} - Command::wallet_add_private_keys => {} - Command::wallet_remove_addresses => {} - Command::buy_rolls => {} - Command::sell_rolls => {} - Command::send_transaction => {} - } - } -} + } + + Command::node_remove_staking_addresses => match serde_json::from_str(¶meters[0]) { + Ok(addresses) => match &client.private.remove_staking_addresses(addresses).await { + Ok(_) => repl_ok!("Addresses successfully removed!"), + Err(e) => repl_err!(e), + }, + Err(_) => self.wrong_parameters(), + }, + + Command::node_add_staking_private_keys => match serde_json::from_str(¶meters[0]) { + Ok(private_keys) => { + match &client.private.add_staking_private_keys(private_keys).await { + Ok(_) => repl_ok!("Private keys successfully added!"), + Err(e) => repl_err!(e), + } + } + Err(_) => self.wrong_parameters(), + }, + + Command::node_testnet_rewards_program_ownership_proof => { + todo!() + } + + Command::get_status => { + todo!() + } + + Command::get_addresses_info => { + todo!() + } + + Command::get_blocks_info => { + todo!() + } + + Command::get_endorsements_info => { + todo!() + } + + Command::get_operations_info => { + todo!() + } -fn cli_help() { - println!("HELP of Massa client (list of available commands):"); - for c in Command::iter() { - println!("{}", c.help()); + Command::wallet_info => { + todo!() + } + + Command::wallet_add_private_keys => { + todo!() + } + + Command::wallet_remove_addresses => { + todo!() + } + + Command::buy_rolls => { + todo!() + } + + Command::sell_rolls => { + todo!() + } + + Command::send_transaction => { + todo!() + } + } } } diff --git a/rpc-client/src/main.rs b/rpc-client/src/main.rs index 0eab9da7761..b68ec5514ae 100644 --- a/rpc-client/src/main.rs +++ b/rpc-client/src/main.rs @@ -63,7 +63,16 @@ fn main(args: Args) { if atty::is(Stream::Stdout) && args.command == Command::help { repl::run(&client).await; // Interactive mode } else { - args.command.run(&client, &args.parameters, args.json).await; // Non-Interactive mode + let output = args.command.run(&client, &args.parameters).await; // Non-Interactive mode + println!( + "{}", + if args.json { + serde_json::to_string(&output) + .expect("Failed to serialized command output ...") + } else { + output + } + ); } }); } diff --git a/rpc-client/src/repl.rs b/rpc-client/src/repl.rs index c900be51b54..a635d7a521a 100644 --- a/rpc-client/src/repl.rs +++ b/rpc-client/src/repl.rs @@ -38,10 +38,13 @@ pub(crate) async fn run(client: &Client) { let cmd: Result = input[0].parse(); let parameters = input[1..].to_vec(); // Print result of evaluated command - match cmd { - Ok(command) => command.run(client, ¶meters, false).await, - Err(_) => println!("{}", Command::not_found()), - } + println!( + "{}", + match cmd { + Ok(command) => command.run(client, ¶meters).await, + Err(_) => Command::not_found(), + } + ); } } } diff --git a/rpc-client/src/rpc.rs b/rpc-client/src/rpc.rs index 403ccd76fcb..66ebbdfd84e 100644 --- a/rpc-client/src/rpc.rs +++ b/rpc-client/src/rpc.rs @@ -1,12 +1,12 @@ // Copyright (c) 2021 MASSA LABS +use crypto::signature::{PrivateKey, PublicKey, Signature}; use jsonrpc_core_client::transports::http; use jsonrpc_core_client::{RpcChannel, RpcResult, TypedClient}; -use std::net::IpAddr; use models::address::AddressHashSet; -use models::Address; use models::node::NodeId; -use crypto::signature::{PublicKey, Signature, PrivateKey}; +use models::Address; +use std::net::IpAddr; // TODO: This crate should at some point be renamed `client`, `massa` or `massa-client` // and replace the previous one! @@ -56,12 +56,6 @@ impl RpcClient { } } - /// Starts the node and waits for node to start. - /// Signals if the node is already running. - pub(crate) async fn start_node(&self) -> RpcResult<()> { - self.0.call_method("start_node", "()", ()).await - } - /// Gracefully stop the node. pub(crate) async fn stop_node(&self) -> RpcResult<()> { self.0.call_method("stop_node", "()", ()).await @@ -80,24 +74,27 @@ impl RpcClient { /// Add a vec of new private keys for the node to use to stake. /// No confirmation to expect. - pub(crate) async fn add_staking_keys(&self, private_keys: Vec) -> RpcResult<()> { + pub(crate) async fn add_staking_private_keys( + &self, + private_keys: Vec, + ) -> RpcResult<()> { self.0 - .call_method("add_staking_keys", "()", private_keys) + .call_method("add_staking_private_keys", "()", private_keys) .await } /// Remove a vec of addresses used to stake. /// No confirmation to expect. - pub(crate) async fn remove_staking_keys(&self, addresses: Vec
) -> RpcResult<()> { + pub(crate) async fn remove_staking_addresses(&self, addresses: Vec
) -> RpcResult<()> { self.0 - .call_method("remove_staking_keys", "()", addresses) + .call_method("remove_staking_addresses", "()", addresses) .await } /// Return hashset of staking addresses. - pub(crate) async fn list_staking_keys(&self) -> RpcResult { + pub(crate) async fn get_staking_addresses(&self) -> RpcResult { self.0 - .call_method("list_staking_keys", "AddressHashSet", ()) + .call_method("get_staking_addresses", "AddressHashSet", ()) .await }