shrupl/src/cli.rs

117 lines
3.1 KiB
Rust
Raw Normal View History

2025-06-02 23:57:17 +00:00
use std::{
fmt,
2025-06-02 23:57:17 +00:00
hash::{DefaultHasher, Hash, Hasher},
time::Duration,
};
2025-05-28 00:07:59 +00:00
2025-06-15 00:46:02 +00:00
use clap::{
Parser,
builder::{PossibleValuesParser, TypedValueParser},
value_parser,
};
2025-05-28 00:07:59 +00:00
use super::{
file::Checked,
sharry::{NewShareRequest, Uri},
};
2025-05-28 12:35:35 +00:00
#[derive(Parser, Hash)]
2025-05-28 00:07:59 +00:00
#[command(version, about, long_about = None)]
pub struct Cli {
2025-05-28 13:42:31 +00:00
/// Timeout in seconds for HTTP actions (set 0 or invalid to disable)
#[arg(
2025-06-02 23:57:17 +00:00
short, long,
2025-05-28 13:42:31 +00:00
default_value = "10", value_name = "SECS",
value_parser = parse_seconds,
)]
timeout: Duration,
2025-05-28 00:07:59 +00:00
/// Protocol for Sharry instance
#[arg(
short, long,
2025-05-28 00:21:14 +00:00
default_value = "https", value_name = "VARIANT",
2025-05-28 13:42:31 +00:00
value_parser = PossibleValuesParser::new(["http", "https"]),
2025-05-28 00:07:59 +00:00
)]
protocol: String,
2025-05-28 00:07:59 +00:00
/// Name of the new share
2025-05-28 12:35:35 +00:00
#[arg(short, long, default_value = "ShrUpl Upload", value_name = "TEXT")]
name: String,
2025-05-28 00:07:59 +00:00
/// Description of the new share
2025-05-28 00:21:14 +00:00
#[arg(short, long, value_name = "TEXT")]
description: Option<String>,
2025-05-28 00:07:59 +00:00
/// Maximum number of views for the new share
2025-05-28 12:35:35 +00:00
#[arg(short, long, default_value_t = 100, value_name = "N")]
max_views: u32,
2025-05-28 00:07:59 +00:00
/// Chunk size for uploading, in MiB
2025-06-15 00:46:02 +00:00
#[arg(
short, long,
default_value_t = 10, value_name = "M",
value_parser = value_parser!(u32).range(1..).map(|s| s as usize),
)]
2025-05-28 00:21:14 +00:00
pub chunk_size: usize,
2025-05-28 00:07:59 +00:00
/// Base URL for Sharry Instance
url: String,
2025-05-28 00:07:59 +00:00
/// ID of a public alias to use
pub alias: String,
2025-05-28 00:07:59 +00:00
/// Files to upload to the new share
2025-05-28 12:35:35 +00:00
#[arg(value_name = "FILE", required = true, value_parser = parse_sharry_file)]
pub files: Vec<Checked>,
2025-05-28 12:35:35 +00:00
}
impl fmt::Debug for Cli {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Cli")
.field("uri", &self.get_uri())
.field("alias", &self.alias)
.field("timeout", &self.get_timeout())
.field("chunk_size", &self.chunk_size)
.field("share_request", &self.get_share_request())
.field("files", &self.files)
.field("hash", &self.get_hash())
.finish_non_exhaustive()
}
}
2025-05-28 12:35:35 +00:00
fn parse_seconds(data: &str) -> Result<Duration, String> {
2025-05-28 13:42:31 +00:00
data.parse().or(Ok(0)).map(Duration::from_secs)
2025-05-28 12:35:35 +00:00
}
fn parse_sharry_file(data: &str) -> Result<Checked, String> {
Checked::new(data).map_err(|e| e.to_string())
2025-05-28 00:07:59 +00:00
}
2025-05-28 13:42:31 +00:00
impl Cli {
pub fn get_timeout(&self) -> Option<Duration> {
(!self.timeout.is_zero()).then_some(self.timeout)
}
pub fn get_uri(&self) -> Uri {
Uri::with_protocol(&self.protocol, &self.url)
}
pub fn get_share_request(&self) -> NewShareRequest {
NewShareRequest::new(&self.name, self.description.as_ref(), self.max_views)
}
2025-06-02 23:57:17 +00:00
pub fn get_hash(&self) -> String {
let file_refs = {
2025-06-04 16:44:24 +00:00
let mut refs: Vec<_> = self.files.iter().collect();
2025-06-02 23:57:17 +00:00
refs.sort_unstable();
refs
};
let mut hasher = DefaultHasher::new();
(self.get_uri(), &self.alias, file_refs).hash(&mut hasher);
2025-06-02 23:57:17 +00:00
format!("{:x}", hasher.finish())
}
2025-05-28 13:42:31 +00:00
}