shrupl/src/impl_ureq.rs

183 lines
5.7 KiB
Rust
Raw Normal View History

use log::{debug, trace};
use crate::{
file::{self, FileTrait},
2025-06-27 01:47:38 +00:00
sharry::{self, AliasID, FileID, ShareID, Uri},
};
fn find_cause(
uri: &Uri,
2025-06-27 01:47:38 +00:00
alias_id: &AliasID,
share_id: Option<&ShareID>,
2025-06-25 23:15:33 +00:00
file_id: Option<&FileID>,
2025-06-27 01:55:43 +00:00
) -> impl FnOnce(ureq::Error) -> crate::Error {
move |error| match error {
ureq::Error::StatusCode(403) => {
trace!("HTTP Error 403: Alias not found!");
2025-06-27 01:55:43 +00:00
crate::Error::InvalidParameter(crate::Parameter::AliasID(alias_id.to_owned()))
}
ureq::Error::StatusCode(404) => {
trace!("HTTP Error 404: Share and/or file may have been deleted!");
if let Some(file_id) = file_id {
2025-06-27 01:55:43 +00:00
crate::Error::InvalidParameter(crate::Parameter::FileID(file_id.to_owned()))
} else if let Some(share_id) = share_id {
2025-06-27 01:55:43 +00:00
crate::Error::InvalidParameter(crate::Parameter::ShareID(share_id.to_owned()))
} else {
2025-06-27 01:55:43 +00:00
crate::Error::InvalidParameter(crate::Parameter::Uri(uri.to_string()))
}
}
ureq::Error::Io(error) => {
trace!("std::io::Error {error:?}");
if let Some(msg) = error.get_ref().map(ToString::to_string) {
2025-06-24 02:08:35 +00:00
if msg.starts_with("failed to lookup address information") {
2025-06-27 01:55:43 +00:00
crate::Error::InvalidParameter(crate::Parameter::Uri(uri.to_string()))
} else {
error.into()
}
} else {
error.into()
}
}
2025-06-27 01:55:43 +00:00
error => crate::Error::Unknown(error.to_string()),
}
}
impl sharry::Client for ureq::Agent {
fn share_create(
&self,
uri: &Uri,
2025-06-27 01:47:38 +00:00
alias_id: &AliasID,
data: sharry::NewShareRequest,
) -> crate::Result<ShareID> {
let res = {
let endpoint = uri.share_create();
let mut res = self
.post(&endpoint)
2025-06-27 01:47:38 +00:00
.header("Sharry-Alias", alias_id.as_ref())
.send_json(data)
.map_err(find_cause(uri, alias_id, None, None))?;
trace!("{endpoint:?} response: {res:?}");
2025-06-27 01:55:43 +00:00
crate::Error::res_status_check(res.status(), ureq::http::StatusCode::OK)?;
res.body_mut()
.read_json::<sharry::NewShareResponse>()
2025-06-27 01:55:43 +00:00
.map_err(crate::Error::response)?
};
debug!("{res:?}");
if res.success && (res.message == "Share created.") {
trace!("new share id: {:?}", res.id);
2025-06-27 01:47:38 +00:00
Ok(res.id.into())
} else {
2025-06-27 01:55:43 +00:00
Err(crate::Error::response(format!("{res:?}")))
}
}
fn share_notify(&self, uri: &Uri, alias_id: &AliasID, share_id: &ShareID) -> crate::Result<()> {
let res = {
let endpoint = uri.share_notify(share_id);
let mut res = self
.post(&endpoint)
2025-06-27 01:47:38 +00:00
.header("Sharry-Alias", alias_id.as_ref())
.send_empty()
.map_err(find_cause(uri, alias_id, Some(share_id), None))?;
trace!("{endpoint:?} response: {res:?}");
2025-06-27 01:55:43 +00:00
crate::Error::res_status_check(res.status(), ureq::http::StatusCode::OK)?;
res.body_mut()
.read_json::<sharry::NotifyShareResponse>()
2025-06-27 01:55:43 +00:00
.map_err(crate::Error::response)?
};
debug!("{res:?}");
Ok(())
}
fn file_create(
&self,
uri: &Uri,
2025-06-27 01:47:38 +00:00
alias_id: &AliasID,
share_id: &ShareID,
file: &file::Checked,
) -> crate::Result<FileID> {
let res = {
let endpoint = uri.file_create(share_id);
let res = self
.post(&endpoint)
2025-06-27 01:47:38 +00:00
.header("Sharry-Alias", alias_id.as_ref())
.header("Sharry-File-Name", file.get_name())
.header("Upload-Length", file.get_size())
.send_empty()
.map_err(find_cause(uri, alias_id, Some(share_id), None))?;
trace!("{endpoint:?} response: {res:?}");
2025-06-27 01:55:43 +00:00
crate::Error::res_status_check(res.status(), ureq::http::StatusCode::CREATED)?;
res
};
let location = (res.headers().get("Location"))
2025-06-27 01:55:43 +00:00
.ok_or_else(|| crate::Error::response("Location header not found"))?
.to_str()
2025-06-27 01:55:43 +00:00
.map_err(crate::Error::response)?
.to_string();
2025-06-25 23:15:33 +00:00
FileID::try_from(location)
}
fn file_patch(
&self,
uri: &Uri,
2025-06-27 01:47:38 +00:00
alias_id: &AliasID,
share_id: &ShareID,
chunk: &file::Chunk,
2025-06-27 01:55:43 +00:00
) -> crate::Result<()> {
let res = {
let endpoint = uri.file_patch(share_id, chunk.get_file_id());
let res = self
.patch(&endpoint)
2025-06-27 01:47:38 +00:00
.header("Sharry-Alias", alias_id.as_ref())
.header("Upload-Offset", chunk.get_offset())
.send(chunk.get_data())
.map_err(find_cause(
uri,
alias_id,
Some(share_id),
Some(chunk.get_file_id()),
))?;
trace!("{endpoint:?} response: {res:?}");
2025-06-27 01:55:43 +00:00
crate::Error::res_status_check(res.status(), ureq::http::StatusCode::NO_CONTENT)?;
res
};
let res_offset = (res.headers().get("Upload-Offset"))
2025-06-27 01:55:43 +00:00
.ok_or_else(|| crate::Error::response("Upload-Offset header not found"))?
.to_str()
2025-06-27 01:55:43 +00:00
.map_err(crate::Error::response)?
.parse::<u64>()
2025-06-27 01:55:43 +00:00
.map_err(crate::Error::response)?;
if chunk.get_behind() == res_offset {
Ok(())
} else {
2025-06-27 01:55:43 +00:00
Err(crate::Error::response(format!(
"Unexpected Upload-Offset: {} (expected {})",
res_offset,
chunk.get_behind()
)))
}
}
}