Too many things to do here... working on activity manager

This commit is contained in:
ChristianVisintin
2020-11-22 15:32:44 +01:00
parent d7c20aa0c5
commit d692cdf28d
4 changed files with 255 additions and 12 deletions

106
src/activity_manager.rs Normal file
View File

@@ -0,0 +1,106 @@
//! ## ActivityManager
//!
//! `activity_manager` is the module which provides run methods and handling for activities
/*
*
* Copyright (C) 2020 Christian Visintin - christian.visintin1997@gmail.com
*
* This file is part of "TermSCP"
*
* TermSCP is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* TermSCP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with TermSCP. If not, see <http://www.gnu.org/licenses/>.
*
*/
use std::path::PathBuf;
// Deps
use crate::filetransfer::FileTransfer;
use crate::host::Localhost;
use crate::ui::activities::{auth_activity::AuthActivity, auth_activity::ScpProtocol, Activity};
use crate::ui::context::Context;
/// ### NextActivity
///
/// NextActivity identified the next identity to run once the current has ended
pub enum NextActivity {
Authentication,
FileTransfer,
}
/// ### FileTransferParams
///
/// Holds connection parameters for file transfers
struct FileTransferParams {
address: String,
port: u16,
protocol: ScpProtocol,
username: Option<String>,
password: Option<String>,
}
/// ### ActivityManager
///
/// The activity manager takes care of running activities and handling them until the application has ended
pub struct ActivityManager {
context: Context,
ftparams: Option<FileTransferParams>,
}
impl ActivityManager {
/// ### new
///
/// Initializes a new Activity Manager
pub fn new(client: Box<dyn FileTransfer>, local_dir: &PathBuf) -> Result<ActivityManager, ()> {
// Prepare Context
let host: Localhost = match Localhost::new(local_dir.clone()) {
Ok(h) => h,
Err(_) => return Err(()),
};
let ctx: Context = Context::new(client, host);
Ok(ActivityManager {
context: ctx,
ftparams: None,
})
}
/// ### set_filetransfer_params
///
/// Set file transfer params
pub fn set_filetransfer_params(
&mut self,
address: String,
port: u16,
protocol: ScpProtocol,
username: Option<String>,
password: Option<String>,
) {
self.ftparams = Some(FileTransferParams {
address: address,
port: port,
protocol: protocol,
username: username,
password: password,
});
}
/// ### run
///
///
/// Loop for activity manager. You need to provide the activity to start with
/// Returns the exitcode
pub fn run(&mut self, launch_activity: NextActivity) -> i32 {
0
}
}

View File

@@ -19,6 +19,7 @@
* *
*/ */
pub mod activity_manager;
pub mod filetransfer; pub mod filetransfer;
pub mod fs; pub mod fs;
pub mod host; pub mod host;

View File

