melib/jmap: fix blob download URL formatting

pull/260/head
Manos Pitsidianakis 11 months ago
parent 48a10f7241
commit 6280bc75e5
No known key found for this signature in database
GPG Key ID: 7729C7707F7E09D0

11
Cargo.lock generated

@ -1284,6 +1284,7 @@ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"serde_path_to_error",
"smallvec", "smallvec",
"smol", "smol",
"stderrlog", "stderrlog",
@ -1934,6 +1935,16 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_path_to_error"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335"
dependencies = [
"itoa",
"serde",
]
[[package]] [[package]]
name = "sha1_smol" name = "sha1_smol"
version = "1.0.0" version = "1.0.0"

@ -71,7 +71,7 @@ regex = "1"
tempfile = "3.3" tempfile = "3.3"
[features] [features]
default = ["sqlite3", "notmuch", "regexp", "smtp", "dbus-notifications", "gpgme", "cli-docs"] default = ["sqlite3", "notmuch", "regexp", "smtp", "dbus-notifications", "gpgme", "cli-docs", "jmap"]
notmuch = ["melib/notmuch_backend", ] notmuch = ["melib/notmuch_backend", ]
jmap = ["melib/jmap_backend",] jmap = ["melib/jmap_backend",]
sqlite3 = ["melib/sqlite3"] sqlite3 = ["melib/sqlite3"]

