shrupl/src/sharry/api/id.rs

85 lines
2.5 KiB
Rust
Raw Normal View History

use std::{fmt, sync::LazyLock};
use log::{debug, trace};
use regex::Regex;
use serde::{Deserialize, Serialize};
use crate::error;
// pub struct AliasID(String);
// pub struct ShareID(String);
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FileID(String);
impl fmt::Display for FileID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl AsRef<str> for FileID {
fn as_ref(&self) -> &str {
&self.0
}
}
impl TryFrom<String> for FileID {
type Error = error::Error;
fn try_from(value: String) -> error::Result<Self> {
/// Pattern breakdown:
/// - `^([^:/?#]+)://` scheme (anything but `:/?#`) + `"://"`
/// - `([^/?#]+)` authority/host (anything but `/?#`)
/// - `/api/v2/alias/upload/` literal path segment
/// - `([^/]+)` capture SID (one or more non-slash chars)
/// - `/files/tus/` literal path segment
/// - `(?P<fid>[^/]+)` capture FID (one or more non-slash chars)
/// - `$` end of string
static UPLOAD_URL_RE: LazyLock<Regex> = LazyLock::new(|| {
trace!("compiling UPLOAD_URL_RE");
Regex::new(
r"^([^:/?#]+)://([^/?#]+)/api/v2/alias/upload/[^/]+/files/tus/(?P<fid>[^/]+)$",
)
.expect("Regex compilation failed")
});
trace!("TryFrom {value:?}");
if let Some(fid) = UPLOAD_URL_RE
.captures(&value)
.and_then(|caps| caps.name("fid").map(|m| m.as_str()))
{
let result = Self(fid.to_owned());
debug!("{result:?}");
Ok(result)
} else {
Err(error::Error::mismatch(
"<proto>://<base>/api/v2/alias/upload/<share>/files/tus/<file>",
value,
))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fileid_tryfrom_string() {
let good = "https://example.com/api/v2/alias/upload/SID123/files/tus/FID456".to_owned();
let good = FileID::try_from(good);
assert!(good.is_ok());
assert_eq!(good.unwrap().as_ref(), "FID456");
let bad = "https://example.com/api/v2/alias/upload//files/tus/FID456".to_owned(); // missing SID
assert!(FileID::try_from(bad).is_err());
let bad = "https://example.com/api/v2/alias/upload/SID123/files/tus/".to_owned(); // missing FID
assert!(FileID::try_from(bad).is_err());
}
}