@@ -28,31 +28,44 @@ extern crate getopts;
// External libs // External libs
use getopts::Options; use getopts::Options;
use std::env; use std::env;
use std::path::PathBuf;
use std::time::Duration;
// Include // Include
mod activity_manager;
mod filetransfer; mod filetransfer;
mod fs; mod fs;
mod host; mod host;
mod ui;
mod utils;
// namespaces
use activity_manager::{ActivityManager, NextActivity};
use filetransfer::{FileTransfer, sftp_transfer::SftpFileTransfer};
use ui::activities::auth_activity::ScpProtocol;
/// ### print_usage /// ### print_usage
/// ///
/// Print usage /// Print usage
fn print_usage(opts: Options) { fn print_usage(opts: Options) {
let brief = format!("Usage: termscp [Options]... Remote"); let brief = format!("Usage: termscp [Options]... [protocol:user@address:port]");
print!("{}", opts.usage(&brief)); print!("{}", opts.usage(&brief));
} }
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
//Program CLI options //Program CLI options
// TODO: insert opts here let mut address: Option<String> = None; // None
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 protocol: ScpProtocol = ScpProtocol::Sftp; // Default protocol
let mut ticks: Duration = Duration::from_micros(50);
//Process options //Process options
// FIXME: there is no way to provide password from CLI atm
let mut opts = Options::new(); let mut opts = Options::new();
// opts.optopt("c", "command", "Specify command to run. Shell returns after running the command", "<command>"); opts.optopt("T", "ticks", "Set UI ticks; default 50µs", "<µs>");
// opts.optopt("C", "config", "Specify YAML configuration file", "<config>");
// opts.optopt("l", "lang", "Specify shell language", "<ru|рус>");
// opts.optopt("s", "shell", "Force the shell binary path", "</bin/bash>");
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 = match opts.parse(&args[1..]) {
@@ -75,6 +88,89 @@ fn main() {
); );
std::process::exit(255); std::process::exit(255);
} }
// TODO: ... // Match protocol first
std::process::exit(0); if let Some(val) = matches.opt_str("P") {
match val.as_str() {
"sftp" => {
protocol = ScpProtocol::Sftp;
// Set port to 22 as default
port = 22;
// Set default username to current
username = Some(whoami::username());
}
"ftp" => {
protocol = ScpProtocol::Ftp;
// Set port to 21
port = 21;
}
_ => {
eprintln!("Unknown protocol '{}'", val);
print_usage(opts);
std::process::exit(255);
}
}
}
// Match ticks
if let Some(val) = matches.opt_str("T") {
match val.parse::<usize>() {
Ok(val) => ticks = Duration::from_micros(val as u64),
Err(_) => {
eprintln!("Ticks is not a number '{}'", val);
print_usage(opts);
std::process::exit(255);
}
}
}
// Check free args
let extra_args: Vec<String> = matches.free.clone();
if let Some(remote) = extra_args.get(0) {
// Parse address
match utils::parse_remote_opt(remote) {
Ok((addr, portn, proto, user)) => {
// Set params
address = Some(addr);
port = portn;
protocol = proto;
username = user;
},
Err(err) => {
eprintln!("Bad address option: {}", err);
print_usage(opts);
std::process::exit(255);
}
}
}
// Prepare file transfer
let file_transfer: Box<dyn FileTransfer> = match protocol {
ScpProtocol::Sftp => Box::new(SftpFileTransfer::new()),
_ => {
// FIXME: complete with ftp client
eprintln!("Unsupported protocol!");
std::process::exit(255);
}
};
// Get working directory
let wrkdir: PathBuf = match env::current_dir() {
Ok(dir) => dir,
Err(_) => PathBuf::from("/")
};
// Create activity manager
let mut manager: ActivityManager = match ActivityManager::new(file_transfer, &wrkdir) {
Ok(m) => m,
Err(_) => {
eprintln!("Invalid directory '{}'", wrkdir.display());
std::process::exit(255);
}
};
// Initialize client if necessary
let mut start_activity: NextActivity = NextActivity::Authentication;
if let Some(address) = address {
// In this case the first activity will be FileTransfer
start_activity = NextActivity::FileTransfer;
manager.set_filetransfer_params(address, port, protocol, username, password);
}
// Run
let rc: i32 = manager.run(start_activity);
// Then return
std::process::exit(rc);
} }

View File

@@ -33,9 +33,14 @@ use super::{Activity, Context};
// Includes // Includes
use crossterm::event::Event as InputEvent; use crossterm::event::Event as InputEvent;
use crossterm::event::{KeyCode, KeyEvent}; use crossterm::event::{KeyCode, KeyEvent};
use tui::layout; use tui::{
use tui::style; backend::CrosstermBackend,
use tui::widgets; layout::{Constraint, Direction, Layout},
style::{Color, Modifier, Style},
text::{Span, Spans, Text},
widgets::{Block, Borders, List, ListItem, Paragraph},
Terminal,
};
/// ### InputField /// ### InputField
/// ///
@@ -52,6 +57,7 @@ enum InputField {
/// ### ScpProtocol /// ### ScpProtocol
/// ///
/// ScpProtocol describes the communication protocol selected by the user to communicate with the remote /// ScpProtocol describes the communication protocol selected by the user to communicate with the remote
#[derive(std::cmp::PartialEq, std::fmt::Debug)]
pub enum ScpProtocol { pub enum ScpProtocol {
Sftp, Sftp,
Ftp, Ftp,
@@ -147,6 +153,7 @@ impl Activity for AuthActivity {
} }
// Everything OK, set enter // Everything OK, set enter
self.form_submit = true; self.form_submit = true;
popup = Some(format!("Connecting to {}:{}...", self.address, self.port));
} }
KeyCode::Backspace => { KeyCode::Backspace => {
// Pop last char // Pop last char
@@ -225,7 +232,40 @@ impl Activity for AuthActivity {
} }
} }
} }
// TODO: draw interface // draw interface
context.terminal.draw(|f| {
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(2)
.constraints(
[
Constraint::Length(1),
Constraint::Length(3),
Constraint::Min(1),
]
.as_ref(),
)
.split(f.size());
// Write header
let (header, h_style) = (
vec![
Span::raw("Press "),
Span::styled("<ESC>", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" to exit, "),
Span::styled("<UP,DOWN>", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" to change input field,"),
Span::styled("<ENTER>", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" to submit form"),
],
Style::default().add_modifier(Modifier::RAPID_BLINK),
);
let mut header_text = Text::from(Spans::from(header));
header_text.patch_style(h_style);
let header_message = Paragraph::new(header_text);
f.render_widget(header_message, chunks[0]);
// Create input fields
// TODO:
});
} }
/// ### on_destroy /// ### on_destroy