diff --git a/Cargo.lock b/Cargo.lock index 45ef734..6cc4276 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -416,6 +416,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-getters" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74ef43543e701c01ad77d3a5922755c6a1d71b22d942cb8042be4994b380caff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + [[package]] name = "derive_builder" version = "0.20.1" @@ -1618,6 +1629,7 @@ dependencies = [ "chrono", "cmake", "dateparser", + "derive-getters", "derive_builder", "derive_more", "derive_setters", diff --git a/Cargo.toml b/Cargo.toml index e87fb9b..f4ba7d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ dateparser = "0.2.0" derive_builder = "0.20" derive_more = "0.99" derive_setters = "0.1" +derive-getters = "0.5" fancy-regex = "0.11" flagset = { version = "0.4", optional = true } futures-util = "0.3" diff --git a/src/formdata.rs b/src/formdata.rs index ec631d6..c54a4b2 100644 --- a/src/formdata.rs +++ b/src/formdata.rs @@ -1,29 +1,45 @@ use derive_builder::Builder; +use derive_getters::Getters; use derive_setters::Setters; use reqwest::header::HeaderMap; use reqwest::multipart::{Form, Part}; use std::path::{Path, PathBuf}; -#[derive(Debug, derive_more::From)] +#[derive(derive_more::From)] pub enum FormDataBody { Data(Vec), File(PathBuf), } -#[derive(Builder, Debug, Setters)] +impl std::fmt::Debug for FormDataBody { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Data(d) => match std::str::from_utf8(d) { + Ok(d) => f.debug_tuple("Data").field(&d).finish(), + Err(_) => f.debug_tuple("Data").field(d).finish(), + }, + Self::File(p) => f.debug_tuple("File").field(p).finish(), + } + } +} + +#[derive(Builder, Getters, Setters)] #[builder(pattern = "owned", setter(strip_option))] #[setters(borrow_self, into)] /// Part of form pub struct FormDataPart { #[builder(default, setter(into))] + #[getter(rename = "get_mime")] #[setters(strip_option)] /// Mime type mime: Option, #[builder(default, setter(into))] + #[getter(rename = "get_filename")] #[setters(strip_option)] /// File name filename: Option, #[builder(default)] + #[getter(skip)] #[setters(skip)] /// HTTP headers pub headers: HeaderMap, @@ -33,11 +49,44 @@ pub struct FormDataPart { body: FormDataBody, } +impl std::fmt::Debug for FormDataPart { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.mime.is_none() && self.filename.is_none() && self.headers.is_empty() { + std::fmt::Debug::fmt(&self.body, f) + } else { + let mut p = f.debug_struct("FormDataPart"); + match &self.mime { + Some(m) => { + p.field("mime", &m.as_str()); + } + None => {} + } + match &self.filename { + Some(f) => { + p.field("filename", &f.as_str()); + } + None => {} + } + if !self.headers.is_empty() { + p.field("headers", &self.headers); + } + p.field("body", &self.body); + p.finish() + } + } +} + /// Form pub struct FormData { fields: Vec<(String, FormDataPart)>, } +impl std::fmt::Debug for FormData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("FormData").field(&self.fields).finish() + } +} + /// Error when convert [FormData] to [Form] #[derive(Debug, derive_more::Display, derive_more::From)] pub enum FormDataError { diff --git a/src/push/telegram/botapi_client.rs b/src/push/telegram/botapi_client.rs index 3a832b8..98d8783 100644 --- a/src/push/telegram/botapi_client.rs +++ b/src/push/telegram/botapi_client.rs @@ -162,6 +162,7 @@ impl BotapiClient { } None => {} } + log::debug!(target: "botapi_client", "Request Form: {:?}", form); let re = self .client .post_multipart( @@ -173,7 +174,10 @@ impl BotapiClient { .ok_or("Failed to send animation.")?; let status = re.status(); match re.text().await { - Ok(t) => Ok(serde_json::from_str(t.as_str())?), + Ok(t) => { + log::debug!(target: "botapi_client", "Response: {}", t); + Ok(serde_json::from_str(t.as_str())?) + } Err(e) => Err(format!("HTTP ERROR {}: {}", status, e))?, } } @@ -261,6 +265,7 @@ impl BotapiClient { } None => {} } + log::debug!(target: "botapi_client", "Request Form: {:?}", form); let re = self .client .post_multipart( @@ -272,7 +277,10 @@ impl BotapiClient { .ok_or("Failed to send document.")?; let status = re.status(); match re.text().await { - Ok(t) => Ok(serde_json::from_str(t.as_str())?), + Ok(t) => { + log::debug!(target: "botapi_client", "Response: {}", t); + Ok(serde_json::from_str(t.as_str())?) + } Err(e) => Err(format!("HTTP ERROR {}: {}", status, e))?, } } @@ -355,6 +363,7 @@ impl BotapiClient { } None => {} } + log::debug!(target: "botapi_client", "Request Form: {:?}", form); let re = self .client .post_multipart( @@ -366,7 +375,10 @@ impl BotapiClient { .ok_or("Failed to send photo.")?; let status = re.status(); match re.text().await { - Ok(t) => Ok(serde_json::from_str(t.as_str())?), + Ok(t) => { + log::debug!(target: "botapi_client", "Response: {}", t); + Ok(serde_json::from_str(t.as_str())?) + } Err(e) => Err(format!("HTTP ERROR {}: {}", status, e))?, } } @@ -418,6 +430,7 @@ impl BotapiClient { } None => {} } + log::debug!(target: "botapi_client", "Request Form: {:?}", form); let re = self .client .post_multipart( @@ -429,7 +442,10 @@ impl BotapiClient { .ok_or("Failed to send media group.")?; let status = re.status(); match re.text().await { - Ok(t) => Ok(serde_json::from_str(t.as_str())?), + Ok(t) => { + log::debug!(target: "botapi_client", "Response: {}", t); + Ok(serde_json::from_str(t.as_str())?) + } Err(e) => Err(format!("HTTP ERROR {}: {}", status, e))?, } } @@ -491,6 +507,7 @@ impl BotapiClient { } None => {} } + log::debug!(target: "botapi_client", "Request params: {:?}", params); let re = self .client .post( @@ -502,7 +519,10 @@ impl BotapiClient { .ok_or("Failed to send message.")?; let status = re.status(); match re.text().await { - Ok(t) => Ok(serde_json::from_str(t.as_str())?), + Ok(t) => { + log::debug!(target: "botapi_client", "Response: {}", t); + Ok(serde_json::from_str(t.as_str())?) + } Err(e) => Err(format!("HTTP ERROR {}: {}", status, e))?, } } @@ -625,6 +645,7 @@ impl BotapiClient { } None => {} } + log::debug!(target: "botapi_client", "Request Form: {:?}", form); let re = self .client .post_multipart( @@ -636,7 +657,10 @@ impl BotapiClient { .ok_or("Failed to send video.")?; let status = re.status(); match re.text().await { - Ok(t) => Ok(serde_json::from_str(t.as_str())?), + Ok(t) => { + log::debug!(target: "botapi_client", "Response: {}", t); + Ok(serde_json::from_str(t.as_str())?) + } Err(e) => Err(format!("HTTP ERROR {}: {}", status, e))?, } } diff --git a/src/push/telegram/tg_type.rs b/src/push/telegram/tg_type.rs index 1f53e2b..8b7cac5 100644 --- a/src/push/telegram/tg_type.rs +++ b/src/push/telegram/tg_type.rs @@ -1,4 +1,4 @@ -use crate::formdata::FormDataPart; +use crate::formdata::{FormDataBody, FormDataPart}; use derive_builder::Builder; use derive_more::From; use serde::{Deserialize, Serialize}; @@ -187,6 +187,21 @@ pub enum InputFile { Content(FormDataPart), } +impl InputFile { + pub async fn get_size(&self) -> Result, std::io::Error> { + match self { + Self::URL(_) => Ok(None), + Self::Content(c) => match c.body() { + FormDataBody::Data(d) => Ok(Some(d.len() as u64)), + FormDataBody::File(f) => { + let m = tokio::fs::metadata(f).await?; + Ok(Some(m.len())) + } + }, + } + } +} + #[derive(Builder, Clone, Debug, Deserialize, Serialize)] #[builder(setter(into))] /// Represents an audio file to be treated as music to be sent.