Refactor for library use

This commit is contained in:
Aditya Kulkarni 2019-10-11 12:03:34 -07:00
parent 79e4b8d0a4
commit 374f50e8e3
3 changed files with 117 additions and 59 deletions

View File

@ -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{}));

View File

@ -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
} }
} }

View File

@ -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);
return; error!("Error during startup: {}", e);
}
};
log4rs::init_config(log_config).unwrap();
let lightclient = match create_lightclient(seed, latest_block_height, &config) {
Ok(lc) => Arc::new(lc),
Err(e) => {
eprintln!("Couldn't create Lightclient. {}", e);
error!("Couldn't create Lightclient. {}", e);
return; return;
} }
}; };
// Startup if command.is_none() {
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) => {
let e = format!("Error executing command {}: {}", command.unwrap(), e);
eprintln!("{}", e);
error!("{}", e);
}
}
}
}
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() {
// If running in interactive mode, output of the sync command
if sync_output.is_some() {
println!("{}", sync_output.unwrap());
}
start_interactive(lightclient, &config);
} else {
let cmd_response = commands::do_user_command(&command.unwrap(), &params, lightclient.as_ref());
println!("{}", cmd_response);
} }
// Start the command loop
let (command_tx, resp_rx) = command_loop(lightclient.clone());
// At startup, run a sync.
if first_sync {
let update = lightclient.do_sync(true);
if print_updates {
println!("{}", update);
}
}
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());
@ -236,14 +264,9 @@ 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>();