mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated smartcontract code
- updated smartcontract code - fixed bug in liteserver listening socket - updated documentation
This commit is contained in:
parent
38c3e39066
commit
b978e27b2f
63 changed files with 3185 additions and 81 deletions
|
@ -56,8 +56,10 @@ class Client::Impl final {
|
|||
std::shared_ptr<OutputQueue> output_queue_;
|
||||
};
|
||||
|
||||
scheduler_.run_in_context(
|
||||
[&] { tonlib_ = td::actor::create_actor<TonlibClient>("Tonlib", td::make_unique<Callback>(output_queue_)); });
|
||||
scheduler_.run_in_context([&] {
|
||||
tonlib_ = td::actor::create_actor<TonlibClient>(td::actor::ActorOptions().with_name("Tonlib").with_poll(),
|
||||
td::make_unique<Callback>(output_queue_));
|
||||
});
|
||||
|
||||
scheduler_thread_ = td::thread([&] { scheduler_.run(); });
|
||||
}
|
||||
|
@ -107,7 +109,7 @@ class Client::Impl final {
|
|||
std::atomic<bool> receive_lock_{false};
|
||||
bool is_closed_{false};
|
||||
|
||||
td::actor::Scheduler scheduler_{{0}};
|
||||
td::actor::Scheduler scheduler_{{1}};
|
||||
td::thread scheduler_thread_;
|
||||
td::actor::ActorOwn<TonlibClient> tonlib_;
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
#include "tonlib/LastBlock.h"
|
||||
|
||||
namespace tonlib {
|
||||
ExtClient::~ExtClient() {
|
||||
last_block_queries_.for_each([](auto id, auto &promise) { promise.set_error(TonlibError::Cancelled()); });
|
||||
queries_.for_each([](auto id, auto &promise) { promise.set_error(TonlibError::Cancelled()); });
|
||||
}
|
||||
void ExtClient::with_last_block(td::Promise<LastBlockState> promise) {
|
||||
auto query_id = last_block_queries_.create(std::move(promise));
|
||||
td::Promise<LastBlockState> P = [query_id, self = this,
|
||||
|
|
|
@ -53,6 +53,7 @@ class ExtClient {
|
|||
ExtClientRef get_client() {
|
||||
return client_;
|
||||
}
|
||||
~ExtClient();
|
||||
|
||||
void with_last_block(td::Promise<LastBlockState> promise);
|
||||
|
||||
|
|
|
@ -36,11 +36,22 @@ td::StringBuilder& operator<<(td::StringBuilder& sb, const LastBlockState& state
|
|||
<< td::tag("init_block", state.init_block_id.to_str());
|
||||
}
|
||||
|
||||
LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, td::unique_ptr<Callback> callback)
|
||||
: state_(std::move(state)), config_(std::move(config)), callback_(std::move(callback)) {
|
||||
LastBlock::LastBlock(ExtClientRef client, LastBlockState state, Config config, td::CancellationToken cancellation_token,
|
||||
td::unique_ptr<Callback> callback)
|
||||
: callback_(std::move(callback))
|
||||
, state_(std::move(state))
|
||||
, config_(std::move(config))
|
||||
, cancellation_token_(std::move(cancellation_token)) {
|
||||
client_.set_client(client);
|
||||
state_.last_block_id = state_.last_key_block_id;
|
||||
|
||||
if (state_.last_key_block_id.is_valid()) {
|
||||
min_seqno_ = state_.last_key_block_id.id.seqno;
|
||||
}
|
||||
if (config_.init_block_id.is_valid() && config_.init_block_id != state_.init_block_id) {
|
||||
min_seqno_ = td::min(min_seqno_, config_.init_block_id.id.seqno);
|
||||
}
|
||||
current_seqno_ = min_seqno_;
|
||||
VLOG(last_block) << "State: " << state_;
|
||||
}
|
||||
|
||||
|
@ -61,6 +72,9 @@ void LastBlock::get_last_block(td::Promise<LastBlockState> promise) {
|
|||
}
|
||||
|
||||
void LastBlock::sync_loop() {
|
||||
SCOPE_EXIT {
|
||||
update_sync_state();
|
||||
};
|
||||
if (promises_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -147,7 +161,7 @@ td::Result<std::unique_ptr<block::BlockProofChain>> LastBlock::process_block_pro
|
|||
return td::Status::Error(PSLICE() << "block proof chain starts from block " << chain->from.to_str()
|
||||
<< ", not from requested block " << from.to_str());
|
||||
}
|
||||
TRY_STATUS(chain->validate());
|
||||
TRY_STATUS(chain->validate(cancellation_token_));
|
||||
return std::move(chain);
|
||||
}
|
||||
|
||||
|
@ -155,6 +169,8 @@ void LastBlock::update_state(block::BlockProofChain& chain) {
|
|||
// Update state_
|
||||
bool is_changed = false;
|
||||
is_changed |= update_mc_last_block(chain.to);
|
||||
current_seqno_ = td::max(current_seqno_, chain.to.id.seqno);
|
||||
max_seqno_ = td::max(max_seqno_, current_seqno_);
|
||||
if (chain.has_key_block) {
|
||||
is_changed |= update_mc_last_key_block(chain.key_blkid);
|
||||
}
|
||||
|
@ -193,10 +209,10 @@ void LastBlock::on_block_proof(
|
|||
if (chain->complete) {
|
||||
VLOG(last_block) << "get_last_block: done\n" << get_last_block_stats_;
|
||||
get_last_block_state_ = QueryState::Done;
|
||||
sync_loop();
|
||||
} else {
|
||||
do_get_last_block();
|
||||
}
|
||||
sync_loop();
|
||||
}
|
||||
|
||||
void LastBlock::on_init_block_proof(
|
||||
|
@ -209,6 +225,7 @@ void LastBlock::on_init_block_proof(
|
|||
check_init_block_state_ = QueryState::Empty;
|
||||
VLOG(last_block) << "check_init_block: error " << r_chain.error();
|
||||
on_sync_error(r_chain.move_as_error_suffix("(during check init block)"));
|
||||
sync_loop();
|
||||
return;
|
||||
}
|
||||
auto chain = r_chain.move_as_ok();
|
||||
|
@ -220,10 +237,10 @@ void LastBlock::on_init_block_proof(
|
|||
if (update_init_block(config_.init_block_id)) {
|
||||
save_state();
|
||||
}
|
||||
sync_loop();
|
||||
} else {
|
||||
do_check_init_block(chain->to, to);
|
||||
}
|
||||
sync_loop();
|
||||
}
|
||||
|
||||
void LastBlock::on_masterchain_info(
|
||||
|
@ -233,6 +250,7 @@ void LastBlock::on_masterchain_info(
|
|||
update_zero_state(create_zero_state_id(info->init_), "masterchain info");
|
||||
// last block is not validated! Do not update it
|
||||
get_mc_info_state_ = QueryState::Done;
|
||||
max_seqno_ = td::max(max_seqno_, (unsigned)info->last_->seqno_);
|
||||
VLOG(last_block) << "get_masterchain_info: done";
|
||||
} else {
|
||||
get_mc_info_state_ = QueryState::Empty;
|
||||
|
@ -334,6 +352,9 @@ void LastBlock::on_sync_ok() {
|
|||
}
|
||||
void LastBlock::on_sync_error(td::Status status) {
|
||||
VLOG(last_block) << "sync: error " << status;
|
||||
if (cancellation_token_) {
|
||||
status = TonlibError::Cancelled();
|
||||
}
|
||||
for (auto& promise : promises_) {
|
||||
promise.set_error(status.clone());
|
||||
}
|
||||
|
@ -348,4 +369,32 @@ void LastBlock::on_fatal_error(td::Status status) {
|
|||
bool LastBlock::has_fatal_error() const {
|
||||
return fatal_error_.is_error();
|
||||
}
|
||||
|
||||
LastBlockSyncState LastBlock::get_sync_state() {
|
||||
LastBlockSyncState state;
|
||||
if (promises_.empty()) {
|
||||
state.type = LastBlockSyncState::Done;
|
||||
return state;
|
||||
}
|
||||
state.type = LastBlockSyncState::InProgress;
|
||||
state.from_seqno = min_seqno_;
|
||||
state.to_seqno = max_seqno_;
|
||||
state.current_seqno = current_seqno_;
|
||||
return state;
|
||||
}
|
||||
|
||||
void LastBlock::update_sync_state() {
|
||||
auto new_state = get_sync_state();
|
||||
if (new_state == sync_state_) {
|
||||
return;
|
||||
}
|
||||
sync_state_ = new_state;
|
||||
VLOG(last_block) << "Sync state: " << current_seqno_ - min_seqno_ << " / " << max_seqno_ - min_seqno_;
|
||||
callback_->on_sync_state_changed(sync_state_);
|
||||
}
|
||||
|
||||
void LastBlock::tear_down() {
|
||||
on_sync_error(TonlibError::Cancelled());
|
||||
}
|
||||
|
||||
} // namespace tonlib
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "tonlib/Config.h"
|
||||
#include "tonlib/ExtClient.h"
|
||||
|
||||
#include "td/utils/CancellationToken.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
namespace block {
|
||||
|
@ -132,6 +133,20 @@ struct LastBlockState {
|
|||
}
|
||||
};
|
||||
|
||||
struct LastBlockSyncState {
|
||||
enum Type { Invalid, InProgress, Done } type = Invalid;
|
||||
td::int32 from_seqno{0};
|
||||
td::int32 to_seqno{0};
|
||||
td::int32 current_seqno{0};
|
||||
|
||||
auto as_key() const {
|
||||
return std::tie(type, from_seqno, to_seqno, current_seqno);
|
||||
}
|
||||
bool operator==(const LastBlockSyncState &other) const {
|
||||
return as_key() == other.as_key();
|
||||
}
|
||||
};
|
||||
|
||||
class LastBlock : public td::actor::Actor {
|
||||
public:
|
||||
class Callback {
|
||||
|
@ -139,16 +154,19 @@ class LastBlock : public td::actor::Actor {
|
|||
virtual ~Callback() {
|
||||
}
|
||||
virtual void on_state_changed(LastBlockState state) = 0;
|
||||
virtual void on_sync_state_changed(LastBlockSyncState state) = 0;
|
||||
};
|
||||
|
||||
explicit LastBlock(ExtClientRef client, LastBlockState state, Config config, td::unique_ptr<Callback> callback);
|
||||
explicit LastBlock(ExtClientRef client, LastBlockState state, Config config, td::CancellationToken cancellation_token,
|
||||
td::unique_ptr<Callback> callback);
|
||||
void get_last_block(td::Promise<LastBlockState> promise);
|
||||
|
||||
private:
|
||||
td::unique_ptr<Callback> callback_;
|
||||
ExtClient client_;
|
||||
LastBlockState state_;
|
||||
Config config_;
|
||||
td::unique_ptr<Callback> callback_;
|
||||
td::CancellationToken cancellation_token_;
|
||||
|
||||
td::Status fatal_error_;
|
||||
|
||||
|
@ -157,6 +175,11 @@ class LastBlock : public td::actor::Actor {
|
|||
QueryState check_init_block_state_{QueryState::Empty}; // init_block <---> last_key_block (from older to newer)
|
||||
QueryState get_last_block_state_{QueryState::Empty}; // last_key_block_id --> ?
|
||||
|
||||
unsigned min_seqno_ = 0;
|
||||
unsigned current_seqno_ = 0;
|
||||
unsigned max_seqno_ = 0;
|
||||
LastBlockSyncState sync_state_;
|
||||
|
||||
// stats
|
||||
struct Stats {
|
||||
td::Timer total_sync_;
|
||||
|
@ -209,6 +232,10 @@ class LastBlock : public td::actor::Actor {
|
|||
void on_fatal_error(td::Status status);
|
||||
bool has_fatal_error() const;
|
||||
|
||||
LastBlockSyncState get_sync_state();
|
||||
void update_sync_state();
|
||||
void sync_loop();
|
||||
|
||||
void tear_down() override;
|
||||
};
|
||||
} // namespace tonlib
|
||||
|
|
|
@ -166,6 +166,9 @@ class GetTransactionHistory : public td::actor::Actor {
|
|||
hash_),
|
||||
[self = this](auto r_transactions) { self->with_transactions(std::move(r_transactions)); });
|
||||
}
|
||||
void hangup() override {
|
||||
check(TonlibError::Cancelled());
|
||||
}
|
||||
};
|
||||
|
||||
class GetRawAccountState : public td::actor::Actor {
|
||||
|
@ -277,6 +280,9 @@ class GetRawAccountState : public td::actor::Actor {
|
|||
stop();
|
||||
}
|
||||
}
|
||||
void hangup() override {
|
||||
check(TonlibError::Cancelled());
|
||||
}
|
||||
};
|
||||
|
||||
TonlibClient::TonlibClient(td::unique_ptr<TonlibCallback> callback) : callback_(std::move(callback)) {
|
||||
|
@ -284,6 +290,7 @@ TonlibClient::TonlibClient(td::unique_ptr<TonlibCallback> callback) : callback_(
|
|||
TonlibClient::~TonlibClient() = default;
|
||||
|
||||
void TonlibClient::hangup() {
|
||||
source_.cancel();
|
||||
is_closing_ = true;
|
||||
ref_cnt_--;
|
||||
raw_client_ = {};
|
||||
|
@ -300,7 +307,7 @@ ExtClientRef TonlibClient::get_client_ref() {
|
|||
}
|
||||
|
||||
void TonlibClient::proxy_request(td::int64 query_id, std::string data) {
|
||||
callback_->on_result(0, tonlib_api::make_object<tonlib_api::updateSendLiteServerQuery>(query_id, data));
|
||||
on_update(tonlib_api::make_object<tonlib_api::updateSendLiteServerQuery>(query_id, data));
|
||||
}
|
||||
|
||||
void TonlibClient::init_ext_client() {
|
||||
|
@ -342,8 +349,28 @@ void TonlibClient::init_ext_client() {
|
|||
}
|
||||
|
||||
void TonlibClient::update_last_block_state(LastBlockState state, td::uint32 config_generation) {
|
||||
if (config_generation == config_generation_) {
|
||||
last_block_storage_.save_state(blockchain_name_, state);
|
||||
if (config_generation != config_generation_) {
|
||||
return;
|
||||
}
|
||||
last_block_storage_.save_state(blockchain_name_, state);
|
||||
}
|
||||
|
||||
void TonlibClient::update_sync_state(LastBlockSyncState state, td::uint32 config_generation) {
|
||||
if (config_generation != config_generation_) {
|
||||
return;
|
||||
}
|
||||
switch (state.type) {
|
||||
case LastBlockSyncState::Done:
|
||||
on_update(
|
||||
tonlib_api::make_object<tonlib_api::updateSyncState>(tonlib_api::make_object<tonlib_api::syncStateDone>()));
|
||||
break;
|
||||
case LastBlockSyncState::InProgress:
|
||||
on_update(
|
||||
tonlib_api::make_object<tonlib_api::updateSyncState>(tonlib_api::make_object<tonlib_api::syncStateInProgress>(
|
||||
state.from_seqno, state.to_seqno, state.current_seqno)));
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << "Unknown LastBlockSyncState type " << state.type;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -357,6 +384,9 @@ void TonlibClient::init_last_block() {
|
|||
void on_state_changed(LastBlockState state) override {
|
||||
send_closure(client_, &TonlibClient::update_last_block_state, std::move(state), config_generation_);
|
||||
}
|
||||
void on_sync_state_changed(LastBlockSyncState sync_state) override {
|
||||
send_closure(client_, &TonlibClient::update_sync_state, std::move(sync_state), config_generation_);
|
||||
}
|
||||
|
||||
private:
|
||||
td::actor::ActorShared<TonlibClient> client_;
|
||||
|
@ -379,19 +409,23 @@ void TonlibClient::init_last_block() {
|
|||
state = r_state.move_as_ok();
|
||||
}
|
||||
|
||||
raw_last_block_ =
|
||||
td::actor::create_actor<LastBlock>("LastBlock", get_client_ref(), std::move(state), config_,
|
||||
td::make_unique<Callback>(td::actor::actor_shared(this), config_generation_));
|
||||
raw_last_block_ = td::actor::create_actor<LastBlock>(
|
||||
td::actor::ActorOptions().with_name("LastBlock").with_poll(false), get_client_ref(), std::move(state), config_,
|
||||
source_.get_cancellation_token(), td::make_unique<Callback>(td::actor::actor_shared(this), config_generation_));
|
||||
}
|
||||
|
||||
void TonlibClient::on_result(td::uint64 id, tonlib_api::object_ptr<tonlib_api::Object> response) {
|
||||
VLOG(tonlib_query) << "Tonlib answer query " << td::tag("id", id) << " " << to_string(response);
|
||||
VLOG_IF(tonlib_query, id != 0) << "Tonlib answer query " << td::tag("id", id) << " " << to_string(response);
|
||||
VLOG_IF(tonlib_query, id == 0) << "Tonlib update " << to_string(response);
|
||||
if (response->get_id() == tonlib_api::error::ID) {
|
||||
callback_->on_error(id, tonlib_api::move_object_as<tonlib_api::error>(response));
|
||||
return;
|
||||
}
|
||||
callback_->on_result(id, std::move(response));
|
||||
}
|
||||
void TonlibClient::on_update(object_ptr<tonlib_api::Object> response) {
|
||||
on_result(0, std::move(response));
|
||||
}
|
||||
|
||||
void TonlibClient::request(td::uint64 id, tonlib_api::object_ptr<tonlib_api::Function> function) {
|
||||
VLOG(tonlib_query) << "Tonlib got query " << td::tag("id", id) << " " << to_string(function);
|
||||
|
@ -415,7 +449,9 @@ void TonlibClient::request(td::uint64 id, tonlib_api::object_ptr<tonlib_api::Fun
|
|||
|
||||
downcast_call(*function, [this, self = this, id](auto& request) {
|
||||
using ReturnType = typename std::decay_t<decltype(request)>::ReturnType;
|
||||
td::Promise<ReturnType> promise = [actor_id = actor_id(self), id](td::Result<ReturnType> r_result) {
|
||||
ref_cnt_++;
|
||||
td::Promise<ReturnType> promise = [actor_id = actor_id(self), id,
|
||||
tmp = actor_shared(self)](td::Result<ReturnType> r_result) {
|
||||
tonlib_api::object_ptr<tonlib_api::Object> result;
|
||||
if (r_result.is_error()) {
|
||||
result = status_to_tonlib_api(r_result.error());
|
||||
|
@ -647,6 +683,7 @@ td::Status TonlibClient::do_request(const tonlib_api::close& request,
|
|||
td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
CHECK(state_ != State::Closed);
|
||||
state_ = State::Closed;
|
||||
source_.cancel();
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
@ -1257,6 +1294,9 @@ class GenericSendGrams : public TonlibQueryActor {
|
|||
void start_up() override {
|
||||
check(do_start_up());
|
||||
}
|
||||
void hangup() override {
|
||||
check(TonlibError::Cancelled());
|
||||
}
|
||||
|
||||
td::Status do_start_up() {
|
||||
if (!send_grams_.destination_) {
|
||||
|
@ -1426,6 +1466,15 @@ td::Status TonlibClient::do_request(tonlib_api::generic_sendGrams& request,
|
|||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Status TonlibClient::do_request(tonlib_api::sync& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise) {
|
||||
client_.with_last_block([promise = std::move(promise)](td::Result<LastBlockState> r_last_block) mutable {
|
||||
TRY_RESULT_PROMISE(promise, last_block, std::move(r_last_block));
|
||||
(void)last_block;
|
||||
promise.set_value(tonlib_api::make_object<tonlib_api::ok>());
|
||||
});
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
td::Result<block::PublicKey> public_key_from_bytes(td::Slice bytes) {
|
||||
TRY_RESULT_PREFIX(key_bytes, block::PublicKey::from_bytes(bytes), TonlibError::Internal());
|
||||
return key_bytes;
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include "td/utils/CancellationToken.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace tonlib {
|
||||
|
@ -66,6 +68,8 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::actor::ActorOwn<LastBlock> raw_last_block_;
|
||||
ExtClient client_;
|
||||
|
||||
td::CancellationTokenSource source_;
|
||||
|
||||
std::map<td::int64, td::actor::ActorOwn<>> actors_;
|
||||
td::int64 actor_id_{1};
|
||||
|
||||
|
@ -92,7 +96,9 @@ class TonlibClient : public td::actor::Actor {
|
|||
}
|
||||
|
||||
void update_last_block_state(LastBlockState state, td::uint32 config_generation_);
|
||||
void update_sync_state(LastBlockSyncState state, td::uint32 config_generation);
|
||||
void on_result(td::uint64 id, object_ptr<tonlib_api::Object> response);
|
||||
void on_update(object_ptr<tonlib_api::Object> response);
|
||||
static bool is_static_request(td::int32 id);
|
||||
static bool is_uninited_request(td::int32 id);
|
||||
template <class T>
|
||||
|
@ -159,6 +165,8 @@ class TonlibClient : public td::actor::Actor {
|
|||
td::Status do_request(tonlib_api::generic_sendGrams& request,
|
||||
td::Promise<object_ptr<tonlib_api::sendGramsResult>>&& promise);
|
||||
|
||||
td::Status do_request(tonlib_api::sync& request, td::Promise<object_ptr<tonlib_api::ok>>&& promise);
|
||||
|
||||
td::Status do_request(const tonlib_api::createNewKey& request, td::Promise<object_ptr<tonlib_api::key>>&& promise);
|
||||
td::Status do_request(const tonlib_api::exportKey& request,
|
||||
td::Promise<object_ptr<tonlib_api::exportedKey>>&& promise);
|
||||
|
|
|
@ -94,7 +94,7 @@ class TonlibCli : public td::actor::Actor {
|
|||
td::actor::ActorShared<TonlibCli> id_;
|
||||
};
|
||||
ref_cnt_++;
|
||||
client_ = td::actor::create_actor<tonlib::TonlibClient>("Tonlib", td::make_unique<TonlibCb>(actor_shared(this)));
|
||||
client_ = td::actor::create_actor<tonlib::TonlibClient>("Tonlib", td::make_unique<TonlibCb>(actor_shared(this, 1)));
|
||||
|
||||
td::mkdir(options_.key_dir).ignore();
|
||||
|
||||
|
@ -144,6 +144,9 @@ class TonlibCli : public td::actor::Actor {
|
|||
void hangup_shared() override {
|
||||
CHECK(ref_cnt_ > 0);
|
||||
ref_cnt_--;
|
||||
if (get_link_token() == 1) {
|
||||
io_.reset();
|
||||
}
|
||||
try_stop();
|
||||
}
|
||||
void try_stop() {
|
||||
|
@ -221,7 +224,6 @@ class TonlibCli : public td::actor::Actor {
|
|||
generate_key();
|
||||
} else if (cmd == "exit") {
|
||||
is_closing_ = true;
|
||||
io_.reset();
|
||||
client_.reset();
|
||||
ref_cnt_--;
|
||||
try_stop();
|
||||
|
@ -263,9 +265,20 @@ class TonlibCli : public td::actor::Actor {
|
|||
set_bounceable(addr, to_bool(bounceable, true));
|
||||
} else if (cmd == "netstats") {
|
||||
dump_netstats();
|
||||
} else if (cmd == "sync") {
|
||||
sync();
|
||||
}
|
||||
}
|
||||
|
||||
void sync() {
|
||||
using tonlib_api::make_object;
|
||||
send_query(make_object<tonlib_api::sync>(), [](auto r_ok) {
|
||||
LOG_IF(ERROR, r_ok.is_error()) << r_ok.error();
|
||||
if (r_ok.is_ok()) {
|
||||
td::TerminalIO::out() << "synchronized\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
void dump_netstats() {
|
||||
td::TerminalIO::out() << td::tag("snd", td::format::as_size(snd_bytes_)) << "\n";
|
||||
td::TerminalIO::out() << td::tag("rcv", td::format::as_size(rcv_bytes_)) << "\n";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue