/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . Copyright 2017-2020 Telegram Systems LLP */ #include "download-archive-slice.hpp" #include "td/utils/port/path.h" #include "td/utils/overloaded.h" namespace ton { namespace validator { namespace fullnode { DownloadArchiveSlice::DownloadArchiveSlice( BlockSeqno masterchain_seqno, std::string tmp_dir, adnl::AdnlNodeIdShort local_id, overlay::OverlayIdShort overlay_id, adnl::AdnlNodeIdShort download_from, td::Timestamp timeout, td::actor::ActorId validator_manager, td::actor::ActorId rldp, td::actor::ActorId overlays, td::actor::ActorId adnl, td::actor::ActorId client, td::Promise promise) : masterchain_seqno_(masterchain_seqno) , tmp_dir_(std::move(tmp_dir)) , local_id_(local_id) , overlay_id_(overlay_id) , download_from_(download_from) , timeout_(timeout) , validator_manager_(validator_manager) , rldp_(rldp) , overlays_(overlays) , adnl_(adnl) , client_(client) , promise_(std::move(promise)) { } void DownloadArchiveSlice::abort_query(td::Status reason) { if (promise_) { promise_.set_error(std::move(reason)); if (!fd_.empty()) { td::unlink(tmp_name_).ensure(); fd_.close(); } } stop(); } void DownloadArchiveSlice::alarm() { abort_query(td::Status::Error(ErrorCode::timeout, "timeout")); } void DownloadArchiveSlice::finish_query() { if (promise_) { promise_.set_value(std::move(tmp_name_)); fd_.close(); } stop(); } void DownloadArchiveSlice::start_up() { alarm_timestamp() = timeout_; auto R = td::mkstemp(tmp_dir_); if (R.is_error()) { abort_query(R.move_as_error_prefix("failed to open temp file: ")); return; } auto r = R.move_as_ok(); fd_ = std::move(r.first); tmp_name_ = std::move(r.second); if (download_from_.is_zero() && client_.empty()) { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result> R) { if (R.is_error()) { td::actor::send_closure(SelfId, &DownloadArchiveSlice::abort_query, R.move_as_error()); } else { auto vec = R.move_as_ok(); if (vec.size() == 0) { td::actor::send_closure(SelfId, &DownloadArchiveSlice::abort_query, td::Status::Error(ErrorCode::notready, "no nodes")); } else { td::actor::send_closure(SelfId, &DownloadArchiveSlice::got_node_to_download, vec[0]); } } }); td::actor::send_closure(overlays_, &overlay::Overlays::get_overlay_random_peers, local_id_, overlay_id_, 1, std::move(P)); } else { got_node_to_download(download_from_); } } void DownloadArchiveSlice::got_node_to_download(adnl::AdnlNodeIdShort download_from) { download_from_ = download_from; auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) { if (R.is_error()) { td::actor::send_closure(SelfId, &DownloadArchiveSlice::abort_query, R.move_as_error()); } else { td::actor::send_closure(SelfId, &DownloadArchiveSlice::got_archive_info, R.move_as_ok()); } }); auto q = create_serialize_tl_object(masterchain_seqno_); if (client_.empty()) { td::actor::send_closure(overlays_, &overlay::Overlays::send_query, download_from_, local_id_, overlay_id_, "get_archive_info", std::move(P), td::Timestamp::in(3.0), std::move(q)); } else { td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_archive_info", create_serialize_tl_object_suffix(std::move(q)), td::Timestamp::in(1.0), std::move(P)); } } void DownloadArchiveSlice::got_archive_info(td::BufferSlice data) { auto F = fetch_tl_object(std::move(data), true); if (F.is_error()) { abort_query(F.move_as_error_prefix("failed to parse ArchiveInfo answer")); return; } auto f = F.move_as_ok(); bool fail = false; ton_api::downcast_call(*f.get(), td::overloaded( [&](const ton_api::tonNode_archiveNotFound &obj) { abort_query(td::Status::Error(ErrorCode::notready, "remote db not found")); fail = true; }, [&](const ton_api::tonNode_archiveInfo &obj) { archive_id_ = obj.id_; })); if (fail) { return; } get_archive_slice(); } void DownloadArchiveSlice::get_archive_slice() { auto P = td::PromiseCreator::lambda([SelfId = actor_id(this)](td::Result R) { if (R.is_error()) { td::actor::send_closure(SelfId, &DownloadArchiveSlice::abort_query, R.move_as_error()); } else { td::actor::send_closure(SelfId, &DownloadArchiveSlice::got_archive_slice, R.move_as_ok()); } }); auto q = create_serialize_tl_object(archive_id_, offset_, slice_size()); if (client_.empty()) { td::actor::send_closure(overlays_, &overlay::Overlays::send_query_via, download_from_, local_id_, overlay_id_, "get_archive_slice", std::move(P), td::Timestamp::in(3.0), std::move(q), slice_size() + 1024, rldp_); } else { td::actor::send_closure(client_, &adnl::AdnlExtClient::send_query, "get_archive_slice", create_serialize_tl_object_suffix(std::move(q)), td::Timestamp::in(1.0), std::move(P)); } } void DownloadArchiveSlice::got_archive_slice(td::BufferSlice data) { auto R = fd_.write(data.as_slice()); if (R.is_error()) { abort_query(R.move_as_error_prefix("failed to write temp file: ")); return; } if (R.move_as_ok() != data.size()) { abort_query(td::Status::Error(ErrorCode::error, "short write to temp file")); return; } offset_ += data.size(); if (data.size() < slice_size()) { finish_query(); } else { get_archive_slice(); } } } // namespace fullnode } // namespace validator } // namespace ton