diff --git a/src/sharry/alias.rs b/src/sharry/alias.rs new file mode 100644 index 0000000..bc04e79 --- /dev/null +++ b/src/sharry/alias.rs @@ -0,0 +1,41 @@ +use log::debug; +use ureq::{Agent, RequestBuilder}; + +use super::{ + api::{NewShareRequest, NewShareResponse, URI}, + share::Share, +}; + +#[derive(Debug)] +pub struct Alias { + pub(super) uri: URI, + pub(super) id: String, +} + +impl Alias { + pub fn new(uri: URI, id: impl Into) -> Self { + Self { uri, id: id.into() } + } + + pub(super) fn add_headers(&self, req: RequestBuilder) -> RequestBuilder { + req.header("Sharry-Alias", &self.id) + } + + pub fn create_share(&self, http: &Agent, data: &NewShareRequest) -> Result { + let endpoint = self.uri.get_endpoint("alias/upload/new"); + + let res = self + .add_headers(http.post(endpoint)) + .send_json(data)? + .body_mut() + .read_json::()?; + + debug!("response: {:?}", res); + + if !(res.success && (res.message == "Share created.")) { + return Err(ureq::Error::Other("unexpected response json".into())); + } + + Ok(Share::new(self, res.id)) + } +} diff --git a/src/sharry/api.rs b/src/sharry/api.rs index 44d3027..c40afc5 100644 --- a/src/sharry/api.rs +++ b/src/sharry/api.rs @@ -21,7 +21,7 @@ impl URI { Self::new_protocol(base_url, "https") } - pub fn get_endpoint(&self, endpoint: impl Display) -> String { + pub(super) fn get_endpoint(&self, endpoint: impl Display) -> String { let uri = format!("{}://{}/api/v2/{}", self.protocol, self.base_url, endpoint); debug!("uri: {:?}", uri); @@ -56,7 +56,7 @@ impl NewShareRequest { } #[derive(Deserialize, Debug)] -pub struct NewShareResponse { +pub(super) struct NewShareResponse { pub success: bool, pub message: String, pub id: String, @@ -64,7 +64,7 @@ pub struct NewShareResponse { #[derive(Deserialize, Debug)] #[allow(dead_code)] -pub struct NotifyShareResponse { +pub(super) struct NotifyShareResponse { pub success: bool, pub message: String, } diff --git a/src/sharry/mod.rs b/src/sharry/mod.rs index 89ace00..0285a90 100644 --- a/src/sharry/mod.rs +++ b/src/sharry/mod.rs @@ -1,121 +1,6 @@ +mod alias; mod api; +mod share; +pub use alias::Alias; pub use api::{NewShareRequest, URI}; -use api::{NewShareResponse, NotifyShareResponse}; -use log::debug; -use std::{ffi::OsStr, fs, path::Path}; -use ureq::{self, RequestBuilder}; - -#[derive(Debug)] -pub struct Alias { - uri: URI, - id: String, -} - -impl Alias { - pub fn new(uri: URI, id: impl Into) -> Self { - Self { uri, id: id.into() } - } - - fn add_headers(&self, req: RequestBuilder) -> RequestBuilder { - req.header("Sharry-Alias", &self.id) - } - - pub fn create_share( - &self, - http: &ureq::Agent, - data: &NewShareRequest, - ) -> Result { - let endpoint = self.uri.get_endpoint("alias/upload/new"); - - let res = self - .add_headers(http.post(endpoint)) - .send_json(data)? - .body_mut() - .read_json::()?; - - debug!("response: {:?}", res); - assert!(res.success); - assert_eq!(res.message, "Share created."); - - Ok(Share { - alias: self, - id: res.id, - }) - } -} - -#[derive(Debug)] -pub struct Share<'t> { - alias: &'t Alias, - id: String, -} - -impl<'t> Share<'t> { - pub fn create_file( - &self, - http: &ureq::Agent, - path: impl AsRef + AsRef, - ) -> Result<(), ureq::Error> { - let filename = Path::new(&path) - .file_name() - .and_then(OsStr::to_str) - .unwrap_or("file.bin"); - - let size = fs::metadata(&path)?.len(); - - let endpoint = self - .alias - .uri - .get_endpoint(&format!("alias/upload/{}/files/tus", &self.id)); - - let res = self - .alias - .add_headers(http.post(endpoint)) - .header("Sharry-File-Name", filename) - // .header("Sharry-File-Type", "application/octet-stream") - // .header("Sharry-File-Length", size) - // .header("Tus-Resumable", "1.0.0") - .header("Upload-Length", size) - .send_empty()?; - - assert_eq!(res.status(), ureq::http::StatusCode::CREATED); - - let location = res - .headers() - .get("Location") - .ok_or_else(|| ureq::Error::Other("Location header not found".into()))? - .to_str() - .map_err(|_| ureq::Error::Other("Location header invalid".into()))?; - - debug!("location: {}", location); - - // let start = 10; - // let count = 10; - - // let mut f = File::open(path)?; - // f.seek(SeekFrom::Start(0)); - // let mut buf = vec![0; count]; - // f.read_exact(&mut buf)?; - - Ok(()) - } - - pub fn notify(&self, http: &ureq::Agent) -> Result<(), ureq::Error> { - let endpoint = self - .alias - .uri - .get_endpoint(&format!("alias/mail/notify/{}", &self.id)); - - let res = self - .alias - .add_headers(http.post(endpoint)) - .send_empty()? - .body_mut() - .read_json::()?; - - debug!("response: {:?}", res); - - Ok(()) - } -} diff --git a/src/sharry/share.rs b/src/sharry/share.rs new file mode 100644 index 0000000..71be644 --- /dev/null +++ b/src/sharry/share.rs @@ -0,0 +1,87 @@ +use log::debug; +use std::{ffi::OsStr, fs, path::Path}; +use ureq::{Agent, http::StatusCode}; + +use super::{alias::Alias, api}; +use api::NotifyShareResponse; + +#[derive(Debug)] +pub struct Share<'t> { + alias: &'t Alias, + id: String, +} + +impl<'t> Share<'t> { + pub(super) fn new(alias: &'t Alias, id: String) -> Self { + Self { alias, id } + } + + pub fn create_file( + &self, + http: &Agent, + path: impl AsRef + AsRef, + ) -> Result<(), ureq::Error> { + let filename = Path::new(&path) + .file_name() + .and_then(OsStr::to_str) + .unwrap_or("file.bin"); + + let size = fs::metadata(&path)?.len(); + + let endpoint = self + .alias + .uri + .get_endpoint(&format!("alias/upload/{}/files/tus", &self.id)); + + let res = self + .alias + .add_headers(http.post(endpoint)) + .header("Sharry-File-Name", filename) + // .header("Sharry-File-Type", "application/octet-stream") + // .header("Sharry-File-Length", size) + // .header("Tus-Resumable", "1.0.0") + .header("Upload-Length", size) + .send_empty()?; + + if res.status() != StatusCode::CREATED { + return Err(ureq::Error::Other("unexpected response status".into())); + } + + let location = res + .headers() + .get("Location") + .ok_or_else(|| ureq::Error::Other("Location header not found".into()))? + .to_str() + .map_err(|_| ureq::Error::Other("Location header invalid".into()))?; + + debug!("location: {}", location); + + // let start = 10; + // let count = 10; + + // let mut f = File::open(path)?; + // f.seek(SeekFrom::Start(0)); + // let mut buf = vec![0; count]; + // f.read_exact(&mut buf)?; + + Ok(()) + } + + pub fn notify(&self, http: &ureq::Agent) -> Result<(), ureq::Error> { + let endpoint = self + .alias + .uri + .get_endpoint(&format!("alias/mail/notify/{}", &self.id)); + + let res = self + .alias + .add_headers(http.post(endpoint)) + .send_empty()? + .body_mut() + .read_json::()?; + + debug!("response: {:?}", res); + + Ok(()) + } +}