2025-06-18 13:09:34 +00:00
|
|
|
use log::{debug, trace};
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
file::{self, FileTrait},
|
|
|
|
|
sharry::{self, ClientError, Uri},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fn find_cause(
|
|
|
|
|
uri: &Uri,
|
|
|
|
|
alias_id: &str,
|
|
|
|
|
share_id: Option<&str>,
|
|
|
|
|
file_id: Option<&str>,
|
|
|
|
|
) -> impl FnOnce(ureq::Error) -> ClientError {
|
|
|
|
|
move |error| match error {
|
|
|
|
|
ureq::Error::StatusCode(403) => {
|
|
|
|
|
trace!("HTTP Error 403: Alias not found!");
|
|
|
|
|
|
|
|
|
|
ClientError::InvalidParameter(sharry::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 {
|
|
|
|
|
ClientError::InvalidParameter(sharry::Parameter::FileID(file_id.to_owned()))
|
|
|
|
|
} else if let Some(share_id) = share_id {
|
|
|
|
|
ClientError::InvalidParameter(sharry::Parameter::ShareID(share_id.to_owned()))
|
|
|
|
|
} else {
|
|
|
|
|
ClientError::unknown(error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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-18 14:49:30 +00:00
|
|
|
ClientError::InvalidParameter(sharry::Parameter::Uri(uri.to_string()))
|
2025-06-18 13:09:34 +00:00
|
|
|
} else {
|
|
|
|
|
error.into()
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
error.into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
error => ClientError::unknown(error),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl sharry::Client for ureq::Agent {
|
|
|
|
|
fn share_create(
|
|
|
|
|
&self,
|
|
|
|
|
uri: &Uri,
|
|
|
|
|
alias_id: &str,
|
|
|
|
|
data: sharry::NewShareRequest,
|
|
|
|
|
) -> sharry::Result<String> {
|
|
|
|
|
let res = {
|
|
|
|
|
let endpoint = uri.share_create();
|
|
|
|
|
|
|
|
|
|
let mut res = self
|
|
|
|
|
.post(&endpoint)
|
|
|
|
|
.header("Sharry-Alias", alias_id)
|
|
|
|
|
.send_json(data)
|
|
|
|
|
.map_err(find_cause(uri, alias_id, None, None))?;
|
|
|
|
|
|
|
|
|
|
trace!("{endpoint:?} response: {res:?}");
|
|
|
|
|
ClientError::res_status_check(res.status(), ureq::http::StatusCode::OK)?;
|
|
|
|
|
|
|
|
|
|
res.body_mut()
|
|
|
|
|
.read_json::<sharry::NewShareResponse>()
|
|
|
|
|
.map_err(ClientError::response)?
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
debug!("{res:?}");
|
|
|
|
|
|
|
|
|
|
if res.success && (res.message == "Share created.") {
|
2025-06-24 00:11:24 +00:00
|
|
|
trace!("new share id: {:?}", res.id);
|
|
|
|
|
|
2025-06-18 13:09:34 +00:00
|
|
|
Ok(res.id)
|
|
|
|
|
} else {
|
|
|
|
|
Err(ClientError::response(format!("{res:?}")))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn share_notify(&self, uri: &Uri, alias_id: &str, share_id: &str) -> sharry::Result<()> {
|
|
|
|
|
let res = {
|
|
|
|
|
let endpoint = uri.share_notify(share_id);
|
|
|
|
|
|
|
|
|
|
let mut res = self
|
|
|
|
|
.post(&endpoint)
|
|
|
|
|
.header("Sharry-Alias", alias_id)
|
|
|
|
|
.send_empty()
|
|
|
|
|
.map_err(find_cause(uri, alias_id, Some(share_id), None))?;
|
|
|
|
|
|
|
|
|
|
trace!("{endpoint:?} response: {res:?}");
|
|
|
|
|
ClientError::res_status_check(res.status(), ureq::http::StatusCode::OK)?;
|
|
|
|
|
|
|
|
|
|
res.body_mut()
|
|
|
|
|
.read_json::<sharry::NotifyShareResponse>()
|
|
|
|
|
.map_err(ClientError::response)?
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
debug!("{res:?}");
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn file_create(
|
|
|
|
|
&self,
|
|
|
|
|
uri: &Uri,
|
|
|
|
|
alias_id: &str,
|
|
|
|
|
share_id: &str,
|
|
|
|
|
file: &file::Checked,
|
|
|
|
|
) -> sharry::Result<String> {
|
|
|
|
|
let res = {
|
|
|
|
|
let endpoint = uri.file_create(share_id);
|
|
|
|
|
|
|
|
|
|
let res = self
|
|
|
|
|
.post(&endpoint)
|
|
|
|
|
.header("Sharry-Alias", alias_id)
|
|
|
|
|
.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:?}");
|
|
|
|
|
ClientError::res_status_check(res.status(), ureq::http::StatusCode::CREATED)?;
|
|
|
|
|
res
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let location = (res.headers().get("Location"))
|
|
|
|
|
.ok_or_else(|| ClientError::response("Location header not found"))?
|
|
|
|
|
.to_str()
|
|
|
|
|
.map_err(ClientError::response)?
|
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
|
|
let file_id = Self::get_file_id(&location)?;
|
|
|
|
|
|
|
|
|
|
debug!("location: {location:?}, file_id: {file_id:?}");
|
|
|
|
|
|
|
|
|
|
Ok(file_id.to_owned())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn file_patch(
|
|
|
|
|
&self,
|
|
|
|
|
uri: &Uri,
|
|
|
|
|
alias_id: &str,
|
|
|
|
|
share_id: &str,
|
|
|
|
|
chunk: &file::Chunk,
|
|
|
|
|
) -> sharry::Result<()> {
|
|
|
|
|
let res = {
|
|
|
|
|
let endpoint = uri.file_patch(share_id, chunk.get_file_id());
|
|
|
|
|
|
|
|
|
|
let res = self
|
|
|
|
|
.patch(&endpoint)
|
|
|
|
|
.header("Sharry-Alias", alias_id)
|
|
|
|
|
.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:?}");
|
|
|
|
|
ClientError::res_status_check(res.status(), ureq::http::StatusCode::NO_CONTENT)?;
|
|
|
|
|
res
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let res_offset = (res.headers().get("Upload-Offset"))
|
|
|
|
|
.ok_or_else(|| ClientError::response("Upload-Offset header not found"))?
|
|
|
|
|
.to_str()
|
|
|
|
|
.map_err(ClientError::response)?
|
|
|
|
|
.parse::<u64>()
|
|
|
|
|
.map_err(ClientError::response)?;
|
|
|
|
|
|
|
|
|
|
if chunk.get_behind() == res_offset {
|
|
|
|
|
Ok(())
|
|
|
|
|
} else {
|
|
|
|
|
Err(ClientError::response(format!(
|
|
|
|
|
"Unexpected Upload-Offset: {} (expected {})",
|
|
|
|
|
res_offset,
|
|
|
|
|
chunk.get_behind()
|
|
|
|
|
)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|