mirror of
https://github.com/Qortal/piratewallet-light-cli.git
synced 2025-02-07 06:44:11 +00:00
Refactor for library use
This commit is contained in:
parent
79e4b8d0a4
commit
374f50e8e3
@ -1,4 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use json::{object};
|
||||||
|
|
||||||
use crate::LightClient;
|
use crate::LightClient;
|
||||||
|
|
||||||
@ -311,6 +312,31 @@ impl Command for TransactionsCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct HeightCommand {}
|
||||||
|
impl Command for HeightCommand {
|
||||||
|
fn help(&self) -> String {
|
||||||
|
let mut h = vec![];
|
||||||
|
h.push("Get the latest block height that the wallet is at");
|
||||||
|
h.push("Usage:");
|
||||||
|
h.push("height");
|
||||||
|
h.push("");
|
||||||
|
|
||||||
|
h.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn short_help(&self) -> String {
|
||||||
|
"Get the latest block height that the wallet is at".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
|
||||||
|
format!("{}",
|
||||||
|
object! {
|
||||||
|
"height" => lightclient.last_scanned_height()
|
||||||
|
}.pretty(2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct NewAddressCommand {}
|
struct NewAddressCommand {}
|
||||||
impl Command for NewAddressCommand {
|
impl Command for NewAddressCommand {
|
||||||
fn help(&self) -> String {
|
fn help(&self) -> String {
|
||||||
@ -407,6 +433,7 @@ pub fn get_commands() -> Box<HashMap<String, Box<dyn Command>>> {
|
|||||||
map.insert("help".to_string(), Box::new(HelpCommand{}));
|
map.insert("help".to_string(), Box::new(HelpCommand{}));
|
||||||
map.insert("balance".to_string(), Box::new(BalanceCommand{}));
|
map.insert("balance".to_string(), Box::new(BalanceCommand{}));
|
||||||
map.insert("addresses".to_string(), Box::new(AddressCommand{}));
|
map.insert("addresses".to_string(), Box::new(AddressCommand{}));
|
||||||
|
map.insert("height".to_string(), Box::new(HeightCommand{}));
|
||||||
map.insert("export".to_string(), Box::new(ExportCommand{}));
|
map.insert("export".to_string(), Box::new(ExportCommand{}));
|
||||||
map.insert("info".to_string(), Box::new(InfoCommand{}));
|
map.insert("info".to_string(), Box::new(InfoCommand{}));
|
||||||
map.insert("send".to_string(), Box::new(SendCommand{}));
|
map.insert("send".to_string(), Box::new(SendCommand{}));
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::lightwallet::LightWallet;
|
use crate::lightwallet::LightWallet;
|
||||||
|
|
||||||
use log::{info, warn, error};
|
use log::{info, warn, error};
|
||||||
|
|
||||||
use rand::{rngs::OsRng, seq::SliceRandom};
|
use rand::{rngs::OsRng, seq::SliceRandom};
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
@ -328,7 +327,18 @@ impl LightClient {
|
|||||||
|
|
||||||
pub fn do_info(&self) -> String {
|
pub fn do_info(&self) -> String {
|
||||||
match get_info(self.get_server_uri(), self.config.no_cert_verification) {
|
match get_info(self.get_server_uri(), self.config.no_cert_verification) {
|
||||||
Ok(i) => format!("{:?}", i)[11..].to_string(),
|
Ok(i) => {
|
||||||
|
let o = object!{
|
||||||
|
"version" => i.version,
|
||||||
|
"vendor" => i.vendor,
|
||||||
|
"taddr_support" => i.taddr_support,
|
||||||
|
"chain_name" => i.chain_name,
|
||||||
|
"sapling_activation_height" => i.sapling_activation_height,
|
||||||
|
"consensus_branch_id" => i.consensus_branch_id,
|
||||||
|
"latest_block_height" => i.block_height
|
||||||
|
};
|
||||||
|
o.pretty(2)
|
||||||
|
},
|
||||||
Err(e) => e
|
Err(e) => e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
123
src/main.rs
123
src/main.rs
@ -129,57 +129,70 @@ pub fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let dangerous = matches.is_present("dangerous");
|
let dangerous = matches.is_present("dangerous");
|
||||||
|
let nosync = matches.is_present("nosync");
|
||||||
|
|
||||||
// Try to get the configuration
|
let (command_tx, resp_rx) = match startup(server, dangerous, seed, !nosync, command.is_none()) {
|
||||||
let (config, latest_block_height) = match create_lightclient_config(server.clone(), dangerous) {
|
|
||||||
Ok((c, h)) => (c, h),
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Couldn't create config: {}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Configure logging first.
|
|
||||||
let log_config = match get_log_config(&config) {
|
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error:\n{}\nCouldn't configure logging, quitting!", e);
|
eprintln!("Error during startup: {}", e);
|
||||||
|
error!("Error during startup: {}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
log4rs::init_config(log_config).unwrap();
|
|
||||||
|
|
||||||
let lightclient = match create_lightclient(seed, latest_block_height, &config) {
|
if command.is_none() {
|
||||||
Ok(lc) => Arc::new(lc),
|
start_interactive(command_tx, resp_rx);
|
||||||
|
} else {
|
||||||
|
command_tx.send(
|
||||||
|
(command.unwrap().to_string(),
|
||||||
|
params.iter().map(|s| s.to_string()).collect::<Vec<String>>()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match resp_rx.recv() {
|
||||||
|
Ok(s) => println!("{}", s),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Couldn't create Lightclient. {}", e);
|
let e = format!("Error executing command {}: {}", command.unwrap(), e);
|
||||||
error!("Couldn't create Lightclient. {}", e);
|
eprintln!("{}", e);
|
||||||
return;
|
error!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Startup
|
fn startup(server: http::Uri, dangerous: bool, seed: Option<String>, first_sync: bool, print_updates: bool)
|
||||||
|
-> Result<(Sender<(String, Vec<String>)>, Receiver<String>)> {
|
||||||
|
// Try to get the configuration
|
||||||
|
let (config, latest_block_height) = create_lightclient_config(server.clone(), dangerous)?;
|
||||||
|
|
||||||
|
// Configure logging first.
|
||||||
|
let log_config = get_log_config(&config)?;
|
||||||
|
log4rs::init_config(log_config).map_err(|e| {
|
||||||
|
std::io::Error::new(ErrorKind::Other, e)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let lightclient = Arc::new(create_lightclient(seed, latest_block_height, &config)?);
|
||||||
|
|
||||||
|
// Print startup Messages
|
||||||
info!(""); // Blank line
|
info!(""); // Blank line
|
||||||
info!("Starting Zecwallet-CLI");
|
info!("Starting Zecwallet-CLI");
|
||||||
info!("Light Client config {:?}", config);
|
info!("Light Client config {:?}", config);
|
||||||
|
|
||||||
// At startup, run a sync.
|
if print_updates {
|
||||||
let sync_output = if matches.is_present("nosync") {
|
println!("Lightclient connecting to {}", config.server);
|
||||||
None
|
}
|
||||||
} else {
|
|
||||||
Some(lightclient.do_sync(true))
|
|
||||||
};
|
|
||||||
|
|
||||||
if command.is_none() {
|
// Start the command loop
|
||||||
// If running in interactive mode, output of the sync command
|
let (command_tx, resp_rx) = command_loop(lightclient.clone());
|
||||||
if sync_output.is_some() {
|
|
||||||
println!("{}", sync_output.unwrap());
|
// At startup, run a sync.
|
||||||
|
if first_sync {
|
||||||
|
let update = lightclient.do_sync(true);
|
||||||
|
if print_updates {
|
||||||
|
println!("{}", update);
|
||||||
}
|
}
|
||||||
start_interactive(lightclient, &config);
|
|
||||||
} else {
|
|
||||||
let cmd_response = commands::do_user_command(&command.unwrap(), ¶ms, lightclient.as_ref());
|
|
||||||
println!("{}", cmd_response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok((command_tx, resp_rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_lightclient_config(server: http::Uri, dangerous: bool) -> Result<(LightClientConfig, u64)> {
|
fn create_lightclient_config(server: http::Uri, dangerous: bool) -> Result<(LightClientConfig, u64)> {
|
||||||
@ -206,19 +219,34 @@ fn create_lightclient(seed: Option<String>, latest_block: u64, config: &LightCli
|
|||||||
Ok(lightclient)
|
Ok(lightclient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_interactive(lightclient: Arc<LightClient>, config: &LightClientConfig) {
|
fn start_interactive(command_tx: Sender<(String, Vec<String>)>, resp_rx: Receiver<String>) {
|
||||||
// Start the command loop
|
|
||||||
let (command_tx, resp_rx) = command_loop(lightclient.clone(), config);
|
|
||||||
|
|
||||||
// `()` can be used when no completer is required
|
// `()` can be used when no completer is required
|
||||||
let mut rl = Editor::<()>::new();
|
let mut rl = Editor::<()>::new();
|
||||||
|
|
||||||
println!("Ready!");
|
println!("Ready!");
|
||||||
|
|
||||||
|
let send_command = |cmd: String, args: Vec<String>| -> String {
|
||||||
|
command_tx.send((cmd.clone(), args)).unwrap();
|
||||||
|
match resp_rx.recv() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
let e = format!("Error executing command {}: {}", cmd, e);
|
||||||
|
eprintln!("{}", e);
|
||||||
|
error!("{}", e);
|
||||||
|
return "".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let info = &send_command("info".to_string(), vec![]);
|
||||||
|
let chain_name = json::parse(info).unwrap()["chain_name"].as_str().unwrap().to_string();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
// Read the height first
|
||||||
|
let height = json::parse(&send_command("height".to_string(), vec![])).unwrap()["height"].as_i64().unwrap();
|
||||||
|
|
||||||
let readline = rl.readline(&format!("({}) Block:{} (type 'help') >> ",
|
let readline = rl.readline(&format!("({}) Block:{} (type 'help') >> ",
|
||||||
config.chain_name,
|
chain_name, height));
|
||||||
lightclient.last_scanned_height()));
|
|
||||||
match readline {
|
match readline {
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
rl.add_history_entry(line.as_str());
|
rl.add_history_entry(line.as_str());
|
||||||
@ -237,13 +265,8 @@ fn start_interactive(lightclient: Arc<LightClient>, config: &LightClientConfig)
|
|||||||
|
|
||||||
let cmd = cmd_args.remove(0);
|
let cmd = cmd_args.remove(0);
|
||||||
let args: Vec<String> = cmd_args;
|
let args: Vec<String> = cmd_args;
|
||||||
command_tx.send((cmd, args)).unwrap();
|
|
||||||
|
|
||||||
// Wait for the response
|
println!("{}", send_command(cmd, args));
|
||||||
match resp_rx.recv() {
|
|
||||||
Ok(response) => println!("{}", response),
|
|
||||||
_ => { eprintln!("Error receiving response");}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special check for Quit command.
|
// Special check for Quit command.
|
||||||
if line == "quit" {
|
if line == "quit" {
|
||||||
@ -253,13 +276,13 @@ fn start_interactive(lightclient: Arc<LightClient>, config: &LightClientConfig)
|
|||||||
Err(ReadlineError::Interrupted) => {
|
Err(ReadlineError::Interrupted) => {
|
||||||
println!("CTRL-C");
|
println!("CTRL-C");
|
||||||
info!("CTRL-C");
|
info!("CTRL-C");
|
||||||
println!("{}", lightclient.do_save());
|
println!("{}", send_command("save".to_string(), vec![]));
|
||||||
break
|
break
|
||||||
},
|
},
|
||||||
Err(ReadlineError::Eof) => {
|
Err(ReadlineError::Eof) => {
|
||||||
println!("CTRL-D");
|
println!("CTRL-D");
|
||||||
info!("CTRL-D");
|
info!("CTRL-D");
|
||||||
println!("{}", lightclient.do_save());
|
println!("{}", send_command("save".to_string(), vec![]));
|
||||||
break
|
break
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -271,9 +294,7 @@ fn start_interactive(lightclient: Arc<LightClient>, config: &LightClientConfig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn command_loop(lightclient: Arc<LightClient>, config: &LightClientConfig) -> (Sender<(String, Vec<String>)>, Receiver<String>) {
|
fn command_loop(lightclient: Arc<LightClient>) -> (Sender<(String, Vec<String>)>, Receiver<String>) {
|
||||||
println!("Lightclient connecting to {}", config.server);
|
|
||||||
|
|
||||||
let (command_tx, command_rx) = channel::<(String, Vec<String>)>();
|
let (command_tx, command_rx) = channel::<(String, Vec<String>)>();
|
||||||
let (resp_tx, resp_rx) = channel::<String>();
|
let (resp_tx, resp_rx) = channel::<String>();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user