Add possibility to download files synchronously.
GitOrigin-RevId: 2b633fcc06a8d8770a6fb31a0d0bd9dac971df9e
This commit is contained in:
parent
ad2690b2a6
commit
db66ddf0be
@ -118,7 +118,7 @@ namespace TdApp
|
|||||||
{
|
{
|
||||||
var args = command.Split(" ".ToCharArray(), 2);
|
var args = command.Split(" ".ToCharArray(), 2);
|
||||||
AcceptCommand(command);
|
AcceptCommand(command);
|
||||||
_client.Send(new TdApi.DownloadFile(Int32.Parse(args[1]), 1, 0, 0), _handler);
|
_client.Send(new TdApi.DownloadFile(Int32.Parse(args[1]), 1, 0, 0, false), _handler);
|
||||||
}
|
}
|
||||||
else if (command.StartsWith("bench"))
|
else if (command.StartsWith("bench"))
|
||||||
{
|
{
|
||||||
|
@ -3099,12 +3099,14 @@ resetAllNotificationSettings = Ok;
|
|||||||
setPinnedChats chat_ids:vector<int53> = Ok;
|
setPinnedChats chat_ids:vector<int53> = Ok;
|
||||||
|
|
||||||
|
|
||||||
//@description Asynchronously downloads a file from the cloud. updateFile will be used to notify about the download progress and successful completion of the download. Returns file state just after the download has been started
|
//@description Downloads a file from the cloud. Download progress and completion of the download will be notified through updateFile updates
|
||||||
//@file_id Identifier of the file to download
|
//@file_id Identifier of the file to download
|
||||||
//@priority Priority of the download (1-32). The higher the priority, the earlier the file will be downloaded. If the priorities of two files are equal, then the last one for which downloadFile was called will be downloaded first
|
//@priority Priority of the download (1-32). The higher the priority, the earlier the file will be downloaded. If the priorities of two files are equal, then the last one for which downloadFile was called will be downloaded first
|
||||||
//@offset File will be downloaded starting from that offset in bytes first. Supposed to be used for streaming
|
//@offset File will be downloaded starting from that offset in bytes first. Supposed to be used for streaming
|
||||||
//@limit Download will be automatically cancelled when at least limit bytes are downloaded starting from the specified offset; use 0 to download without limit
|
//@limit Download will be automatically cancelled when at least limit bytes are downloaded starting from the specified offset; use 0 to download without limit
|
||||||
downloadFile file_id:int32 priority:int32 offset:int32 limit:int32 = File;
|
//@synchronous If false, this request returns file state just after the download has been started. If true, this request returns file state only after
|
||||||
|
//-the download has succeeded, has failed, has been cancelled or a new downloadFile request with different offset/limit parameters was sent
|
||||||
|
downloadFile file_id:int32 priority:int32 offset:int32 limit:int32 synchronous:Bool = File;
|
||||||
|
|
||||||
//@description Returns file downloaded prefix size from a given offset @file_id Identifier of the file @offset Offset from which downloaded prefix size should be calculated
|
//@description Returns file downloaded prefix size from a given offset @file_id Identifier of the file @offset Offset from which downloaded prefix size should be calculated
|
||||||
getFileDownloadedPrefixSize file_id:int32 offset:int32 = Count;
|
getFileDownloadedPrefixSize file_id:int32 offset:int32 = Count;
|
||||||
|
Binary file not shown.
@ -3915,9 +3915,11 @@ class Td::DownloadFileCallback : public FileManager::DownloadCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_download_ok(FileId file_id) override {
|
void on_download_ok(FileId file_id) override {
|
||||||
|
send_closure(G()->td(), &Td::on_file_download_finished, file_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_download_error(FileId file_id, Status error) override {
|
void on_download_error(FileId file_id, Status error) override {
|
||||||
|
send_closure(G()->td(), &Td::on_file_download_finished, file_id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5734,18 +5736,67 @@ void Td::on_request(uint64 id, const td_api::downloadFile &request) {
|
|||||||
if (!(1 <= priority && priority <= 32)) {
|
if (!(1 <= priority && priority <= 32)) {
|
||||||
return send_error_raw(id, 5, "Download priority must be in [1;32] range");
|
return send_error_raw(id, 5, "Download priority must be in [1;32] range");
|
||||||
}
|
}
|
||||||
if (request.offset_ < 0) {
|
auto offset = request.offset_;
|
||||||
|
if (offset < 0) {
|
||||||
return send_error_raw(id, 5, "Download offset must be non-negative");
|
return send_error_raw(id, 5, "Download offset must be non-negative");
|
||||||
}
|
}
|
||||||
file_manager_->download(FileId(request.file_id_, 0), download_file_callback_, priority, request.offset_,
|
auto limit = request.limit_;
|
||||||
request.limit_);
|
if (limit < 0) {
|
||||||
|
return send_error_raw(id, 5, "Download limit must be non-negative");
|
||||||
|
}
|
||||||
|
|
||||||
auto file = file_manager_->get_file_object(FileId(request.file_id_, 0), false);
|
FileId file_id(request.file_id_, 0);
|
||||||
if (file->id_ == 0) {
|
auto file_view = file_manager_->get_file_view(file_id);
|
||||||
|
if (file_view.empty()) {
|
||||||
return send_error_raw(id, 400, "Invalid file id");
|
return send_error_raw(id, 400, "Invalid file id");
|
||||||
}
|
}
|
||||||
|
|
||||||
send_closure(actor_id(this), &Td::send_result, id, std::move(file));
|
auto info_it = pending_file_downloads_.find(file_id);
|
||||||
|
DownloadInfo *info = info_it == pending_file_downloads_.end() ? nullptr : &info_it->second;
|
||||||
|
if (info != nullptr && (offset != info->offset || limit != info->limit)) {
|
||||||
|
// we can't have two pending requests with different offset and limit, so cancel all previous requests
|
||||||
|
for (auto request_id : info->request_ids) {
|
||||||
|
send_closure(actor_id(this), &Td::send_error, request_id,
|
||||||
|
Status::Error(200, "Cancelled by another downloadFile request"));
|
||||||
|
}
|
||||||
|
info->request_ids.clear();
|
||||||
|
}
|
||||||
|
if (request.synchronous_) {
|
||||||
|
if (info == nullptr) {
|
||||||
|
info = &pending_file_downloads_[file_id];
|
||||||
|
}
|
||||||
|
info->offset = offset;
|
||||||
|
info->limit = limit;
|
||||||
|
info->request_ids.push_back(id);
|
||||||
|
}
|
||||||
|
file_manager_->download(file_id, download_file_callback_, priority, offset, limit);
|
||||||
|
if (!request.synchronous_) {
|
||||||
|
send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(file_id, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Td::on_file_download_finished(FileId file_id) {
|
||||||
|
auto it = pending_file_downloads_.find(file_id);
|
||||||
|
if (it == pending_file_downloads_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto id : it->second.request_ids) {
|
||||||
|
// there was send_closure to call this function
|
||||||
|
auto file_object = file_manager_->get_file_object(file_id, false);
|
||||||
|
CHECK(file_object != nullptr);
|
||||||
|
auto download_offset = file_object->local_->download_offset_;
|
||||||
|
auto downloaded_size = file_object->local_->downloaded_prefix_size_;
|
||||||
|
auto file_size = file_object->size_;
|
||||||
|
if (file_object->local_->is_downloading_completed_ ||
|
||||||
|
(download_offset <= it->second.offset && download_offset + downloaded_size >= it->second.offset &&
|
||||||
|
((file_size != 0 && download_offset + downloaded_size == file_size) ||
|
||||||
|
download_offset + downloaded_size - it->second.offset >= it->second.limit))) {
|
||||||
|
send_result(id, std::move(file_object));
|
||||||
|
} else {
|
||||||
|
send_error_impl(id, td_api::make_object<td_api::error>(400, "File download has failed or was cancelled"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pending_file_downloads_.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Td::on_request(uint64 id, const td_api::cancelDownloadFile &request) {
|
void Td::on_request(uint64 id, const td_api::cancelDownloadFile &request) {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "td/telegram/files/FileId.h"
|
||||||
#include "td/telegram/net/MtprotoHeader.h"
|
#include "td/telegram/net/MtprotoHeader.h"
|
||||||
#include "td/telegram/net/NetQuery.h"
|
#include "td/telegram/net/NetQuery.h"
|
||||||
#include "td/telegram/StateManager.h"
|
#include "td/telegram/StateManager.h"
|
||||||
@ -275,6 +276,13 @@ class Td final : public NetQueryCallback {
|
|||||||
|
|
||||||
TermsOfService pending_terms_of_service_;
|
TermsOfService pending_terms_of_service_;
|
||||||
|
|
||||||
|
struct DownloadInfo {
|
||||||
|
int32 offset = -1;
|
||||||
|
int32 limit = -1;
|
||||||
|
vector<uint64> request_ids;
|
||||||
|
};
|
||||||
|
std::unordered_map<FileId, DownloadInfo, FileIdHash> pending_file_downloads_;
|
||||||
|
|
||||||
vector<std::pair<uint64, td_api::object_ptr<td_api::Function>>> pending_preauthentication_requests_;
|
vector<std::pair<uint64, td_api::object_ptr<td_api::Function>>> pending_preauthentication_requests_;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -303,6 +311,8 @@ class Td final : public NetQueryCallback {
|
|||||||
|
|
||||||
void clear_requests();
|
void clear_requests();
|
||||||
|
|
||||||
|
void on_file_download_finished(FileId file_id);
|
||||||
|
|
||||||
static bool is_internal_config_option(Slice name);
|
static bool is_internal_config_option(Slice name);
|
||||||
|
|
||||||
void on_config_option_updated(const string &name);
|
void on_config_option_updated(const string &name);
|
||||||
|
@ -2371,7 +2371,7 @@ class CliClient final : public Actor {
|
|||||||
send_request(td_api::make_object<td_api::getMapThumbnailFile>(
|
send_request(td_api::make_object<td_api::getMapThumbnailFile>(
|
||||||
as_location(latitude, longitude), to_integer<int32>(zoom), to_integer<int32>(width),
|
as_location(latitude, longitude), to_integer<int32>(zoom), to_integer<int32>(width),
|
||||||
to_integer<int32>(height), to_integer<int32>(scale), as_chat_id(chat_id)));
|
to_integer<int32>(height), to_integer<int32>(scale), as_chat_id(chat_id)));
|
||||||
} else if (op == "df" || op == "DownloadFile" || op == "dff") {
|
} else if (op == "df" || op == "DownloadFile" || op == "dff" || op == "dfs") {
|
||||||
string file_id;
|
string file_id;
|
||||||
string priority;
|
string priority;
|
||||||
string offset;
|
string offset;
|
||||||
@ -2386,8 +2386,8 @@ class CliClient final : public Actor {
|
|||||||
int32 max_file_id = as_file_id(file_id);
|
int32 max_file_id = as_file_id(file_id);
|
||||||
int32 min_file_id = (op == "dff" ? 1 : max_file_id);
|
int32 min_file_id = (op == "dff" ? 1 : max_file_id);
|
||||||
for (int32 i = min_file_id; i <= max_file_id; i++) {
|
for (int32 i = min_file_id; i <= max_file_id; i++) {
|
||||||
send_request(td_api::make_object<td_api::downloadFile>(i, to_integer<int32>(priority),
|
send_request(td_api::make_object<td_api::downloadFile>(
|
||||||
to_integer<int32>(offset), to_integer<int32>(limit)));
|
i, to_integer<int32>(priority), to_integer<int32>(offset), to_integer<int32>(limit), op == "dfs"));
|
||||||
}
|
}
|
||||||
} else if (op == "cdf") {
|
} else if (op == "cdf") {
|
||||||
send_request(td_api::make_object<td_api::cancelDownloadFile>(as_file_id(args), false));
|
send_request(td_api::make_object<td_api::cancelDownloadFile>(as_file_id(args), false));
|
||||||
|
@ -1900,6 +1900,13 @@ void FileManager::download(FileId file_id, std::shared_ptr<DownloadCallback> cal
|
|||||||
node->set_download_limit(limit);
|
node->set_download_limit(limit);
|
||||||
auto *file_info = get_file_id_info(file_id);
|
auto *file_info = get_file_id_info(file_id);
|
||||||
CHECK(new_priority == 0 || callback);
|
CHECK(new_priority == 0 || callback);
|
||||||
|
if (file_info->download_callback_ != nullptr && file_info->download_callback_.get() != callback.get()) {
|
||||||
|
// the callback will be destroyed soon and lost forever
|
||||||
|
// this would be an error and should never happen, unless we cancel previous download query
|
||||||
|
// in that case we send an error to the callback
|
||||||
|
CHECK(new_priority == 0);
|
||||||
|
file_info->download_callback_->on_download_error(file_id, Status::Error(200, "Cancelled"));
|
||||||
|
}
|
||||||
file_info->download_priority_ = narrow_cast<int8>(new_priority);
|
file_info->download_priority_ = narrow_cast<int8>(new_priority);
|
||||||
file_info->download_callback_ = std::move(callback);
|
file_info->download_callback_ = std::move(callback);
|
||||||
// TODO: send current progress?
|
// TODO: send current progress?
|
||||||
|
@ -615,7 +615,7 @@ class CheckTestC : public Task {
|
|||||||
if (text.substr(0, tag_.size()) == tag_) {
|
if (text.substr(0, tag_.size()) == tag_) {
|
||||||
file_id_to_check_ = messageDocument->document_->document_->id_;
|
file_id_to_check_ = messageDocument->document_->document_->id_;
|
||||||
LOG(ERROR) << "GOT FILE " << to_string(messageDocument->document_->document_);
|
LOG(ERROR) << "GOT FILE " << to_string(messageDocument->document_->document_);
|
||||||
this->send_query(make_tl_object<td_api::downloadFile>(file_id_to_check_, 1, 0, 0),
|
this->send_query(make_tl_object<td_api::downloadFile>(file_id_to_check_, 1, 0, 0, false),
|
||||||
[](auto res) { check_td_error(res); });
|
[](auto res) { check_td_error(res); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user