@ -207,7 +207,9 @@ impl MailBackend for PluginBackend {
&mut self, &mut self,
_name: String, _name: String,
) -> ResultFuture<(MailboxHash, HashMap<MailboxHash, Mailbox>)> { ) -> ResultFuture<(MailboxHash, HashMap<MailboxHash, Mailbox>)> {
Err(Error::new("Creating a mailbox is currently unimplemented for plugins")) Err(Error::new(
"Creating a mailbox is currently unimplemented for plugins",
))
} }
fn collection(&self) -> melib::Collection { fn collection(&self) -> melib::Collection {
self.collection.clone() self.collection.clone()

@ -40,9 +40,10 @@ nom = { version = "7" }
notify = { version = "4.0.15", optional = true } notify = { version = "4.0.15", optional = true }
regex = { version = "1" } regex = { version = "1" }
rusqlite = { version = "^0.28", default-features = false, optional = true } rusqlite = { version = "^0.28", default-features = false, optional = true }
serde = { version = "1.0.71", features = ["rc", ] } serde = { version = "1.0", features = ["rc", ] }
serde_derive = "1.0.71" serde_derive = "1.0"
serde_json = { version = "1.0", features = ["raw_value",] } serde_json = { version = "1.0", features = ["raw_value",] }
serde_path_to_error = { version = "0.1" }
smallvec = { version = "^1.5.0", features = ["serde", ] } smallvec = { version = "^1.5.0", features = ["serde", ] }
smol = "1.0.0" smol = "1.0.0"

@ -84,6 +84,22 @@ use objects::*;
pub mod mailbox; pub mod mailbox;
use mailbox::*; use mailbox::*;
pub fn deserialize_from_str<'de, T: serde::de::Deserialize<'de>>(s: &'de str) -> Result<T> {
let jd = &mut serde_json::Deserializer::from_str(s);
match serde_path_to_error::deserialize(jd) {
Ok(v) => Ok(v),
Err(err) => Err(Error::new(format!(
"BUG: Could not deserialize server JSON response properly, please report this!\nError \
{} at {}. Reply from server: {}",
err,
err.path(),
&s
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug)),
}
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EnvelopeCache { pub struct EnvelopeCache {
bytes: Option<String>, bytes: Option<String>,
@ -430,15 +446,8 @@ impl MailBackend for JmapType {
}; };
let res_text = res.text().await?; let res_text = res.text().await?;
let upload_response: UploadResponse = match serde_json::from_str(&res_text) { let upload_response: UploadResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!(
"BUG: Could not deserialize {} server JSON response properly, please \
report this!\nReply from server: {}",
&conn.server_conf.server_url, &res_text
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug);
*conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
@ -467,23 +476,15 @@ impl MailBackend for JmapType {
.await?; .await?;
let res_text = res.text().await?; let res_text = res.text().await?;
let mut v: MethodResponse = match serde_json::from_str(&res_text) { let mut v: MethodResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!(
"BUG: Could not deserialize {} server JSON response properly, please \
report this!\nReply from server: {}",
&conn.server_conf.server_url, &res_text
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug);
*conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
Ok(s) => s, Ok(s) => s,
}; };
let m = ImportResponse::try_from(v.method_responses.remove(0)).map_err(|err| { let m = ImportResponse::try_from(v.method_responses.remove(0)).map_err(|err| {
let ierr: Result<ImportError> = let ierr: Result<ImportError> = deserialize_from_str(&res_text);
serde_json::from_str(&res_text).map_err(|err| err.into());
if let Ok(err) = ierr { if let Ok(err) = ierr {
Error::new(format!("Could not save message: {:?}", err)) Error::new(format!("Could not save message: {:?}", err))
} else { } else {
@ -554,15 +555,8 @@ impl MailBackend for JmapType {
.await?; .await?;
let res_text = res.text().await?; let res_text = res.text().await?;
let mut v: MethodResponse = match serde_json::from_str(&res_text) { let mut v: MethodResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!(
"BUG: Could not deserialize {} server JSON response properly, please \
report this!\nReply from server: {}",
&conn.server_conf.server_url, &res_text
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug);
*conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
@ -694,15 +688,8 @@ impl MailBackend for JmapType {
let res_text = res.text().await?; let res_text = res.text().await?;
let mut v: MethodResponse = match serde_json::from_str(&res_text) { let mut v: MethodResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!(
"BUG: Could not deserialize {} server JSON response properly, please \
report this!\nReply from server: {}",
&conn.server_conf.server_url, &res_text
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug);
*conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
@ -816,15 +803,8 @@ impl MailBackend for JmapType {
* p-5;vfs-0"} * p-5;vfs-0"}
*/ */
//debug!("res_text = {}", &res_text); //debug!("res_text = {}", &res_text);
let mut v: MethodResponse = match serde_json::from_str(&res_text) { let mut v: MethodResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!(
"BUG: Could not deserialize {} server JSON response properly, please \
report this!\nReply from server: {}",
&conn.server_conf.server_url, &res_text
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug);
*conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }

@ -100,8 +100,8 @@ impl JmapConnection {
jmap_session_resource_url = to_well_known(&self.server_conf.server_url); jmap_session_resource_url = to_well_known(&self.server_conf.server_url);
if let Ok(s) = self.client.get_async(&jmap_session_resource_url).await { if let Ok(s) = self.client.get_async(&jmap_session_resource_url).await {
log::error!( log::error!(
"Account {} server URL should start with `https`. Please correct \ "Account {} server URL should start with `https`. Please correct your \
your configuration value. Its current value is `{}`.", configuration value. Its current value is `{}`.",
self.store.account_name, self.store.account_name,
self.server_conf.server_url self.server_conf.server_url
); );
@ -151,7 +151,7 @@ impl JmapConnection {
Ok(s) => s, Ok(s) => s,
}; };
let session: JmapSession = match serde_json::from_str(&res_text) { let session: JmapSession = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!( let err = Error::new(format!(
"Could not connect to JMAP server endpoint for {}. Is your server url setting \ "Could not connect to JMAP server endpoint for {}. Is your server url setting \
@ -167,14 +167,36 @@ impl JmapConnection {
Ok(s) => s, Ok(s) => s,
}; };
if !session.capabilities.contains_key(JMAP_CORE_CAPABILITY) { if !session.capabilities.contains_key(JMAP_CORE_CAPABILITY) {
let err = Error::new(format!("Server {} did not return JMAP Core capability ({core_capability}). Returned capabilities were: {}", &self.server_conf.server_url, session.capabilities.keys().map(String::as_str).collect::<Vec<&str>>().join(", "), core_capability=JMAP_CORE_CAPABILITY)); let err = Error::new(format!(
"Server {} did not return JMAP Core capability ({core_capability}). Returned \
capabilities were: {}",
&self.server_conf.server_url,
session
.capabilities
.keys()
.map(String::as_str)
.collect::<Vec<&str>>()
.join(", "),
core_capability = JMAP_CORE_CAPABILITY
));
*self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *self.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
*self.store.core_capabilities.lock().unwrap() = *self.store.core_capabilities.lock().unwrap() =
session.capabilities[JMAP_CORE_CAPABILITY].clone(); session.capabilities[JMAP_CORE_CAPABILITY].clone();
if !session.capabilities.contains_key(JMAP_MAIL_CAPABILITY) { if !session.capabilities.contains_key(JMAP_MAIL_CAPABILITY) {
let err = Error::new(format!("Server {} does not support JMAP Mail capability ({mail_capability}). Returned capabilities were: {}", &self.server_conf.server_url, session.capabilities.keys().map(String::as_str).collect::<Vec<&str>>().join(", "), mail_capability=JMAP_MAIL_CAPABILITY)); let err = Error::new(format!(
"Server {} does not support JMAP Mail capability ({mail_capability}). Returned \
capabilities were: {}",
&self.server_conf.server_url,
session
.capabilities
.keys()
.map(String::as_str)
.collect::<Vec<&str>>()
.join(", "),
mail_capability = JMAP_MAIL_CAPABILITY
));
*self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *self.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
@ -266,15 +288,8 @@ impl JmapConnection {
let res_text = res.text().await?; let res_text = res.text().await?;
debug!(&res_text); debug!(&res_text);
let mut v: MethodResponse = match serde_json::from_str(&res_text) { let mut v: MethodResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!(
"BUG: Could not deserialize {} server JSON response properly, please \
report this!\nReply from server: {}",
&self.server_conf.server_url, &res_text
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug);
*self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *self.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
@ -446,11 +461,10 @@ impl JmapConnection {
let res_text = res.text().await?; let res_text = res.text().await?;
debug!(&res_text); debug!(&res_text);
let _: MethodResponse = match serde_json::from_str(&res_text) { let _: MethodResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &self.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug);
*self.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
log::error!("{}", &err); log::error!("{}", &err);
*self.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
Ok(s) => s, Ok(s) => s,

@ -337,7 +337,7 @@ impl std::convert::From<EmailObject> for crate::Envelope {
pub struct HtmlBody { pub struct HtmlBody {
pub blob_id: Id<BlobObject>, pub blob_id: Id<BlobObject>,
#[serde(default)] #[serde(default)]
pub charset: String, pub charset: Option<String>,
#[serde(default)] #[serde(default)]
pub cid: Option<String>, pub cid: Option<String>,
#[serde(default)] #[serde(default)]
@ -364,7 +364,7 @@ pub struct HtmlBody {
pub struct TextBody { pub struct TextBody {
pub blob_id: Id<BlobObject>, pub blob_id: Id<BlobObject>,
#[serde(default)] #[serde(default)]
pub charset: String, pub charset: Option<String>,
#[serde(default)] #[serde(default)]
pub cid: Option<String>, pub cid: Option<String>,
#[serde(default)] #[serde(default)]
@ -854,16 +854,9 @@ pub struct EmailQueryChangesResponse {
impl std::convert::TryFrom<&RawValue> for EmailQueryChangesResponse { impl std::convert::TryFrom<&RawValue> for EmailQueryChangesResponse {
type Error = crate::error::Error; type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<Self> {
let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { fn try_from(t: &RawValue) -> std::result::Result<Self, Self::Error> {
crate::error::Error::new(format!( let res: (String, Self, String) = deserialize_from_str(t.get())?;
"BUG: Could not deserialize server JSON response properly, please report \
this!\nReply from server: {}",
&t
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug)
})?;
assert_eq!(&res.0, "Email/queryChanges"); assert_eq!(&res.0, "Email/queryChanges");
Ok(res.1) Ok(res.1)
} }

@ -196,16 +196,9 @@ pub struct ImportResponse {
impl std::convert::TryFrom<&RawValue> for ImportResponse { impl std::convert::TryFrom<&RawValue> for ImportResponse {
type Error = crate::error::Error; type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<Self> { fn try_from(t: &RawValue) -> Result<Self> {
let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { let res: (String, Self, String) = deserialize_from_str(t.get())?;
crate::error::Error::new(format!(
"BUG: Could not deserialize server JSON response properly, please report \
this!\nReply from server: {}",
&t
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug)
})?;
assert_eq!(&res.0, &ImportCall::NAME); assert_eq!(&res.0, &ImportCall::NAME);
Ok(res.1) Ok(res.1)
} }

@ -19,9 +19,10 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>. * along with meli. If not, see <http://www.gnu.org/licenses/>.
*/ */
use super::*;
use core::marker::PhantomData; use core::marker::PhantomData;
use super::*;
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ThreadObject { pub struct ThreadObject {

@ -49,8 +49,7 @@ impl BackendOp for JmapOp {
fn as_bytes(&mut self) -> ResultFuture<Vec<u8>> { fn as_bytes(&mut self) -> ResultFuture<Vec<u8>> {
{ {
let byte_lck = self.store.byte_cache.lock().unwrap(); let byte_lck = self.store.byte_cache.lock().unwrap();
if byte_lck.contains_key(&self.hash) && byte_lck[&self.hash].bytes.is_some() { if let Some(Some(ret)) = byte_lck.get(&self.hash).map(|c| c.bytes.clone()) {
let ret = byte_lck[&self.hash].bytes.clone().unwrap();
return Ok(Box::pin(async move { Ok(ret.into_bytes()) })); return Ok(Box::pin(async move { Ok(ret.into_bytes()) }));
} }
} }

@ -90,7 +90,7 @@ pub async fn get_mailboxes(conn: &JmapConnection) -> Result<HashMap<MailboxHash,
}))?) }))?)
.await?; .await?;
let mut v: MethodResponse = serde_json::from_str(&res_text).unwrap(); let mut v: MethodResponse = deserialize_from_str(&res_text)?;
*conn.store.online_status.lock().await = (std::time::Instant::now(), Ok(())); *conn.store.online_status.lock().await = (std::time::Instant::now(), Ok(()));
let m = GetResponse::<MailboxObject>::try_from(v.method_responses.remove(0))?; let m = GetResponse::<MailboxObject>::try_from(v.method_responses.remove(0))?;
let GetResponse::<MailboxObject> { let GetResponse::<MailboxObject> {
@ -191,15 +191,8 @@ pub async fn get_message_list(
.await?; .await?;
let res_text = res.text().await?; let res_text = res.text().await?;
let mut v: MethodResponse = match serde_json::from_str(&res_text) { let mut v: MethodResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!(
"BUG: Could not deserialize {} server JSON response properly, please report \
this!\nReply from server: {}",
&conn.server_conf.server_url, &res_text
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug);
*conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);
} }
@ -259,7 +252,7 @@ impl EmailFetchState {
let current_state_lck = mbox.email_state.lock().unwrap(); let current_state_lck = mbox.email_state.lock().unwrap();
( (
current_state_lck.is_none(), current_state_lck.is_none(),
current_state_lck.as_ref() != Some(&state), current_state_lck.as_ref() == Some(&state),
) )
}) })
.unwrap_or((true, true)) .unwrap_or((true, true))
@ -324,15 +317,8 @@ impl EmailFetchState {
let _prev_seq = req.add_call(&email_call); let _prev_seq = req.add_call(&email_call);
let res_text = conn.send_request(serde_json::to_string(&req)?).await?; let res_text = conn.send_request(serde_json::to_string(&req)?).await?;
let mut v: MethodResponse = match serde_json::from_str(&res_text) { let mut v: MethodResponse = match deserialize_from_str(&res_text) {
Err(err) => { Err(err) => {
let err = Error::new(format!(
"BUG: Could not deserialize {} server JSON response properly, please report \
this!\nReply from server: {}",
&conn.server_conf.server_url, &res_text
))
.set_source(Some(Arc::new(err)))
.set_kind(ErrorKind::Bug);
*conn.store.online_status.lock().await = *conn.store.online_status.lock().await =
(Instant::now(), Err(err.clone())); (Instant::now(), Err(err.clone()));
return Err(err); return Err(err);

@ -42,7 +42,7 @@ use std::collections::HashMap;
pub use argument::*; pub use argument::*;
use super::protocol::Method; use super::{deserialize_from_str, protocol::Method};
pub trait Object { pub trait Object {
const NAME: &'static str; const NAME: &'static str;
} }
@ -282,7 +282,6 @@ impl Object for BlobObject {
/// - `account_id`: `Id` /// - `account_id`: `Id`
/// ///
/// The id of the account to use. /// The id of the account to use.
///
#[derive(Deserialize, Clone, Debug)] #[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Get<OBJ> pub struct Get<OBJ>
@ -427,16 +426,9 @@ pub struct GetResponse<OBJ: Object> {
impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for GetResponse<OBJ> { impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for GetResponse<OBJ> {
type Error = crate::error::Error; type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<Self, crate::error::Error> { fn try_from(t: &RawValue) -> Result<Self, crate::error::Error> {
let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { let res: (String, Self, String) = deserialize_from_str(t.get())?;
crate::error::Error::new(format!(
"BUG: Could not deserialize server JSON response properly, please report \
this!\nReply from server: {}",
&t
))
.set_source(Some(Arc::new(err)))
.set_kind(crate::error::ErrorKind::Bug)
})?;
assert_eq!(&res.0, &format!("{}/get", OBJ::NAME)); assert_eq!(&res.0, &format!("{}/get", OBJ::NAME));
Ok(res.1) Ok(res.1)
} }
@ -548,16 +540,9 @@ pub struct QueryResponse<OBJ: Object> {
impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for QueryResponse<OBJ> { impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for QueryResponse<OBJ> {
type Error = crate::error::Error; type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<Self, crate::error::Error> {
let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { fn try_from(t: &RawValue) -> std::result::Result<Self, Self::Error> {
crate::error::Error::new(format!( let res: (String, Self, String) = deserialize_from_str(t.get())?;
"BUG: Could not deserialize server JSON response properly, please report \
this!\nReply from server: {}",
&t
))
.set_source(Some(Arc::new(err)))
.set_kind(crate::error::ErrorKind::Bug)
})?;
assert_eq!(&res.0, &format!("{}/query", OBJ::NAME)); assert_eq!(&res.0, &format!("{}/query", OBJ::NAME));
Ok(res.1) Ok(res.1)
} }
@ -618,7 +603,6 @@ impl<M: Method<OBJ>, OBJ: Object> ResultField<M, OBJ> {
/// to return. If supplied by the client, the value MUST be a /// to return. If supplied by the client, the value MUST be a
/// positive integer greater than 0. If a value outside of this range /// positive integer greater than 0. If a value outside of this range
/// is given, the server MUST re /// is given, the server MUST re
///
#[derive(Deserialize, Serialize, Clone, Debug)] #[derive(Deserialize, Serialize, Clone, Debug)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
/* ch-ch-ch-ch-ch-Changes */ /* ch-ch-ch-ch-ch-Changes */
@ -697,16 +681,9 @@ pub struct ChangesResponse<OBJ: Object> {
impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for ChangesResponse<OBJ> { impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for ChangesResponse<OBJ> {
type Error = crate::error::Error; type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<Self, crate::error::Error> {
let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { fn try_from(t: &RawValue) -> std::result::Result<Self, Self::Error> {
crate::error::Error::new(format!( let res: (String, Self, String) = deserialize_from_str(t.get())?;
"BUG: Could not deserialize server JSON response properly, please report \
this!\nReply from server: {}",
&t
))
.set_source(Some(Arc::new(err)))
.set_kind(crate::error::ErrorKind::Bug)
})?;
assert_eq!(&res.0, &format!("{}/changes", OBJ::NAME)); assert_eq!(&res.0, &format!("{}/changes", OBJ::NAME));
Ok(res.1) Ok(res.1)
} }
@ -911,16 +888,9 @@ pub struct SetResponse<OBJ: Object> {
impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for SetResponse<OBJ> { impl<OBJ: Object + DeserializeOwned> std::convert::TryFrom<&RawValue> for SetResponse<OBJ> {
type Error = crate::error::Error; type Error = crate::error::Error;
fn try_from(t: &RawValue) -> Result<Self, crate::error::Error> { fn try_from(t: &RawValue) -> Result<Self, crate::error::Error> {
let res: (String, Self, String) = serde_json::from_str(t.get()).map_err(|err| { let res: (String, Self, String) = deserialize_from_str(t.get())?;
crate::error::Error::new(format!(
"BUG: Could not deserialize server JSON response properly, please report \
this!\nReply from server: {}",
&t
))
.set_source(Some(Arc::new(err)))
.set_kind(crate::error::ErrorKind::Bug)
})?;
assert_eq!(&res.0, &format!("{}/set", OBJ::NAME)); assert_eq!(&res.0, &format!("{}/set", OBJ::NAME));
Ok(res.1) Ok(res.1)
} }
@ -1038,6 +1008,16 @@ pub fn download_request_format(
} else if download_url[prev_pos..].starts_with("{name}") { } else if download_url[prev_pos..].starts_with("{name}") {
ret.push_str(name.as_deref().unwrap_or("")); ret.push_str(name.as_deref().unwrap_or(""));
prev_pos += "{name}".len(); prev_pos += "{name}".len();
} else if download_url[prev_pos..].starts_with("{type}") {
ret.push_str("application/octet-stream");
prev_pos += "{name}".len();
} else {
// [ref:FIXME]: return protocol error here
log::error!(
"BUG: unknown parameter in download url: {}",
&download_url[prev_pos..]
);
break;
} }
} }
if prev_pos != download_url.len() { if prev_pos != download_url.len() {

Loading…
Cancel
Save