telegram-api 0.1.1

Telegram Bot API library
Documentation
use reqwest::{Client, Error as ReqwestError};
use serde::{Deserialize, Serialize};
use std::time::Duration;

const BASE_URL: &str = "https://api.telegram.org/bot";

#[derive(Debug)]
pub enum TelegramError {
    RequestError(ReqwestError),
    ApiError(String),
}

impl From<ReqwestError> for TelegramError {
    fn from(error: ReqwestError) -> Self {
        TelegramError::RequestError(error)
    }
}

#[derive(Debug, Deserialize)]
pub struct Update {
    pub update_id: i64,
    pub message: Option<Message>,
}

#[derive(Debug, Deserialize)]
pub struct Message {
    pub message_id: i64,
    pub from: Option<User>,
    pub chat: Chat,
    pub text: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct User {
    pub id: i64,
    pub first_name: String,
    pub last_name: Option<String>,
    pub username: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct Chat {
    pub id: i64,
    pub chat_type: String,
    pub title: Option<String>,
    pub username: Option<String>,
}

#[derive(Debug, Serialize)]
pub struct SendMessageRequest {
    pub chat_id: i64,
    pub text: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reply_to_message_id: Option<i64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parse_mode: Option<String>,
}

pub struct Bot {
    token: String,
    client: Client,
}

impl Bot {
    pub fn new(token: String) -> Result<Self, TelegramError> {
        let client = Client::builder().timeout(Duration::from_secs(30)).build()?;

        Ok(Bot { token, client })
    }

    fn api_url(&self, method: &str) -> String {
        format!("{}{}/{}", BASE_URL, self.token, method)
    }

    pub async fn get_updates(&self, offset: Option<i64>) -> Result<Vec<Update>, TelegramError> {
        let mut url = self.api_url("getUpdates");
        if let Some(offset) = offset {
            url = format!("{}?offset={}", url, offset);
        }

        let response = self
            .client
            .get(&url)
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;

        if let Some(ok) = response.get("ok").and_then(|v| v.as_bool()) {
            if !ok {
                return Err(TelegramError::ApiError(
                    response
                        .get("description")
                        .and_then(|v| v.as_str())
                        .unwrap_or("Unknown API error")
                        .to_string(),
                ));
            }
        }

        let updates = response
            .get("result")
            .and_then(|v| serde_json::from_value::<Vec<Update>>(v.clone()).ok())
            .unwrap_or_default();

        Ok(updates)
    }

    pub async fn send_message(
        &self,
        request: SendMessageRequest,
    ) -> Result<Message, TelegramError> {
        let url = self.api_url("sendMessage");

        let response = self
            .client
            .post(&url)
            .json(&request)
            .send()
            .await?
            .json::<serde_json::Value>()
            .await?;

        if let Some(ok) = response.get("ok").and_then(|v| v.as_bool()) {
            if !ok {
                return Err(TelegramError::ApiError(
                    response
                        .get("description")
                        .and_then(|v| v.as_str())
                        .unwrap_or("Unknown API error")
                        .to_string(),
                ));
            }
        }

        let message = response
            .get("result")
            .and_then(|v| serde_json::from_value::<Message>(v.clone()).ok())
            .ok_or_else(|| {
                TelegramError::ApiError("Failed to parse message response".to_string())
            })?;

        Ok(message)
    }
}