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(&self, method: &str, body: &Value) -> Result { 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) -> Result<()> { self.post_json::("setMyCommands", &serde_json::json!({"commands": commands})).await?; Ok(()) } pub async fn send_message(&self, chat_id: ChatId, text: String) -> Result { 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 { 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 { 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 { 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::("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::("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 { 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> { 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)) } }