Skip to content

Commit

Permalink
Add telegram botapi sendMessage
Browse files Browse the repository at this point in the history
  • Loading branch information
lifegpc authored Sep 20, 2024
1 parent b15bf70 commit 995ea62
Show file tree
Hide file tree
Showing 7 changed files with 447 additions and 5 deletions.
80 changes: 80 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ c_fixed_string = { version = "0.2", optional = true }
cfg-if = "1"
chrono = { version = "0.4", features = ["serde"] }
dateparser = "0.2.0"
derive_builder = "0.20"
derive_more = "0.99"
fancy-regex = "0.11"
flagset = { version = "0.4", optional = true }
Expand Down Expand Up @@ -43,11 +44,11 @@ percent-encoding = "*"
proc_macros = { path = "proc_macros" }
rand = { version = "0", optional = true }
regex = "1"
reqwest = { version = "0.11", features = ["brotli", "deflate", "gzip", "socks", "stream"] }
reqwest = { version = "0.11", features = ["brotli", "deflate", "gzip", "multipart", "socks", "stream"] }
rusqlite = { version = "0.29", features = ["bundled", "chrono"], optional = true }
RustyXML = "0.3"
serde = "1"
serde_json = { version = "1", optional = true }
serde_json = "1"
serde_urlencoded = { version = "*", optional = true }
tokio = { version = "1.27", features = ["rt", "macros", "rt-multi-thread", "time"] }
url = "2.3"
Expand All @@ -66,7 +67,7 @@ db_all = ["db", "db_sqlite"]
db_sqlite = ["rusqlite"]
docker = []
exif = ["bindgen", "c_fixed_string", "cmake", "link-cplusplus", "utf16string"]
server = ["async-trait", "base64", "db", "hex", "hyper", "multipart", "openssl", "serde_json", "rand", "serde_urlencoded"]
server = ["async-trait", "base64", "db", "hex", "hyper", "multipart", "openssl", "rand", "serde_urlencoded"]
ugoira = ["avdict", "bindgen", "cmake", "link-cplusplus"]

[patch.crates-io]
Expand Down
1 change: 0 additions & 1 deletion src/db/sqlite/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ pub enum SqliteError {
DbError(rusqlite::Error),
DatabaseVersionTooNew,
UserNameAlreadyExists,
#[cfg(feature = "serde_json")]
SerdeError(serde_json::Error),
}
1 change: 0 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub enum PixivDownloaderError {
ParseIntError(std::num::ParseIntError),
ReqwestError(reqwest::Error),
PixivAppError(crate::pixivapp::error::PixivAppError),
#[cfg(feature = "serde_json")]
SerdeJsonError(serde_json::Error),
#[cfg(feature = "serde_urlencoded")]
SerdeUrlencodedError(serde_urlencoded::ser::Error),
Expand Down
176 changes: 176 additions & 0 deletions src/push/telegram/botapi_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
use super::tg_type::*;
use crate::webclient::WebClient;
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

fn default_base() -> String {
String::from("https://api.telegram.org")
}

#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
/// Bot API Client Config
pub struct BotapiClientConfig {
#[serde(default = "default_base")]
#[builder(default = "String::from(\"https://api.telegram.org\")")]
/// Bot API Server. Default: https://api.telegram.org
pub base: String,
/// Auth token
pub token: String,
}

pub struct BotapiClient {
cfg: BotapiClientConfig,
client: WebClient,
}

#[derive(Debug, derive_more::Display, derive_more::From)]
pub enum BotapiClientError {
SerdeJson(serde_json::Error),
Str(String),
}

impl From<&str> for BotapiClientError {
fn from(value: &str) -> Self {
Self::Str(value.to_owned())
}
}

impl BotapiClient {
pub fn new(cfg: &BotapiClientConfig) -> Self {
Self {
cfg: cfg.clone(),
client: WebClient::default(),
}
}

pub async fn send_message<T: AsRef<str> + ?Sized>(
&self,
chat_id: &ChatId,
message_thread_id: Option<i64>,
text: &T,
parse_mode: Option<ParseMode>,
link_preview_options: Option<&LinkPreviewOptions>,
disable_notification: Option<bool>,
protect_content: Option<bool>,
message_effect_id: Option<&str>,
reply_parameters: Option<&ReplyParameters>,
) -> Result<BotApiResult<Message>, BotapiClientError> {
let mut params = HashMap::new();
params.insert("chat_id", chat_id.to_string());
match message_thread_id {
Some(m) => {
params.insert("message_thread_id", m.to_string());
}
None => {}
}
params.insert("text", text.as_ref().to_owned());
match parse_mode {
Some(m) => {
params.insert("parse_mode", m.as_ref().to_owned());
}
None => {}
}
match link_preview_options {
Some(m) => {
params.insert("link_preview_options", serde_json::to_string(m)?);
}
None => {}
}
match disable_notification {
Some(b) => {
params.insert("disable_notification", b.to_string());
}
None => {}
}
match protect_content {
Some(b) => {
params.insert("protect_content", b.to_string());
}
None => {}
}
match message_effect_id {
Some(b) => {
params.insert("message_effect_id", b.to_owned());
}
None => {}
}
match reply_parameters {
Some(b) => {
params.insert("reply_parameters", serde_json::to_string(b)?);
}
None => {}
}
let re = self
.client
.post(
format!("{}/bot{}/sendMessage", self.cfg.base, self.cfg.token),
None,
Some(params),
)
.await
.ok_or("Failed to send message.")?;
let status = re.status();
match re.text().await {
Ok(t) => Ok(serde_json::from_str(t.as_str())?),
Err(e) => Err(format!("HTTP ERROR {}: {}", status, e))?,
}
}
}

#[proc_macros::async_timeout_test(120s)]
#[tokio::test(flavor = "multi_thread")]
async fn test_telegram_botapi_sendmessage() {
match std::env::var("TGBOT_TOKEN") {
Ok(token) => match std::env::var("TGBOT_CHATID") {
Ok(c) => {
let cfg = BotapiClientConfigBuilder::default()
.token(token)
.build()
.unwrap();
let client = BotapiClient::new(&cfg);
let cid = ChatId::try_from(c).unwrap();
let data = client
.send_message(
&cid,
None,
"Hello world.",
None,
None,
None,
None,
None,
None,
)
.await
.unwrap()
.unwrap();
let r = ReplyParametersBuilder::default()
.message_id(data.message_id)
.build()
.unwrap();
client
.send_message(
&cid,
data.message_thread_id,
"Reply message",
None,
None,
None,
None,
None,
Some(&r),
)
.await
.unwrap()
.unwrap();
}
Err(_) => {
println!("No chat id specified, skip test.")
}
},
Err(_) => {
println!("No tg bot token specified, skip test.")
}
}
}
4 changes: 4 additions & 0 deletions src/push/telegram/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
/// Telegram Bot API Client
pub mod botapi_client;
/// Split long messages into multiple messages if needed (Only supports HTML messages)
pub mod text;
/// Telegram params type
pub mod tg_type;
Loading

0 comments on commit 995ea62

Please sign in to comment.