-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
3867: refactor: use clap as a commands parser r=sdbondi a=DenisKolodin Description --- The PR refactors replace our own parser with a derived by the `clap` crate. It also adds the `watch` command, and avoids unexpected status printing. Motivation and Context --- Improve the user experience of the node's shell. Simplify maintenance and adding new commands. Also periodically status prnting breaks the rustyline and prompt chars not printed properly. How Has This Been Tested? --- Manually 3892: chore: add license info missing from some crates r=sdbondi a=delta1 Description --- Adds the BSD-3-Clause license field to our crates that were missing license info Co-authored-by: Denis Kolodin <deniskolodin@gmail.com> Co-authored-by: Byron Hambly <bizzle@tari.com>
- Loading branch information
Showing
53 changed files
with
2,355 additions
and
1,812 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1 @@ | ||
use std::{ | ||
iter::Peekable, | ||
str::{FromStr, SplitWhitespace}, | ||
}; | ||
|
||
use tari_utilities::hex::{Hex, HexError}; | ||
use thiserror::Error; | ||
|
||
#[derive(Debug, Error)] | ||
#[error("{name} {reason}")] | ||
pub struct ArgsError { | ||
name: &'static str, | ||
reason: ArgsReason, | ||
} | ||
|
||
impl ArgsError { | ||
pub fn new(name: &'static str, reason: impl Into<ArgsReason>) -> Self { | ||
Self { | ||
name, | ||
reason: reason.into(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Error)] | ||
pub enum ArgsReason { | ||
#[error("argument required")] | ||
Required, | ||
#[error("argument can't be parsed: {details}")] | ||
NotParsed { details: String }, | ||
#[error("argument is not valid: {description}")] | ||
Inconsistent { description: String }, | ||
} | ||
|
||
impl<T: AsRef<str>> From<T> for ArgsReason { | ||
fn from(value: T) -> Self { | ||
Self::Inconsistent { | ||
description: value.as_ref().to_owned(), | ||
} | ||
} | ||
} | ||
|
||
pub struct Args<'a> { | ||
splitted: Peekable<SplitWhitespace<'a>>, | ||
} | ||
|
||
impl<'a> Args<'a> { | ||
pub fn split(s: &'a str) -> Self { | ||
Self { | ||
splitted: s.split_whitespace().peekable(), | ||
} | ||
} | ||
|
||
// TODO: Remove | ||
pub fn shift_one(&mut self) { | ||
self.splitted.next(); | ||
} | ||
|
||
// TODO: Use `next` always | ||
pub fn try_take_next<T>(&mut self, name: &'static str) -> Result<Option<T>, ArgsError> | ||
where | ||
T: FromStr, | ||
T::Err: ToString, | ||
{ | ||
match self.splitted.peek().map(|s| s.parse()) { | ||
Some(Ok(value)) => Ok(Some(value)), | ||
Some(Err(err)) => Err(ArgsError::new(name, ArgsReason::NotParsed { | ||
details: err.to_string(), | ||
})), | ||
None => Ok(None), | ||
} | ||
} | ||
|
||
pub fn take_next<T>(&mut self, name: &'static str) -> Result<T, ArgsError> | ||
where | ||
T: FromStr, | ||
T::Err: ToString, | ||
{ | ||
match self.try_take_next(name)? { | ||
Some(value) => { | ||
self.shift_one(); | ||
Ok(value) | ||
}, | ||
None => Err(ArgsError::new(name, ArgsReason::Required)), | ||
} | ||
} | ||
} | ||
|
||
pub struct FromHex<T>(pub T); | ||
|
||
impl<T: Hex> FromStr for FromHex<T> { | ||
type Err = HexError; | ||
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
T::from_hex(s).map(Self) | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
applications/tari_base_node/src/commands/command/ban_peer.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use std::time::Duration; | ||
|
||
use anyhow::Error; | ||
use async_trait::async_trait; | ||
use clap::Parser; | ||
use tari_app_utilities::utilities::UniNodeId; | ||
use tari_comms::peer_manager::NodeId; | ||
|
||
use super::{CommandContext, HandleCommand}; | ||
use crate::LOG_TARGET; | ||
|
||
/// Bans a peer | ||
#[derive(Debug, Parser)] | ||
pub struct ArgsBan { | ||
/// hex public key or emoji id | ||
node_id: UniNodeId, | ||
/// length of time to ban the peer for in seconds | ||
#[clap(default_value_t = std::u64::MAX)] | ||
length: u64, | ||
} | ||
|
||
/// Removes a peer ban | ||
#[derive(Debug, Parser)] | ||
pub struct ArgsUnban { | ||
/// hex public key or emoji id | ||
node_id: UniNodeId, | ||
/// length of time to ban the peer for in seconds | ||
#[clap(default_value_t = std::u64::MAX)] | ||
length: u64, | ||
} | ||
|
||
#[async_trait] | ||
impl HandleCommand<ArgsBan> for CommandContext { | ||
async fn handle_command(&mut self, args: ArgsBan) -> Result<(), Error> { | ||
let node_id = args.node_id.into(); | ||
let duration = Duration::from_secs(args.length); | ||
self.ban_peer(node_id, duration, true).await | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl HandleCommand<ArgsUnban> for CommandContext { | ||
async fn handle_command(&mut self, args: ArgsUnban) -> Result<(), Error> { | ||
let node_id = args.node_id.into(); | ||
let duration = Duration::from_secs(args.length); | ||
self.ban_peer(node_id, duration, false).await | ||
} | ||
} | ||
|
||
impl CommandContext { | ||
pub async fn ban_peer(&mut self, node_id: NodeId, duration: Duration, must_ban: bool) -> Result<(), Error> { | ||
if self.base_node_identity.node_id() == &node_id { | ||
println!("Cannot ban our own node"); | ||
} else if must_ban { | ||
// TODO: Use errors | ||
match self | ||
.connectivity | ||
.ban_peer_until(node_id.clone(), duration, "UI manual ban".to_string()) | ||
.await | ||
{ | ||
Ok(_) => println!("Peer was banned in base node."), | ||
Err(err) => { | ||
println!("Failed to ban peer: {:?}", err); | ||
log::error!(target: LOG_TARGET, "Could not ban peer: {:?}", err); | ||
}, | ||
} | ||
} else { | ||
match self.peer_manager.unban_peer(&node_id).await { | ||
Ok(_) => { | ||
println!("Peer ban was removed from base node."); | ||
}, | ||
Err(err) if err.is_peer_not_found() => { | ||
println!("Peer not found in base node"); | ||
}, | ||
Err(err) => { | ||
println!("Failed to ban peer: {:?}", err); | ||
log::error!(target: LOG_TARGET, "Could not ban peer: {:?}", err); | ||
}, | ||
} | ||
} | ||
Ok(()) | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
applications/tari_base_node/src/commands/command/block_timing.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
use anyhow::Error; | ||
use async_trait::async_trait; | ||
use clap::Parser; | ||
use tari_core::blocks::BlockHeader; | ||
|
||
use super::{CommandContext, HandleCommand}; | ||
|
||
/// Calculates the maximum, minimum, and average time taken to mine a given range of blocks | ||
#[derive(Debug, Parser)] | ||
pub struct Args { | ||
/// number of blocks from chain tip or start height | ||
start: u64, | ||
/// end height | ||
end: Option<u64>, | ||
} | ||
|
||
#[async_trait] | ||
impl HandleCommand<Args> for CommandContext { | ||
async fn handle_command(&mut self, args: Args) -> Result<(), Error> { | ||
// TODO: is that possible to validate it with clap? | ||
if args.end.is_none() && args.start < 2 { | ||
Err(Error::msg("Number of headers must be at least 2.")) | ||
} else { | ||
self.block_timing(args.start, args.end).await | ||
} | ||
} | ||
} | ||
|
||
impl CommandContext { | ||
pub async fn block_timing(&self, start: u64, end: Option<u64>) -> Result<(), Error> { | ||
let headers = self.get_chain_headers(start, end).await?; | ||
if !headers.is_empty() { | ||
let headers = headers.into_iter().map(|ch| ch.into_header()).rev().collect::<Vec<_>>(); | ||
let (max, min, avg) = BlockHeader::timing_stats(&headers); | ||
println!( | ||
"Timing for blocks #{} - #{}", | ||
headers.first().unwrap().height, | ||
headers.last().unwrap().height | ||
); | ||
println!("Max block time: {}", max); | ||
println!("Min block time: {}", min); | ||
println!("Avg block time: {}", avg); | ||
} else { | ||
println!("No headers found"); | ||
} | ||
Ok(()) | ||
} | ||
} |
Oops, something went wrong.