fqnd / src /ui /telegram /worker_bot.rs
Haruka041
fix: remove send_document & multipart dep - minimal worker
60465b6
Raw
History Blame Contribute Delete
3.84 kB
use anyhow::Result;
use serde::de::DeserializeOwned;
use serde_json::Value;
use teloxide::types::{ChatAction, ChatId, ChatMember, Message, Update};
use reqwest::Client;
#[derive(Clone)]
pub struct WorkerBot {
client: Client,
worker_url: String,
token: String,
}
impl WorkerBot {
pub fn new(worker_url: &str, token: &str) -> Self {
let client = Client::builder()
.timeout(std::time::Duration::from_secs(30))
.build()
.expect("build client");
Self { client, worker_url: worker_url.trim_end_matches('/').to_string(), token: token.to_string() }
}
fn api_url(&self, method: &str) -> String {
format!("{}/bot{}/{}", self.worker_url, self.token, method)
}
async fn post_json<T: DeserializeOwned>(&self, method: &str, body: &Value) -> Result<T> {
let resp = self.client.post(&self.api_url(method)).json(body).send().await?;
let result: Value = resp.json().await?;
if let Some(ok) = result.get("ok").and_then(|v| v.as_bool()) {
if ok {
return Ok(serde_json::from_value(result.get("result").cloned().unwrap_or_default())?);
}
}
Err(anyhow::anyhow!("Telegram API error: {:?}", result))
}
pub async fn set_my_commands(&self, commands: Vec<teloxide::types::BotCommand>) -> Result<()> {
self.post_json::<Value>("setMyCommands", &serde_json::json!({"commands": commands})).await?;
Ok(())
}
pub async fn send_message(&self, chat_id: ChatId, text: String) -> Result<Message> {
self.post_json("sendMessage", &serde_json::json!({"chat_id": chat_id.0, "text": text})).await
}
pub async fn send_message_with_reply(&self, chat_id: ChatId, text: String, reply: serde_json::Value) -> Result<Message> {
let mut body = serde_json::json!({"chat_id": chat_id.0, "text": text, "reply_markup": reply});
self.post_json("sendMessage", &body).await
}
pub async fn edit_message_text(&self, chat_id: ChatId, msg_id: i32, text: String) -> Result<Message> {
self.post_json("editMessageText", &serde_json::json!({"chat_id": chat_id.0, "message_id": msg_id, "text": text})).await
}
pub async fn edit_message_with_reply(&self, chat_id: ChatId, msg_id: i32, text: String, reply: serde_json::Value) -> Result<Message> {
self.post_json("editMessageText", &serde_json::json!({"chat_id": chat_id.0, "message_id": msg_id, "text": text, "reply_markup": reply})).await
}
pub async fn send_chat_action(&self, chat_id: ChatId, action: ChatAction) -> Result<()> {
let action_str = format!("{:?}", action).to_lowercase();
self.post_json::<Value>("sendChatAction", &serde_json::json!({"chat_id": chat_id.0, "action": action_str})).await?;
Ok(())
}
pub async fn answer_callback_query(&self, query_id: String, text: &str) -> Result<()> {
self.post_json::<Value>("answerCallbackQuery", &serde_json::json!({"callback_query_id": query_id, "text": text})).await?;
Ok(())
}
pub async fn get_chat_member(&self, chat_id: &str, user_id: u64) -> Result<ChatMember> {
self.post_json("getChatMember", &serde_json::json!({"chat_id": chat_id, "user_id": user_id})).await
}
pub async fn get_updates(&self, offset: i64, timeout: u32) -> Result<Vec<Update>> {
let url = format!("{}?offset={}&timeout={}", self.api_url("getUpdates"), offset, timeout);
let resp = self.client.get(&url).send().await?;
let result: Value = resp.json().await?;
if let Some(ok) = result.get("ok").and_then(|v| v.as_bool()) {
if ok {
return Ok(serde_json::from_value(result.get("result").cloned().unwrap_or_default())?);
}
}
Err(anyhow::anyhow!("getUpdates error: {:?}", result))
}
}