create struct sharry::api::FileID
This commit is contained in:
parent
f2b063ba85
commit
f1c6eb5d75
7 changed files with 104 additions and 78 deletions
|
|
@ -1,5 +1,7 @@
|
|||
use std::fmt;
|
||||
|
||||
use crate::sharry;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Parameter {
|
||||
#[error("given URI {0:?}")]
|
||||
|
|
@ -11,8 +13,8 @@ pub enum Parameter {
|
|||
#[error("stored Share ID {0:?}")]
|
||||
ShareID(String),
|
||||
|
||||
#[error("stored File ID {0:?}")]
|
||||
FileID(String),
|
||||
#[error("stored {0:?}")]
|
||||
FileID(sharry::FileID),
|
||||
}
|
||||
|
||||
impl Parameter {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::fmt;
|
||||
|
||||
use crate::sharry;
|
||||
|
||||
pub struct Chunk<'t> {
|
||||
file_id: String,
|
||||
file_id: sharry::FileID,
|
||||
offset: u64,
|
||||
data: &'t [u8],
|
||||
}
|
||||
|
|
@ -17,7 +19,7 @@ impl fmt::Debug for Chunk<'_> {
|
|||
}
|
||||
|
||||
impl<'t> Chunk<'t> {
|
||||
pub fn new(file_id: String, offset: u64, data: &'t [u8]) -> Self {
|
||||
pub fn new(file_id: sharry::FileID, offset: u64, data: &'t [u8]) -> Self {
|
||||
Self {
|
||||
file_id,
|
||||
offset,
|
||||
|
|
@ -25,7 +27,7 @@ impl<'t> Chunk<'t> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_file_id(&self) -> &str {
|
||||
pub fn get_file_id(&self) -> &sharry::FileID {
|
||||
&self.file_id
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ use std::{
|
|||
use log::warn;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::sharry;
|
||||
|
||||
use super::{Checked, Chunk, FileTrait};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
|
@ -17,14 +19,19 @@ pub struct Uploading {
|
|||
size: u64,
|
||||
/// hash of that file
|
||||
hash: Option<String>,
|
||||
file_id: String,
|
||||
file_id: sharry::FileID,
|
||||
#[serde(skip)]
|
||||
last_offset: Option<u64>,
|
||||
offset: u64,
|
||||
}
|
||||
|
||||
impl Uploading {
|
||||
pub(super) fn new(path: PathBuf, size: u64, hash: Option<String>, file_id: String) -> Self {
|
||||
pub(super) fn new(
|
||||
path: PathBuf,
|
||||
size: u64,
|
||||
hash: Option<String>,
|
||||
file_id: sharry::FileID,
|
||||
) -> Self {
|
||||
Self {
|
||||
path,
|
||||
size,
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ use log::{debug, trace};
|
|||
use crate::{
|
||||
error,
|
||||
file::{self, FileTrait},
|
||||
sharry::{self, Uri},
|
||||
sharry::{self, FileID, Uri},
|
||||
};
|
||||
|
||||
fn find_cause(
|
||||
uri: &Uri,
|
||||
alias_id: &str,
|
||||
share_id: Option<&str>,
|
||||
file_id: Option<&str>,
|
||||
file_id: Option<&FileID>,
|
||||
) -> impl FnOnce(ureq::Error) -> error::Error {
|
||||
move |error| match error {
|
||||
ureq::Error::StatusCode(403) => {
|
||||
|
|
@ -22,7 +22,7 @@ fn find_cause(
|
|||
trace!("HTTP Error 404: Share and/or file may have been deleted!");
|
||||
|
||||
if let Some(file_id) = file_id {
|
||||
error::Error::InvalidParameter(error::Parameter::FileID(file_id.to_owned()))
|
||||
error::Error::InvalidParameter(error::Parameter::FileID(file_id.clone()))
|
||||
} else if let Some(share_id) = share_id {
|
||||
error::Error::InvalidParameter(error::Parameter::ShareID(share_id.to_owned()))
|
||||
} else {
|
||||
|
|
@ -110,7 +110,7 @@ impl sharry::Client for ureq::Agent {
|
|||
alias_id: &str,
|
||||
share_id: &str,
|
||||
file: &file::Checked,
|
||||
) -> error::Result<String> {
|
||||
) -> error::Result<FileID> {
|
||||
let res = {
|
||||
let endpoint = uri.file_create(share_id);
|
||||
|
||||
|
|
@ -133,11 +133,7 @@ impl sharry::Client for ureq::Agent {
|
|||
.map_err(error::Error::response)?
|
||||
.to_string();
|
||||
|
||||
let file_id = Self::get_file_id(&location)?;
|
||||
|
||||
debug!("location: {location:?}, file_id: {file_id:?}");
|
||||
|
||||
Ok(file_id.to_owned())
|
||||
FileID::try_from(location)
|
||||
}
|
||||
|
||||
fn file_patch(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use std::fmt;
|
||||
use std::{fmt, sync::LazyLock};
|
||||
|
||||
use log::trace;
|
||||
use log::{debug, trace};
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Uri(String);
|
||||
|
||||
|
|
@ -41,11 +44,83 @@ impl Uri {
|
|||
self.endpoint(format_args!("alias/upload/{share_id}/files/tus"))
|
||||
}
|
||||
|
||||
pub fn file_patch(&self, share_id: &str, file_id: &str) -> String {
|
||||
pub fn file_patch(&self, share_id: &str, file_id: &FileID) -> String {
|
||||
self.endpoint(format_args!("alias/upload/{share_id}/files/tus/{file_id}"))
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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::unknown(format!(
|
||||
"Could not extract File ID from {value:?}"
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move into tests subdir
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
|
||||
// #[test]
|
||||
// fn test_get_file_id() {
|
||||
// let good = "https://example.com/api/v2/alias/upload/SID123/files/tus/FID456";
|
||||
// let good = Client::get_file_id(good);
|
||||
// assert!(good.is_ok());
|
||||
// assert_eq!(good.unwrap(), "FID456");
|
||||
|
||||
// let bad = "https://example.com/api/v2/alias/upload//files/tus/FID456"; // missing SID
|
||||
// assert!(Client::get_file_id(bad).is_err());
|
||||
|
||||
// let bad: &'static str = "https://example.com/api/v2/alias/upload/SID123/files/tus/"; // missing FID
|
||||
// assert!(Client::get_file_id(bad).is_err());
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct NewShareRequest {
|
||||
|
|
|
|||
|
|
@ -1,43 +1,8 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use log::trace;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::{error, file};
|
||||
|
||||
use super::api::{NewShareRequest, Uri};
|
||||
use super::api::{FileID, NewShareRequest, Uri};
|
||||
|
||||
pub trait Client {
|
||||
fn get_file_id(uri: &str) -> error::Result<&str> {
|
||||
/// 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")
|
||||
});
|
||||
|
||||
if let Some(fid) = UPLOAD_URL_RE
|
||||
.captures(uri)
|
||||
.and_then(|caps| caps.name("fid").map(|m| m.as_str()))
|
||||
{
|
||||
Ok(fid)
|
||||
} else {
|
||||
Err(error::Error::unknown(format!(
|
||||
"Could not extract File ID from {uri:?}"
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
fn share_create(
|
||||
&self,
|
||||
uri: &Uri,
|
||||
|
|
@ -53,7 +18,7 @@ pub trait Client {
|
|||
alias_id: &str,
|
||||
share_id: &str,
|
||||
file: &file::Checked,
|
||||
) -> error::Result<String>;
|
||||
) -> error::Result<FileID>;
|
||||
|
||||
fn file_patch(
|
||||
&self,
|
||||
|
|
@ -63,24 +28,3 @@ pub trait Client {
|
|||
chunk: &file::Chunk,
|
||||
) -> error::Result<()>;
|
||||
}
|
||||
|
||||
// TODO move into tests subdir
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
|
||||
// #[test]
|
||||
// fn test_get_file_id() {
|
||||
// let good = "https://example.com/api/v2/alias/upload/SID123/files/tus/FID456";
|
||||
// let good = Client::get_file_id(good);
|
||||
// assert!(good.is_ok());
|
||||
// assert_eq!(good.unwrap(), "FID456");
|
||||
|
||||
// let bad = "https://example.com/api/v2/alias/upload//files/tus/FID456"; // missing SID
|
||||
// assert!(Client::get_file_id(bad).is_err());
|
||||
|
||||
// let bad: &'static str = "https://example.com/api/v2/alias/upload/SID123/files/tus/"; // missing FID
|
||||
// assert!(Client::get_file_id(bad).is_err());
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
mod api;
|
||||
mod client;
|
||||
|
||||
pub use api::{NewShareRequest, NewShareResponse, NotifyShareResponse, Uri};
|
||||
pub use api::{FileID, NewShareRequest, NewShareResponse, NotifyShareResponse, Uri};
|
||||
pub use client::Client;
|
||||
|
|
|
|||
Loading…
Reference in a new issue