Skip to content

Commit

Permalink
added Api getFile and downloadFile methods
Browse files Browse the repository at this point in the history
Use Api::getFile method to get basic information about a file and prepare it for downloading.
Use Api::downloadFile method to download a file from Telegram and save it in memory.
  • Loading branch information
baderouaich committed Oct 6, 2023
1 parent ba5f585 commit c273278
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 3 deletions.
19 changes: 19 additions & 0 deletions include/tgbotxx/Api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,25 @@ namespace tgbotxx {
bool allowSendingWithoutReply = false,
const Ptr<IReplyMarkup>& replyMarkup = nullptr) const;

/// @brief Use this method to get basic information about a file and prepare it for downloading.
/// For the moment, bots can download files of up to 20MB in size.
/// The file can then be downloaded using Api::downloadFile or via the link https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> is taken from the response.
/// @param fileId File identifier to get information about
/// @returns a File object is returned on success.
/// @note It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling getFile again.
/// @note This function may not preserve the original file name and MIME type. You should save the file's MIME type and name (if available) when the File object is received.
/// @ref https://core.telegram.org/bots/api#getfile
Ptr<File> getFile(const std::string& fileId) const;

/// @brief Use this method to download a file from Telegram and save it in memory.
/// For the moment, bots can download files of up to 20MB in size. See Api::getFile.
/// The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>, where <file_path> is taken from the response.
/// @param filePath Telegram file path from Api::getFile(fileId) -> File::filePath
/// @returns std::string contains downloaded file contents.
/// @ref https://core.telegram.org/bots/api#getfile
/// @throws Exception on failure
std::string downloadFile(const std::string& filePath) const;

/// @brief Use this method to remove webhook integration if you decide to switch back to getUpdates.
/// Returns True on success.
/// @param dropPendingUpdates: Pass True to drop all pending updates.
Expand Down
32 changes: 29 additions & 3 deletions src/Api.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#include "cpr/accept_encoding.h"
#include "cpr/response.h"
#include "cpr/status_codes.h"
#include "cpr/timeout.h"
#include <exception>
#include <tgbotxx/Api.hpp>
Expand All @@ -13,7 +16,7 @@ nl::json Api::sendRequest(const std::string& endpoint, const cpr::Multipart& dat
// You can initiate multiple concurrent requests to the Telegram API, which means
// You can call sendMessage while getUpdates long polling is still pending, and you can't do that with a single cpr::Session instance.
bool hasFiles = std::any_of(data.parts.begin(), data.parts.end(), [](const cpr::Part& part) noexcept { return part.is_file; });
if(hasFiles) // Files can take longer to upload
if (hasFiles)// Files can take longer to upload
session.SetTimeout(FILES_UPLOAD_TIMEOUT);
else
session.SetTimeout(TIMEOUT);
Expand Down Expand Up @@ -319,7 +322,7 @@ Ptr<Message> Api::sendAudio(std::int64_t chatId,
data.parts.emplace_back("performer", performer);
if (not title.empty())
data.parts.emplace_back("title", title);
if(thumbnail.has_value()) {
if (thumbnail.has_value()) {
if (thumbnail->index() == 0) /* cpr::File */ {
const cpr::File& file = std::get<cpr::File>(*thumbnail);
data.parts.emplace_back("thumbnail", cpr::Files{file});
Expand Down Expand Up @@ -367,7 +370,7 @@ Ptr<Message> Api::sendDocument(std::int64_t chatId,
}
if (messageThreadId)
data.parts.emplace_back("message_thread_id", messageThreadId);
if(thumbnail.has_value()) {
if (thumbnail.has_value()) {
if (thumbnail->index() == 0) /* cpr::File */ {
const cpr::File& file = std::get<cpr::File>(*thumbnail);
data.parts.emplace_back("thumbnail", cpr::Files{file});
Expand Down Expand Up @@ -401,3 +404,26 @@ Ptr<Message> Api::sendDocument(std::int64_t chatId,
Ptr<Message> message(new Message(sentMessageObj));
return message;
}

Ptr<File> Api::getFile(const std::string& fileId) const {
cpr::Multipart data{};
data.parts.reserve(1);
data.parts.emplace_back("file_id", fileId);
nl::json fileObj = sendRequest("getFile", data);
Ptr<File> file(new File(fileObj));
return file;
}

std::string Api::downloadFile(const std::string& filePath) const {
std::ostringstream oss;
oss << BASE_URL << "/file/bot" << m_token << "/" << filePath;

cpr::Url url{oss.str()};
cpr::Timeout timeout{FILES_UPLOAD_TIMEOUT};
cpr::AcceptEncoding encoding = cpr::AcceptEncoding{{cpr::AcceptEncodingMethods::deflate, cpr::AcceptEncodingMethods::gzip, cpr::AcceptEncodingMethods::zlib}};
cpr::Response res = cpr::Get(url, timeout, encoding);
if (res.status_code == cpr::status::HTTP_OK) {
return res.text;
}
throw Exception("Failed to download file " + filePath + " with status code: " + std::to_string(res.status_code));
}

0 comments on commit c273278

Please sign in to comment.