replace '~' with absolute path & removed unnecessary return traits
This commit is contained in:
parent
ba0678c149
commit
91f1a6d69f
@ -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?;
|
||||||
|
|
||||||
|
@ -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)?;
|
||||||
|
36
src/main.rs
36
src/main.rs
@ -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),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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() {
|
||||||
|
69
src/util.rs
69
src/util.rs
@ -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(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user