diff options
Diffstat (limited to 'protocols/Telegram/tdlib/td/td/telegram/files/FileHashUploader.cpp')
-rw-r--r-- | protocols/Telegram/tdlib/td/td/telegram/files/FileHashUploader.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/protocols/Telegram/tdlib/td/td/telegram/files/FileHashUploader.cpp b/protocols/Telegram/tdlib/td/td/telegram/files/FileHashUploader.cpp new file mode 100644 index 0000000000..2408e16df4 --- /dev/null +++ b/protocols/Telegram/tdlib/td/td/telegram/files/FileHashUploader.cpp @@ -0,0 +1,142 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/files/FileHashUploader.h" + +#include "td/telegram/telegram_api.h" + +#include "td/telegram/Global.h" +#include "td/telegram/net/NetQueryDispatcher.h" + +#include "td/utils/buffer.h" +#include "td/utils/crypto.h" +#include "td/utils/logging.h" +#include "td/utils/MimeType.h" +#include "td/utils/misc.h" +#include "td/utils/PathView.h" +#include "td/utils/port/Fd.h" +#include "td/utils/port/FileFd.h" +#include "td/utils/Status.h" + +namespace td { +void FileHashUploader::start_up() { + auto status = init(); + if (status.is_error()) { + callback_->on_error(std::move(status)); + stop_flag_ = true; + return; + } +} +Status FileHashUploader::init() { + TRY_RESULT(fd, FileFd::open(local_.path_, FileFd::Read)); + if (fd.get_size() != size_) { + return Status::Error("size mismatch"); + } + fd_ = BufferedFd<FileFd>(std::move(fd)); + sha256_init(&sha256_state_); + + resource_state_.set_unit_size(1024); + resource_state_.update_estimated_limit(size_); + return Status::OK(); +} +void FileHashUploader::loop() { + if (stop_flag_) { + return; + } + + auto status = loop_impl(); + if (status.is_error()) { + callback_->on_error(std::move(status)); + stop_flag_ = true; + return; + } +} + +Status FileHashUploader::loop_impl() { + if (state_ == CalcSha) { + TRY_STATUS(loop_sha()); + } + if (state_ == NetRequest) { + // messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document; + auto hash = BufferSlice(32); + sha256_final(&sha256_state_, hash.as_slice()); + auto mime_type = MimeType::from_extension(PathView(local_.path_).extension(), "image/gif"); + auto query = + telegram_api::messages_getDocumentByHash(std::move(hash), static_cast<int32>(size_), std::move(mime_type)); + LOG(INFO) << "Send getDocumentByHash request: " << to_string(query); + auto ptr = G()->net_query_creator().create(create_storer(query)); + G()->net_query_dispatcher().dispatch_with_callback(std::move(ptr), actor_shared(this)); + state_ = WaitNetResult; + } + return Status::OK(); +} + +Status FileHashUploader::loop_sha() { + auto limit = resource_state_.unused(); + if (limit == 0) { + return Status::OK(); + } + if (limit > size_left_) { + limit = size_left_; + } + resource_state_.start_use(limit); + + fd_.update_flags(Fd::Flag::Read); + TRY_RESULT(read_size, fd_.flush_read(static_cast<size_t>(limit))); + if (read_size != static_cast<size_t>(limit)) { + return Status::Error("unexpected end of file"); + } + while (true) { + auto ready = fd_.input_buffer().prepare_read(); + if (ready.empty()) { + break; + } + sha256_update(ready, &sha256_state_); + fd_.input_buffer().confirm_read(ready.size()); + } + resource_state_.stop_use(limit); + + size_left_ -= narrow_cast<int64>(read_size); + CHECK(size_left_ >= 0); + if (size_left_ == 0) { + state_ = NetRequest; + return Status::OK(); + } + return Status::OK(); +} + +void FileHashUploader::on_result(NetQueryPtr net_query) { + auto status = on_result_impl(std::move(net_query)); + if (status.is_error()) { + callback_->on_error(std::move(status)); + stop_flag_ = true; + return; + } +} + +Status FileHashUploader::on_result_impl(NetQueryPtr net_query) { + if (net_query->is_error()) { + return net_query->move_as_error(); + } + TRY_RESULT(res, fetch_result<telegram_api::messages_getDocumentByHash>(net_query->ok())); + + switch (res->get_id()) { + case telegram_api::documentEmpty::ID: + return Status::Error("Document is not found by hash"); + case telegram_api::document::ID: { + auto document = move_tl_object_as<telegram_api::document>(res); + callback_->on_ok(FullRemoteFileLocation(FileType::Document, document->id_, document->access_hash_, + DcId::internal(document->dc_id_))); + + stop_flag_ = true; + return Status::OK(); + } + default: + UNREACHABLE(); + return Status::Error("UNREACHABLE"); + } +} +} // namespace td |