mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 22:46:39 +01:00
Implement file downloading (and also add Bot::get_file
)
This commit is contained in:
parent
9f157057ec
commit
f543cc371f
6 changed files with 127 additions and 2 deletions
|
@ -14,3 +14,4 @@ apply = "0.2.2"
|
|||
derive_more = "0.15.0"
|
||||
tokio = "0.2.0-alpha.4"
|
||||
bytes = "0.4.12"
|
||||
futures-preview = "0.3.0-alpha.18"
|
|
@ -1,5 +1,7 @@
|
|||
use reqwest::r#async::Client;
|
||||
|
||||
use crate::core::network::{download_file, download_file_stream};
|
||||
use crate::core::requests::get_file::GetFile;
|
||||
use crate::core::{
|
||||
requests::{
|
||||
edit_message_live_location::EditMessageLiveLocation,
|
||||
|
@ -11,6 +13,10 @@ use crate::core::{
|
|||
},
|
||||
types::{InputFile, InputMedia},
|
||||
};
|
||||
use crate::DownloadError;
|
||||
use reqwest::r#async::Chunk;
|
||||
use tokio::io::AsyncWrite;
|
||||
use tokio::stream::Stream;
|
||||
|
||||
pub struct Bot {
|
||||
token: String,
|
||||
|
@ -42,6 +48,62 @@ impl Bot {
|
|||
|
||||
/// Telegram functions
|
||||
impl Bot {
|
||||
/// Download file from telegram into `destination`.
|
||||
/// `path` can be obtained from [`get_file`] method.
|
||||
///
|
||||
/// For downloading as Stream of Chunks see [`download_file_stream`].
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use async_telegram_bot::{
|
||||
/// bot::Bot,
|
||||
/// core::{requests::Request, types::File as TgFile},
|
||||
/// };
|
||||
/// use tokio::fs::File;
|
||||
/// # use async_telegram_bot::core::requests::RequestError;
|
||||
///
|
||||
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let bot = Bot::new("TOKEN");
|
||||
/// let mut file = File::create("/home/waffle/Pictures/test.png").await?;
|
||||
///
|
||||
/// let TgFile { file_path, .. } = bot.get_file("*file_id*").send().await?;
|
||||
/// bot.download_file(&file_path, &mut file).await?;
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
///
|
||||
/// [`get_file`]: crate::bot::Bot::get_file
|
||||
/// [`download_file_stream`]: crate::bot::Bot::download_file_stream
|
||||
pub async fn download_file<D>(
|
||||
&self,
|
||||
path: &str,
|
||||
destination: &mut D,
|
||||
) -> Result<(), DownloadError>
|
||||
where
|
||||
D: AsyncWrite + Unpin,
|
||||
{
|
||||
download_file(&self.client, &self.token, path, destination).await
|
||||
}
|
||||
|
||||
/// Download file from telegram.
|
||||
///
|
||||
/// `path` can be obtained from [`get_file`] method.
|
||||
///
|
||||
/// For downloading into [`AsyncWrite`] (e.g. [`tokio::fs::File`])
|
||||
/// see [`download_file`].
|
||||
///
|
||||
/// [`get_file`]: crate::bot::Bot::get_file
|
||||
/// [`AsyncWrite`]: tokio::io::AsyncWrite
|
||||
/// [`tokio::fs::File`]: tokio::fs::File
|
||||
/// [`download_file`]: crate::bot::Bot::download_file
|
||||
pub async fn download_file_stream(
|
||||
&self,
|
||||
path: &str,
|
||||
) -> Result<impl Stream<Item = Result<Chunk, reqwest::Error>>, reqwest::Error>
|
||||
{
|
||||
download_file_stream(&self.client, &self.token, path).await
|
||||
}
|
||||
|
||||
pub fn get_me(&self) -> GetMe {
|
||||
GetMe::new(self.ctx())
|
||||
}
|
||||
|
@ -135,4 +197,11 @@ impl Bot {
|
|||
pub fn stop_message_live_location(&self) -> StopMessageLiveLocation {
|
||||
StopMessageLiveLocation::new(self.ctx())
|
||||
}
|
||||
|
||||
pub fn get_file<F>(&self, file_id: F) -> GetFile
|
||||
where
|
||||
F: Into<String>,
|
||||
{
|
||||
GetFile::new(self.ctx(), file_id.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
mod network;
|
||||
pub(crate) mod network;
|
||||
pub mod requests;
|
||||
pub mod types;
|
||||
|
|
|
@ -3,12 +3,19 @@ use crate::core::{
|
|||
types::ResponseParameters,
|
||||
};
|
||||
|
||||
use crate::DownloadError;
|
||||
use apply::Apply;
|
||||
use bytes::Buf;
|
||||
use futures::StreamExt;
|
||||
use reqwest::r#async::Chunk;
|
||||
use reqwest::{
|
||||
r#async::{multipart::Form, Client},
|
||||
StatusCode,
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::prelude::AsyncWrite;
|
||||
use tokio::stream::Stream;
|
||||
|
||||
const TELEGRAM_API_URL: &str = "https://api.telegram.org";
|
||||
|
||||
|
@ -102,6 +109,34 @@ enum TelegramResponse<R> {
|
|||
},
|
||||
}
|
||||
|
||||
pub async fn download_file<D>(
|
||||
client: &Client,
|
||||
token: &str,
|
||||
path: &str,
|
||||
destination: &mut D,
|
||||
) -> Result<(), DownloadError>
|
||||
where
|
||||
D: AsyncWrite + Unpin,
|
||||
{
|
||||
let mut stream = download_file_stream(client, token, path).await?;
|
||||
|
||||
while let Some(chunk) = stream.next().await {
|
||||
destination.write_all(chunk?.bytes()).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn download_file_stream(
|
||||
client: &Client,
|
||||
token: &str,
|
||||
path: &str,
|
||||
) -> Result<impl Stream<Item = Result<Chunk, reqwest::Error>>, reqwest::Error> {
|
||||
let url = file_url(TELEGRAM_API_URL, token, path);
|
||||
let resp = client.get(&url).send().await?.error_for_status()?;
|
||||
Ok(resp.into_body())
|
||||
}
|
||||
|
||||
impl<R> Into<ResponseResult<R>> for TelegramResponse<R> {
|
||||
fn into(self) -> Result<R, RequestError> {
|
||||
match self {
|
||||
|
|
17
src/errors.rs
Normal file
17
src/errors.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#[derive(Debug, Display, From)]
|
||||
pub enum DownloadError {
|
||||
#[display(fmt = "Network error: {err}", err = _0)]
|
||||
NetworkError(reqwest::Error),
|
||||
|
||||
#[display(fmt = "IO Error: {err}", err = _0)]
|
||||
Io(std::io::Error),
|
||||
}
|
||||
|
||||
impl std::error::Error for DownloadError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
DownloadError::NetworkError(err) => Some(err),
|
||||
DownloadError::Io(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,3 +5,6 @@ extern crate serde;
|
|||
|
||||
pub mod bot;
|
||||
pub mod core;
|
||||
pub mod errors;
|
||||
|
||||
pub use errors::DownloadError;
|
||||
|
|
Loading…
Reference in a new issue