main() refactoring

This commit is contained in:
veeso
2021-07-08 16:21:39 +02:00
parent 37abe596c7
commit e15b79750b

View File

@@ -38,9 +38,9 @@ extern crate magic_crypt;
extern crate rpassword; extern crate rpassword;
// External libs // External libs
use getopts::Options; use getopts::{Matches, Options};
use std::env; use std::env;
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
// Include // Include
@@ -59,31 +59,43 @@ use activity_manager::{ActivityManager, NextActivity};
use filetransfer::FileTransferProtocol; use filetransfer::FileTransferProtocol;
use system::logging; use system::logging;
/// ### print_usage enum Task {
/// Activity(NextActivity),
/// Print usage ImportTheme(PathBuf),
}
fn print_usage(opts: Options) { struct RunOpts {
let brief = String::from( address: Option<String>,
"Usage: termscp [options]... [protocol://user@address:port:wrkdir] [local-wrkdir]", port: u16,
); username: Option<String>,
print!("{}", opts.usage(&brief)); password: Option<String>,
println!("\nPlease, report issues to <https://github.com/veeso/termscp>"); remote_wrkdir: Option<PathBuf>,
println!("Please, consider supporting the author <https://www.buymeacoffee.com/veeso>") protocol: FileTransferProtocol,
ticks: Duration,
log_enabled: bool,
task: Task,
}
impl Default for RunOpts {
fn default() -> Self {
Self {
address: None,
port: 22,
username: None,
password: None,
remote_wrkdir: None,
protocol: FileTransferProtocol::Sftp,
ticks: Duration::from_millis(10),
log_enabled: true,
task: Task::Activity(NextActivity::Authentication),
}
}
} }
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
//Program CLI options //Program CLI options
let mut address: Option<String> = None; // None let mut run_opts: RunOpts = RunOpts::default();
let mut port: u16 = 22; // Default port
let mut username: Option<String> = None; // Default username
let mut password: Option<String> = None; // Default password
let mut remote_wrkdir: Option<PathBuf> = None;
let mut protocol: FileTransferProtocol = FileTransferProtocol::Sftp; // Default protocol
let mut ticks: Duration = Duration::from_millis(10);
let mut log_enabled: bool = true;
let mut start_activity: NextActivity = NextActivity::Authentication;
//Process options //Process options
let mut opts = Options::new(); let mut opts = Options::new();
opts.optflag("c", "config", "Open termscp configuration"); opts.optflag("c", "config", "Open termscp configuration");
@@ -93,81 +105,113 @@ fn main() {
opts.optopt("T", "ticks", "Set UI ticks; default 10ms", "<ms>"); opts.optopt("T", "ticks", "Set UI ticks; default 10ms", "<ms>");
opts.optflag("v", "version", ""); opts.optflag("v", "version", "");
opts.optflag("h", "help", "Print this menu"); opts.optflag("h", "help", "Print this menu");
let matches = match opts.parse(&args[1..]) { let matches: Matches = match opts.parse(&args[1..]) {
Ok(m) => m, Ok(m) => m,
Err(f) => { Err(f) => {
println!("{}", f.to_string()); println!("{}", f.to_string());
std::process::exit(255); std::process::exit(255);
} }
}; };
// Help // Parse args
if matches.opt_present("h") { if let Err(err) = parse_run_opts(&mut run_opts, matches) {
print_usage(opts); if let Some(err) = err {
eprintln!("{}", err);
} else {
print_usage(opts);
}
std::process::exit(255); std::process::exit(255);
} }
// Setup logging
if run_opts.log_enabled {
if let Err(err) = logging::init() {
eprintln!("Failed to initialize logging: {}", err);
}
}
// Read password from remote
if let Err(err) = read_password(&mut run_opts) {
eprintln!("{}", err);
std::process::exit(255);
}
info!("termscp {} started!", TERMSCP_VERSION);
// Run
info!("Starting activity manager...");
let rc: i32 = run(run_opts);
info!("termscp terminated");
// Then return
std::process::exit(rc);
}
/// ### print_usage
///
/// Print usage
fn print_usage(opts: Options) {
let brief = String::from(
"Usage: termscp [options]... [protocol://user@address:port:wrkdir] [local-wrkdir]",
);
print!("{}", opts.usage(&brief));
println!("\nPlease, report issues to <https://github.com/veeso/termscp>");
println!("Please, consider supporting the author <https://www.buymeacoffee.com/veeso>")
}
/// ### parse_run_opts
///
/// Parse run options; in case something is wrong returns the error message
fn parse_run_opts(run_opts: &mut RunOpts, opts: Matches) -> Result<(), Option<String>> {
// Help
if opts.opt_present("h") {
return Err(None);
}
// Version // Version
if matches.opt_present("v") { if opts.opt_present("v") {
eprintln!( return Err(Some(format!(
"termscp - {} - Developed by {}", "termscp - {} - Developed by {}",
TERMSCP_VERSION, TERMSCP_AUTHORS, TERMSCP_VERSION, TERMSCP_AUTHORS,
); )));
std::process::exit(255);
} }
// Setup activity? // Setup activity?
if matches.opt_present("c") { if opts.opt_present("c") {
start_activity = NextActivity::SetupActivity; run_opts.task = Task::Activity(NextActivity::SetupActivity);
} }
// Logging // Logging
if matches.opt_present("q") { if opts.opt_present("q") {
log_enabled = false; run_opts.log_enabled = false;
} }
// Match password // Match password
if let Some(passwd) = matches.opt_str("P") { if let Some(passwd) = opts.opt_str("P") {
password = Some(passwd); run_opts.password = Some(passwd);
} }
// Match ticks // Match ticks
if let Some(val) = matches.opt_str("T") { if let Some(val) = opts.opt_str("T") {
match val.parse::<usize>() { match val.parse::<usize>() {
Ok(val) => ticks = Duration::from_millis(val as u64), Ok(val) => run_opts.ticks = Duration::from_millis(val as u64),
Err(_) => { Err(_) => {
eprintln!("Ticks is not a number '{}'", val); return Err(Some(format!("Ticks is not a number: '{}'", val)));
print_usage(opts);
std::process::exit(255);
} }
} }
} }
// @! extra modes // @! extra modes
if let Some(theme) = matches.opt_str("t") { if let Some(theme) = opts.opt_str("t") {
match support::import_theme(Path::new(theme.as_str())) { run_opts.task = Task::ImportTheme(PathBuf::from(theme));
Ok(_) => {
println!("Theme has been successfully imported!");
std::process::exit(0)
}
Err(err) => {
eprintln!("{}", err);
std::process::exit(1);
}
}
} }
// @! Ordinary mode // @! Ordinary mode
// Check free args // Check free args
let extra_args: Vec<String> = matches.free; let extra_args: Vec<String> = opts.free;
// Remote argument // Remote argument
if let Some(remote) = extra_args.get(0) { if let Some(remote) = extra_args.get(0) {
// Parse address // Parse address
match utils::parser::parse_remote_opt(remote) { match utils::parser::parse_remote_opt(remote) {
Ok(host_opts) => { Ok(host_opts) => {
// Set params // Set params
address = Some(host_opts.hostname); run_opts.address = Some(host_opts.hostname);
port = host_opts.port; run_opts.port = host_opts.port;
protocol = host_opts.protocol; run_opts.protocol = host_opts.protocol;
username = host_opts.username; run_opts.username = host_opts.username;
remote_wrkdir = host_opts.wrkdir; run_opts.remote_wrkdir = host_opts.wrkdir;
// In this case the first activity will be FileTransfer
run_opts.task = Task::Activity(NextActivity::FileTransfer);
} }
Err(err) => { Err(err) => {
eprintln!("Bad address option: {}", err); return Err(Some(format!("Bad address option: {}", err)));
print_usage(opts);
std::process::exit(255);
} }
} }
} }
@@ -176,64 +220,85 @@ fn main() {
// Change working directory if local dir is set // Change working directory if local dir is set
let localdir: PathBuf = PathBuf::from(localdir); let localdir: PathBuf = PathBuf::from(localdir);
if let Err(err) = env::set_current_dir(localdir.as_path()) { if let Err(err) = env::set_current_dir(localdir.as_path()) {
eprintln!("Bad working directory argument: {}", err); return Err(Some(format!("Bad working directory argument: {}", err)));
std::process::exit(255);
} }
} }
// Get working directory Ok(())
let wrkdir: PathBuf = match env::current_dir() { }
Ok(dir) => dir,
Err(_) => PathBuf::from("/"), /// ### read_password
}; ///
// Setup logging /// Read password from tty if address is specified
if log_enabled { fn read_password(run_opts: &mut RunOpts) -> Result<(), String> {
if let Err(err) = logging::init() {
eprintln!("Failed to initialize logging: {}", err);
}
}
info!("termscp {} started!", TERMSCP_VERSION);
// Initialize client if necessary // Initialize client if necessary
if address.is_some() { if run_opts.address.is_some() {
debug!("User has specified remote options: address: {:?}, port: {:?}, protocol: {:?}, user: {:?}, password: {}", address, port, protocol, username, utils::fmt::shadow_password(password.as_deref().unwrap_or(""))); debug!("User has specified remote options: address: {:?}, port: {:?}, protocol: {:?}, user: {:?}, password: {}", run_opts.address, run_opts.port, run_opts.protocol, run_opts.username, utils::fmt::shadow_password(run_opts.password.as_deref().unwrap_or("")));
if password.is_none() { if run_opts.password.is_none() {
// Ask password if unspecified // Ask password if unspecified
password = match rpassword::read_password_from_tty(Some("Password: ")) { run_opts.password = match rpassword::read_password_from_tty(Some("Password: ")) {
Ok(p) => { Ok(p) => {
if p.is_empty() { if p.is_empty() {
None None
} else { } else {
debug!(
"Read password from tty: {}",
utils::fmt::shadow_password(p.as_str())
);
Some(p) Some(p)
} }
} }
Err(_) => { Err(_) => {
eprintln!("Could not read password from prompt"); return Err("Could not read password from prompt".to_string());
std::process::exit(255);
} }
}; };
debug!(
"Read password from tty: {}",
utils::fmt::shadow_password(password.as_deref().unwrap_or(""))
);
} }
// In this case the first activity will be FileTransfer
start_activity = NextActivity::FileTransfer;
} }
// Create activity manager (and context too) Ok(())
let mut manager: ActivityManager = match ActivityManager::new(&wrkdir, ticks) { }
Ok(m) => m,
Err(err) => { /// ### run
eprintln!("Could not start activity manager: {}", err); ///
std::process::exit(255); /// Run task and return rc
} fn run(mut run_opts: RunOpts) -> i32 {
}; match run_opts.task {
// Set file transfer params if set Task::ImportTheme(theme) => match support::import_theme(theme.as_path()) {
if let Some(address) = address { Ok(_) => {
manager.set_filetransfer_params(address, port, protocol, username, password, remote_wrkdir); println!("Theme has been successfully imported!");
} 0
// Run }
info!("Starting activity manager..."); Err(err) => {
manager.run(start_activity); eprintln!("{}", err);
info!("termscp terminated"); 1
// Then return }
std::process::exit(0); },
Task::Activity(activity) => {
// Get working directory
let wrkdir: PathBuf = match env::current_dir() {
Ok(dir) => dir,
Err(_) => PathBuf::from("/"),
};
// Create activity manager (and context too)
let mut manager: ActivityManager =
match ActivityManager::new(wrkdir.as_path(), run_opts.ticks) {
Ok(m) => m,
Err(err) => {
eprintln!("Could not start activity manager: {}", err);
return 1;
}
};
// Set file transfer params if set
if let Some(address) = run_opts.address.take() {
manager.set_filetransfer_params(
address,
run_opts.port,
run_opts.protocol,
run_opts.username,
run_opts.password,
run_opts.remote_wrkdir,
);
}
manager.run(activity);
0
}
}
} }