182 lines
5.4 KiB
Rust
182 lines
5.4 KiB
Rust
use log::{debug, trace};
|
|
|
|
use crate::{
|
|
file::{self, FileTrait},
|
|
sharry::{self, AliasID, FileID, ShareID, Uri},
|
|
};
|
|
|
|
fn find_cause(
|
|
uri: &Uri,
|
|
alias_id: &AliasID,
|
|
share_id: Option<&ShareID>,
|
|
file_id: Option<&FileID>,
|
|
) -> impl FnOnce(ureq::Error) -> crate::Error {
|
|
move |error| match error {
|
|
ureq::Error::StatusCode(403) => {
|
|
trace!("HTTP Error 403: Alias not found!");
|
|
|
|
alias_id.into()
|
|
}
|
|
ureq::Error::StatusCode(404) => {
|
|
trace!("HTTP Error 404: Share and/or file may have been deleted!");
|
|
|
|
if let Some(file_id) = file_id {
|
|
file_id.into()
|
|
} else if let Some(share_id) = share_id {
|
|
share_id.into()
|
|
} else {
|
|
uri.into()
|
|
}
|
|
}
|
|
ureq::Error::Io(error) => {
|
|
trace!("std::io::Error {error:?}");
|
|
|
|
if let Some(msg) = error.get_ref().map(ToString::to_string) {
|
|
if msg.starts_with("failed to lookup address information") {
|
|
uri.into()
|
|
} else {
|
|
error.into()
|
|
}
|
|
} else {
|
|
error.into()
|
|
}
|
|
}
|
|
error => crate::Error::Unknown(error.to_string()),
|
|
}
|
|
}
|
|
|
|
impl sharry::Client for ureq::Agent {
|
|
fn share_create(
|
|
&self,
|
|
uri: &Uri,
|
|
alias_id: &AliasID,
|
|
data: sharry::json::NewShareRequest,
|
|
) -> crate::Result<ShareID> {
|
|
let res = {
|
|
let endpoint = uri.share_create();
|
|
|
|
let mut res = self
|
|
.post(&endpoint)
|
|
.header("Sharry-Alias", alias_id.as_ref())
|
|
.send_json(data)
|
|
.map_err(find_cause(uri, alias_id, None, None))?;
|
|
|
|
trace!("{endpoint:?} response: {res:?}");
|
|
crate::Error::res_status_check(res.status(), ureq::http::StatusCode::OK)?;
|
|
|
|
res.body_mut()
|
|
.read_json::<sharry::json::NewShareResponse>()
|
|
.map_err(crate::Error::response)?
|
|
};
|
|
|
|
debug!("{res:?}");
|
|
|
|
if res.success && (res.message == "Share created.") {
|
|
trace!("new share id: {:?}", res.id);
|
|
|
|
Ok(res.id.into())
|
|
} else {
|
|
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)
|
|
.header("Sharry-Alias", alias_id.as_ref())
|
|
.send_empty()
|
|
.map_err(find_cause(uri, alias_id, Some(share_id), None))?;
|
|
|
|
trace!("{endpoint:?} response: {res:?}");
|
|
crate::Error::res_status_check(res.status(), ureq::http::StatusCode::OK)?;
|
|
|
|
res.body_mut()
|
|
.read_json::<sharry::json::NotifyShareResponse>()
|
|
.map_err(crate::Error::response)?
|
|
};
|
|
|
|
debug!("{res:?}");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn file_create(
|
|
&self,
|
|
uri: &Uri,
|
|
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)
|
|
.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:?}");
|
|
crate::Error::res_status_check(res.status(), ureq::http::StatusCode::CREATED)?;
|
|
res
|
|
};
|
|
|
|
let location = (res.headers().get("Location"))
|
|
.ok_or_else(|| crate::Error::response("Location header not found"))?
|
|
.to_str()
|
|
.map_err(crate::Error::response)?
|
|
.to_string();
|
|
|
|
FileID::try_from(location)
|
|
}
|
|
|
|
fn file_patch(
|
|
&self,
|
|
uri: &Uri,
|
|
alias_id: &AliasID,
|
|
share_id: &ShareID,
|
|
chunk: &file::Chunk,
|
|
) -> crate::Result<()> {
|
|
let res = {
|
|
let endpoint = uri.file_patch(share_id, chunk.get_file_id());
|
|
|
|
let res = self
|
|
.patch(&endpoint)
|
|
.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:?}");
|
|
crate::Error::res_status_check(res.status(), ureq::http::StatusCode::NO_CONTENT)?;
|
|
res
|
|
};
|
|
|
|
let res_offset = (res.headers().get("Upload-Offset"))
|
|
.ok_or_else(|| crate::Error::response("Upload-Offset header not found"))?
|
|
.to_str()
|
|
.map_err(crate::Error::response)?
|
|
.parse::<u64>()
|
|
.map_err(crate::Error::response)?;
|
|
|
|
if chunk.get_behind() == res_offset {
|
|
Ok(())
|
|
} else {
|
|
Err(crate::Error::response(format!(
|
|
"Unexpected Upload-Offset: {} (expected {})",
|
|
res_offset,
|
|
chunk.get_behind()
|
|
)))
|
|
}
|
|
}
|
|
}
|