mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
main() refactoring
This commit is contained in:
273
src/main.rs
273
src/main.rs
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user