Compare commits
No commits in common. "fada53044dc0a5630010c6a4aa4d2c01c1f4c9fc" and "2cc13f24e7af906cfa3d43882a9f12d3e6e28f55" have entirely different histories.
fada53044d
...
2cc13f24e7
4 changed files with 33 additions and 58 deletions
|
|
@ -62,7 +62,7 @@ impl AppState {
|
||||||
if let Some(upl) = self.inner.peek_uploading() {
|
if let Some(upl) = self.inner.peek_uploading() {
|
||||||
if bar.length().is_none() {
|
if bar.length().is_none() {
|
||||||
bar.set_length(upl.get_size());
|
bar.set_length(upl.get_size());
|
||||||
bar.set_message(upl.get_name().to_string());
|
bar.set_message(upl.get_name().to_owned());
|
||||||
bar.enable_steady_tick(Duration::from_millis(100));
|
bar.enable_steady_tick(Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
16
src/cli.rs
16
src/cli.rs
|
|
@ -2,7 +2,11 @@ use std::{convert::Infallible, fmt, io, time::Duration};
|
||||||
|
|
||||||
use base64ct::{Base64UrlUnpadded, Encoding};
|
use base64ct::{Base64UrlUnpadded, Encoding};
|
||||||
use blake2b_simd::Params as Blake2b;
|
use blake2b_simd::Params as Blake2b;
|
||||||
use clap::{Parser, builder::TypedValueParser, value_parser};
|
use clap::{
|
||||||
|
Parser,
|
||||||
|
builder::{PossibleValuesParser, TypedValueParser},
|
||||||
|
value_parser,
|
||||||
|
};
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -21,6 +25,14 @@ pub struct Cli {
|
||||||
)]
|
)]
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
|
|
||||||
|
/// Protocol for Sharry instance
|
||||||
|
#[arg(
|
||||||
|
short, long,
|
||||||
|
default_value = "https", value_name = "VARIANT",
|
||||||
|
value_parser = PossibleValuesParser::new(["http", "https"]),
|
||||||
|
)]
|
||||||
|
protocol: String,
|
||||||
|
|
||||||
/// Number of times actions are retried
|
/// Number of times actions are retried
|
||||||
#[arg(short, long, default_value_t = 5, value_name = "N")]
|
#[arg(short, long, default_value_t = 5, value_name = "N")]
|
||||||
retry_limit: u32,
|
retry_limit: u32,
|
||||||
|
|
@ -106,7 +118,7 @@ impl Cli {
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_uri(&self) -> Uri {
|
pub fn get_uri(&self) -> Uri {
|
||||||
Uri::from(self.url.clone())
|
Uri::new(&self.protocol, &self.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
|
||||||
|
|
@ -54,13 +54,13 @@ impl TryFrom<String> for FileID {
|
||||||
|
|
||||||
fn try_from(value: String) -> crate::Result<Self> {
|
fn try_from(value: String) -> crate::Result<Self> {
|
||||||
/// Pattern breakdown:
|
/// Pattern breakdown:
|
||||||
/// - `^([^:/?#]+)://` - scheme (anything but `:/?#`) + `"://"`
|
/// - `^([^:/?#]+)://` – scheme (anything but `:/?#`) + `"://"`
|
||||||
/// - `([^/?#]+)` - authority/host (anything but `/?#`)
|
/// - `([^/?#]+)` – authority/host (anything but `/?#`)
|
||||||
/// - `/api/v2/alias/upload/` - literal path segment
|
/// - `/api/v2/alias/upload/` – literal path segment
|
||||||
/// - `([^/]+)` - capture SID (one or more non-slash chars)
|
/// - `([^/]+)` – capture SID (one or more non-slash chars)
|
||||||
/// - `/files/tus/` - literal path segment
|
/// - `/files/tus/` – literal path segment
|
||||||
/// - `(?P<fid>[^/]+)` - capture FID (one or more non-slash chars)
|
/// - `(?P<fid>[^/]+)` – capture FID (one or more non-slash chars)
|
||||||
/// - `$` - end of string
|
/// - `$` – end of string
|
||||||
static UPLOAD_URL_RE: LazyLock<Regex> = LazyLock::new(|| {
|
static UPLOAD_URL_RE: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
trace!("compiling UPLOAD_URL_RE");
|
trace!("compiling UPLOAD_URL_RE");
|
||||||
|
|
||||||
|
|
@ -76,13 +76,13 @@ impl TryFrom<String> for FileID {
|
||||||
.captures(&value)
|
.captures(&value)
|
||||||
.and_then(|caps| caps.name("fid").map(|m| m.as_str()))
|
.and_then(|caps| caps.name("fid").map(|m| m.as_str()))
|
||||||
{
|
{
|
||||||
let result = Self(fid.to_string());
|
let result = Self(fid.to_owned());
|
||||||
debug!("{result:?}");
|
debug!("{result:?}");
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
Err(crate::Error::mismatch(
|
Err(crate::Error::mismatch(
|
||||||
"<proto>://<host>/api/v2/alias/upload/<share>/files/tus/<file>",
|
"<proto>://<base>/api/v2/alias/upload/<share>/files/tus/<file>",
|
||||||
value,
|
value,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
@ -112,8 +112,8 @@ mod tests {
|
||||||
];
|
];
|
||||||
|
|
||||||
for (good, expected_fid) in cases {
|
for (good, expected_fid) in cases {
|
||||||
let file_id =
|
let s = good.to_string();
|
||||||
FileID::try_from(good.to_string()).expect("URL should parse successfully");
|
let file_id = FileID::try_from(s.clone()).expect("URL should parse successfully");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
file_id.0, expected_fid,
|
file_id.0, expected_fid,
|
||||||
"Expected `{}` → FileID({}), got {:?}",
|
"Expected `{}` → FileID({}), got {:?}",
|
||||||
|
|
@ -143,7 +143,7 @@ mod tests {
|
||||||
match err {
|
match err {
|
||||||
crate::Error::Mismatch { expected, actual } => {
|
crate::Error::Mismatch { expected, actual } => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected, "<proto>://<host>/api/v2/alias/upload/<share>/files/tus/<file>",
|
expected, "<proto>://<base>/api/v2/alias/upload/<share>/files/tus/<file>",
|
||||||
"Error should output expected format"
|
"Error should output expected format"
|
||||||
);
|
);
|
||||||
assert_eq!(actual, bad.to_string(), "Error should echo back the input");
|
assert_eq!(actual, bad.to_string(), "Error should echo back the input");
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use std::{fmt, sync::LazyLock};
|
use std::fmt;
|
||||||
|
|
||||||
use log::{debug, trace};
|
use log::trace;
|
||||||
use regex::Regex;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
@ -19,47 +18,11 @@ impl AsRef<[u8]> for Uri {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Uri {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
fn parse_url(value: &str) -> Option<(String, String)> {
|
|
||||||
/// Pattern breakdown:
|
|
||||||
/// - `^(?P<scheme>[^:/?#]+)://` - capture scheme (anything but `:/?#`) + `"://"`
|
|
||||||
/// - `(?P<host>[^/?#]+)` - capture authority/host (anything but `/?#`)
|
|
||||||
/// - `(/.*)?` - maybe trailing slash and some path
|
|
||||||
/// - `$` - end of string
|
|
||||||
static SHARRY_URI_RE: LazyLock<Regex> = LazyLock::new(|| {
|
|
||||||
trace!("compiling SHARRY_URI_RE");
|
|
||||||
|
|
||||||
Regex::new(r"^(?P<scheme>[^:/?#]+)://(?P<host>[^/?#]+)(/.*)?$")
|
|
||||||
.expect("Regex compilation failed")
|
|
||||||
});
|
|
||||||
|
|
||||||
SHARRY_URI_RE.captures(value).map(|caps| {
|
|
||||||
let captured = |name| {
|
|
||||||
caps.name(name)
|
|
||||||
.expect(&format!("{name} not captured"))
|
|
||||||
.as_str()
|
|
||||||
.to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
(captured("scheme"), captured("host"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!("TryFrom {value:?}");
|
|
||||||
|
|
||||||
if let Some((scheme, host)) = parse_url(&value) {
|
|
||||||
let result = Self(format!("{scheme}://{host}"));
|
|
||||||
debug!("{result:?}");
|
|
||||||
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Uri {
|
impl Uri {
|
||||||
|
pub fn new(protocol: impl fmt::Display, base_url: impl fmt::Display) -> Self {
|
||||||
|
Self(format!("{protocol}://{base_url}"))
|
||||||
|
}
|
||||||
|
|
||||||
fn endpoint(&self, path: fmt::Arguments) -> String {
|
fn endpoint(&self, path: fmt::Arguments) -> String {
|
||||||
let uri = format!("{}/api/v2/{path}", self.0);
|
let uri = format!("{}/api/v2/{path}", self.0);
|
||||||
trace!("endpoint: {uri:?}");
|
trace!("endpoint: {uri:?}");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue