2025-07-03 12:58:53 +00:00
|
|
|
use std::{fmt, sync::LazyLock};
|
2025-06-25 23:42:00 +00:00
|
|
|
|
2025-07-03 12:58:53 +00:00
|
|
|
use log::{debug, trace};
|
|
|
|
|
use regex::Regex;
|
2025-06-25 23:42:00 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
2025-07-01 15:20:07 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
2025-06-25 23:42:00 +00:00
|
|
|
pub struct Uri(String);
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for Uri {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
|
f.write_str(&self.0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl AsRef<[u8]> for Uri {
|
|
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
|
self.0.as_bytes()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-03 12:58:53 +00:00
|
|
|
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)
|
|
|
|
|
}
|
2025-06-25 23:42:00 +00:00
|
|
|
}
|
2025-07-03 12:58:53 +00:00
|
|
|
}
|
2025-06-25 23:42:00 +00:00
|
|
|
|
2025-07-03 12:58:53 +00:00
|
|
|
impl Uri {
|
2025-06-25 23:42:00 +00:00
|
|
|
fn endpoint(&self, path: fmt::Arguments) -> String {
|
|
|
|
|
let uri = format!("{}/api/v2/{path}", self.0);
|
|
|
|
|
trace!("endpoint: {uri:?}");
|
|
|
|
|
uri
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn share_create(&self) -> String {
|
|
|
|
|
self.endpoint(format_args!("alias/upload/new"))
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 01:47:38 +00:00
|
|
|
pub fn share_notify(&self, share_id: &super::ShareID) -> String {
|
2025-06-25 23:42:00 +00:00
|
|
|
self.endpoint(format_args!("alias/mail/notify/{share_id}"))
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 01:47:38 +00:00
|
|
|
pub fn file_create(&self, share_id: &super::ShareID) -> String {
|
2025-06-25 23:42:00 +00:00
|
|
|
self.endpoint(format_args!("alias/upload/{share_id}/files/tus"))
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 01:47:38 +00:00
|
|
|
pub fn file_patch(&self, share_id: &super::ShareID, file_id: &super::FileID) -> String {
|
2025-06-25 23:42:00 +00:00
|
|
|
self.endpoint(format_args!("alias/upload/{share_id}/files/tus/{file_id}"))
|
|
|
|
|
}
|
|
|
|
|
}
|