replace '~' with absolute path & removed unnecessary return traits

This commit is contained in:
17ms 2023-05-28 19:27:17 +03:00
parent ba0678c149
commit 91f1a6d69f
5 changed files with 85 additions and 37 deletions

View File

@ -130,7 +130,7 @@ impl Client {
debug!("File '{}': {} bytes remaining", file.hash, remaining); debug!("File '{}': {} bytes remaining", file.hash, remaining);
} }
let check_hash = crypto::try_hash(&path)?; let check_hash = crypto::try_hash(&path).unwrap();
let msg = check_hash.as_bytes().to_vec(); let msg = check_hash.as_bytes().to_vec();
handler.send(&msg).await?; handler.send(&msg).await?;

View File

@ -102,7 +102,7 @@ impl Crypto {
} }
} }
pub fn try_hash(path: &Path) -> Result<String, Box<dyn Error + Send + Sync>> { pub fn try_hash(path: &Path) -> Result<String, Box<dyn Error>> {
debug!("Calculating SHA hash"); debug!("Calculating SHA hash");
let hash = sha256::try_digest(path)?; let hash = sha256::try_digest(path)?;

View File

@ -6,9 +6,10 @@ use contego::{
client::Client, client::Client,
parser::{addr_parser, dirpath_parser, filepath_parser}, parser::{addr_parser, dirpath_parser, filepath_parser},
server::Server, server::Server,
util::{filepaths, metadata, Ip}, util::{filepaths, handle_exit, metadata, Ip},
}; };
use env_logger::Env; use env_logger::Env;
use log::error;
use tokio::sync::mpsc; use tokio::sync::mpsc;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
@ -20,16 +21,16 @@ struct Cli {
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
enum Commands { enum Commands {
#[clap(group(ArgGroup::new("input").required(true).args(&["infile", "files"])))] #[clap(group(ArgGroup::new("input").required(true).args(&["source", "files"])))]
Host { Host {
/// Access key /// Access key
#[clap(short = 'k', long)] #[clap(short = 'k', long)]
key: String, key: String,
/// Path to a source file (alternative to --files) /// Path to a source file (alternative to --files)
#[clap(short = 'i', long, value_parser = filepath_parser, conflicts_with = "files", group = "input")] #[clap(short = 's', long, value_parser = filepath_parser, conflicts_with = "files", group = "input")]
source: Option<PathBuf>, source: Option<PathBuf>,
/// Paths to shareable files (alternative to --source) /// Paths to shareable files (alternative to --source)
#[clap(short = 'f', long, num_args = 1.., value_parser = filepath_parser, conflicts_with = "infile", group = "input")] #[clap(short = 'f', long, num_args = 1.., value_parser = filepath_parser, conflicts_with = "source", group = "input")]
files: Option<Vec<PathBuf>>, files: Option<Vec<PathBuf>>,
/// Host port /// Host port
#[clap(short = 'p', long, default_value_t = 8080)] #[clap(short = 'p', long, default_value_t = 8080)]
@ -58,9 +59,8 @@ enum Commands {
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> { async fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let cli = Cli::parse(); let cli = Cli::parse();
match cli.command { match cli.command {
@ -73,23 +73,33 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
local, local,
key, key,
} => { } => {
let files = filepaths(source, files)?; let (tx, rx) = mpsc::channel::<()>(1);
let (metadata, index) = metadata(&files).await?;
let paths = filepaths(source, files)?;
let (metadata, index) = metadata(&paths).await?;
let addr = match (local, ipv6) { let addr = match (local, ipv6) {
(true, _) => Ip::Local.fetch(port)?, (true, _) => Ip::Local.fetch(port)?,
(false, true) => Ip::V6.fetch(port)?, (false, true) => Ip::V6.fetch(port)?,
(false, false) => Ip::V4.fetch(port)?, (false, false) => Ip::V4.fetch(port)?,
}; };
// TODO: handle shutdown signal
let (_tx, rx) = mpsc::channel::<()>(1);
let server = Server::new(addr, key, chunksize, metadata, index); let server = Server::new(addr, key, chunksize, metadata, index);
server.start(rx).await?;
tokio::spawn(async move {
match server.start(rx).await {
Ok(_) => {}
Err(e) => error!("Error during server execution: {}", e),
};
});
handle_exit(tx).await?;
} }
Commands::Connect { addr, out, key } => { Commands::Connect { addr, out, key } => {
let client = Client::new(addr, key, out); let client = Client::new(addr, key, out);
client.connection().await?; match client.connection().await {
Ok(_) => {}
Err(e) => error!("Error during client execution: {}", e),
};
} }
}; };

View File

@ -1,9 +1,12 @@
use std::{ use std::{
env,
io::{Error, ErrorKind::NotFound}, io::{Error, ErrorKind::NotFound},
net::{AddrParseError, SocketAddr}, net::{AddrParseError, SocketAddr},
path::PathBuf, path::PathBuf,
}; };
use log::debug;
pub fn addr_parser(addr: &str) -> Result<SocketAddr, AddrParseError> { pub fn addr_parser(addr: &str) -> Result<SocketAddr, AddrParseError> {
let addr = addr let addr = addr
.parse::<SocketAddr>() .parse::<SocketAddr>()
@ -13,7 +16,13 @@ pub fn addr_parser(addr: &str) -> Result<SocketAddr, AddrParseError> {
} }
pub fn filepath_parser(path: &str) -> Result<PathBuf, Error> { pub fn filepath_parser(path: &str) -> Result<PathBuf, Error> {
let path = path.parse::<PathBuf>().expect("Failed to parse path"); debug!("Validating filepath '{}'", path);
let home = env::var("HOME").unwrap();
let path = path
.replace('~', &home)
.parse::<PathBuf>()
.expect("Failed to parse path");
if path.exists() && path.is_file() { if path.exists() && path.is_file() {
Ok(path) Ok(path)
@ -23,6 +32,8 @@ pub fn filepath_parser(path: &str) -> Result<PathBuf, Error> {
} }
pub fn dirpath_parser(path: &str) -> Result<PathBuf, Error> { pub fn dirpath_parser(path: &str) -> Result<PathBuf, Error> {
debug!("Validating dirpath '{}'", path);
let path = path.parse::<PathBuf>().expect("Failed to parse path"); let path = path.parse::<PathBuf>().expect("Failed to parse path");
if path.exists() && path.is_dir() { if path.exists() && path.is_dir() {

View File

@ -1,7 +1,15 @@
use std::{collections::HashMap, error::Error, fs, net::SocketAddr, path::PathBuf}; use std::{
collections::HashMap,
env,
error::Error,
fs,
io::{stdin, Read},
net::SocketAddr,
path::PathBuf,
};
use log::{debug, info}; use log::{debug, info};
use tokio::{fs::File, io::BufWriter}; use tokio::{fs::File, io::BufWriter, sync::mpsc::Sender};
use crate::crypto; use crate::crypto;
@ -16,9 +24,7 @@ pub enum Ip {
} }
impl Ip { impl Ip {
pub fn fetch(self, port: u16) -> Result<SocketAddr, Box<dyn Error + Send + Sync>> { pub fn fetch(self, port: u16) -> Result<SocketAddr, Box<dyn Error>> {
debug!("Fetching IP information");
let addr = match self { let addr = match self {
Ip::V4 => PUBLIC_IPV4, Ip::V4 => PUBLIC_IPV4,
Ip::V6 => PUBLIC_IPV6, Ip::V6 => PUBLIC_IPV6,
@ -28,6 +34,8 @@ impl Ip {
} }
}; };
info!("Fetching IP information from {}", addr);
let res = format!("{}:{}", ureq::get(addr).call()?.into_string()?.trim(), port); let res = format!("{}:{}", ureq::get(addr).call()?.into_string()?.trim(), port);
let addr = res.parse::<SocketAddr>()?; let addr = res.parse::<SocketAddr>()?;
@ -51,38 +59,41 @@ impl FileInfo {
} }
pub fn filepaths( pub fn filepaths(
infile: Option<PathBuf>, source: Option<PathBuf>,
files: Option<Vec<PathBuf>>, files: Option<Vec<PathBuf>>,
) -> Result<Vec<PathBuf>, Box<dyn Error + Send + Sync>> { ) -> Result<Vec<PathBuf>, Box<dyn Error>> {
info!("Collecting filepaths"); info!("Collecting filepaths");
let mut filepaths = Vec::new(); let mut paths = Vec::new();
if let Some(infile) = infile { if let Some(source) = source {
let paths = fs::read_to_string(infile)?; let home = env::var("HOME")?;
for path in paths.lines() { let content = fs::read_to_string(source)?;
filepaths.push(PathBuf::from(path)); paths = content
} .lines()
.into_iter()
.map(|p| PathBuf::from(p.replace('~', &home)))
.collect();
} else if let Some(files) = files { } else if let Some(files) = files {
for file in files { paths = files;
filepaths.push(file);
}
} }
debug!("Filepaths collection finished (total: {})", filepaths.len()); debug!("Filepaths collection finished (total: {})", paths.len());
Ok(filepaths) Ok(paths)
} }
pub async fn metadata( pub async fn metadata(
files: &Vec<PathBuf>, files: &Vec<PathBuf>,
) -> Result<(Vec<FileInfo>, HashMap<String, PathBuf>), Box<dyn Error + Send + Sync>> { ) -> Result<(Vec<FileInfo>, HashMap<String, PathBuf>), Box<dyn Error>> {
info!("Collecting metadata"); info!("Collecting metadata");
let mut metadata = Vec::new(); let mut metadata = Vec::new();
let mut index = HashMap::new(); let mut index = HashMap::new();
for path in files { for path in files {
debug!("Collecting '{}' metadata", path.to_str().unwrap());
let split = path.to_str().unwrap().split('/').collect::<Vec<&str>>(); let split = path.to_str().unwrap().split('/').collect::<Vec<&str>>();
let name = split[split.len() - 1].to_string(); let name = split[split.len() - 1].to_string();
let handle = File::open(path).await?; let handle = File::open(path).await?;
@ -90,8 +101,6 @@ pub async fn metadata(
let hash = crypto::try_hash(path)?; let hash = crypto::try_hash(path)?;
if size > 0 { if size > 0 {
debug!("Collecting '{}' metadata", name);
let info = FileInfo::new(name, size, hash.clone()); let info = FileInfo::new(name, size, hash.clone());
metadata.push(info); metadata.push(info);
index.insert(hash, path.clone()); index.insert(hash, path.clone());
@ -117,3 +126,21 @@ pub async fn new_file(
Ok((BufWriter::new(handle), path)) Ok((BufWriter::new(handle), path))
} }
pub async fn handle_exit(tx: Sender<()>) -> Result<(), Box<dyn Error>> {
let mut stdin = stdin().lock().bytes();
loop {
let k = match stdin.next() {
None => continue,
Some(k) => k?,
};
if k == b'q' {
tx.send(()).await?;
break;
}
}
Ok(())
}