Browse Source

Refactor for library use

checkpoints
Aditya Kulkarni 5 years ago
parent
commit
374f50e8e3
  1. 27
      src/commands.rs
  2. 14
      src/lightclient.rs
  3. 127
      src/main.rs

27
src/commands.rs

@ -1,4 +1,5 @@
use std::collections::HashMap;
use json::{object};
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 {}
impl Command for NewAddressCommand {
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("balance".to_string(), Box::new(BalanceCommand{}));
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("info".to_string(), Box::new(InfoCommand{}));
map.insert("send".to_string(), Box::new(SendCommand{}));

14
src/lightclient.rs

@ -1,7 +1,6 @@
use crate::lightwallet::LightWallet;
use log::{info, warn, error};
use rand::{rngs::OsRng, seq::SliceRandom};
use std::sync::{Arc, RwLock};
@ -328,7 +327,18 @@ impl LightClient {
pub fn do_info(&self) -> String {
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
}
}

127
src/main.rs

@ -129,57 +129,70 @@ pub fn main() {
}
let dangerous = matches.is_present("dangerous");
let nosync = matches.is_present("nosync");
// Try to get the configuration
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) {
let (command_tx, resp_rx) = match startup(server, dangerous, seed, !nosync, command.is_none()) {
Ok(c) => c,
Err(e) => {
eprintln!("Error:\n{}\nCouldn't configure logging, quitting!", e);
eprintln!("Error during startup: {}", e);
error!("Error during startup: {}", e);
return;
}
};
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;
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)
})?;
// Startup
let lightclient = Arc::new(create_lightclient(seed, latest_block_height, &config)?);
// Print startup Messages
info!(""); // Blank line
info!("Starting Zecwallet-CLI");
info!("Light Client config {:?}", config);
// At startup, run a sync.
let sync_output = if matches.is_present("nosync") {
None
} else {
Some(lightclient.do_sync(true))
};
if print_updates {
println!("Lightclient connecting to {}", config.server);
}
if command.is_none() {
// If running in interactive mode, output of the sync command
if sync_output.is_some() {
println!("{}", sync_output.unwrap());
// 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);
}
start_interactive(lightclient, &config);
} else {
let cmd_response = commands::do_user_command(&command.unwrap(), &params, lightclient.as_ref());
println!("{}", cmd_response);
}
Ok((command_tx, resp_rx))
}
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)
}
fn start_interactive(lightclient: Arc<LightClient>, config: &LightClientConfig) {
// Start the command loop
let (command_tx, resp_rx) = command_loop(lightclient.clone(), config);
fn start_interactive(command_tx: Sender<(String, Vec<String>)>, resp_rx: Receiver<String>) {
// `()` can be used when no completer is required
let mut rl = Editor::<()>::new();
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 {
// 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') >> ",
config.chain_name,
lightclient.last_scanned_height()));
chain_name, height));
match readline {
Ok(line) => {
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 args: Vec<String> = cmd_args;
command_tx.send((cmd, args)).unwrap();
let args: Vec<String> = cmd_args;
// Wait for the response
match resp_rx.recv() {
Ok(response) => println!("{}", response),
_ => { eprintln!("Error receiving response");}
}
println!("{}", send_command(cmd, args));
// Special check for Quit command.
if line == "quit" {
@ -253,13 +276,13 @@ fn start_interactive(lightclient: Arc<LightClient>, config: &LightClientConfig)
Err(ReadlineError::Interrupted) => {
println!("CTRL-C");
info!("CTRL-C");
println!("{}", lightclient.do_save());
println!("{}", send_command("save".to_string(), vec![]));
break
},
Err(ReadlineError::Eof) => {
println!("CTRL-D");
info!("CTRL-D");
println!("{}", lightclient.do_save());
println!("{}", send_command("save".to_string(), vec![]));
break
},
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>) {
println!("Lightclient connecting to {}", config.server);
fn command_loop(lightclient: Arc<LightClient>) -> (Sender<(String, Vec<String>)>, Receiver<String>) {
let (command_tx, command_rx) = channel::<(String, Vec<String>)>();
let (resp_tx, resp_rx) = channel::<String>();

Loading…
Cancel
Save