Merge commit '1cfa7545c938212b8976eafe3055fe161b8fd7c4'

Conflicts:
	td/telegram/Client.cpp
This commit is contained in:
Andrea Cavalli 2020-10-12 16:05:01 +02:00
commit ef9e05a805
19 changed files with 521 additions and 377 deletions

View File

@ -619,24 +619,21 @@ class TdClient {
this.TdModule = await loadTdlib(mode, this.onFS, options.wasmUrl);
log.info('got TdModule');
this.td_functions = {
td_create: this.TdModule.cwrap('td_create', 'number', []),
td_destroy: this.TdModule.cwrap('td_destroy', null, ['number']),
td_send: this.TdModule.cwrap('td_send', null, ['number', 'string']),
td_execute: this.TdModule.cwrap('td_execute', 'string', [
'number',
td_create: this.TdModule.cwrap('td_emscripten_create', 'number', []),
td_send: this.TdModule.cwrap('td_emscripten_send', null, ['number', 'string']),
td_execute: this.TdModule.cwrap('td_emscripten_execute', 'string', [
'string'
]),
td_receive: this.TdModule.cwrap('td_receive', 'string', ['number']),
td_receive: this.TdModule.cwrap('td_emscripten_receive', 'string', []),
td_set_verbosity: verbosity => {
this.td_functions.td_execute(
0,
JSON.stringify({
'@type': 'setLogVerbosityLevel',
new_verbosity_level: verbosity
})
);
},
td_get_timeout: this.TdModule.cwrap('td_get_timeout', 'number', [])
td_get_timeout: this.TdModule.cwrap('td_emscripten_get_timeout', 'number', [])
};
//this.onFS(this.TdModule.FS);
this.FS = this.TdModule.FS;
@ -849,7 +846,7 @@ class TdClient {
execute(query) {
try {
const res = this.td_functions.td_execute(0, JSON.stringify(query));
const res = this.td_functions.td_execute(JSON.stringify(query));
const response = JSON.parse(res);
this.callback(response);
} catch (error) {
@ -863,7 +860,7 @@ class TdClient {
}
try {
while (true) {
const msg = this.td_functions.td_receive(this.client);
const msg = this.td_functions.td_receive();
if (!msg) {
break;
}

View File

@ -117,11 +117,7 @@ class ClientManager::Impl final {
}
void send(ClientId client_id, RequestId request_id, td_api::object_ptr<td_api::Function> &&request) {
Request request;
request.client_id = client_id;
request.id = request_id;
request.request = std::move(request);
requests_.push_back(std::move(request));
requests_.push_back({client_id, request_id, std::move(request)});
}
Response receive(double timeout) {
@ -131,10 +127,20 @@ class ClientManager::Impl final {
Response receive(double timeout, bool include_responses, bool include_updates) {
if (!requests_.empty()) {
auto guard = concurrent_scheduler_->get_main_guard();
for (auto &request : requests_) {
auto &td = tds_[request.client_id];
CHECK(!td.empty());
send_closure_later(td, &Td::request, request.id, std::move(request.request));
for (size_t i = 0; i < requests_.size(); i++) {
auto &request = requests_[i];
if (request.client_id <= 0 || request.client_id > client_id_) {
receiver_->add_response(request.client_id, request.id,
td_api::make_object<td_api::error>(400, "Invalid TDLib instance specified"));
continue;
}
auto it = tds_.find(request.client_id);
if (it == tds_.end() || it->second.empty()) {
receiver_->add_response(request.client_id, request.id,
td_api::make_object<td_api::error>(500, "Request aborted"));
continue;
}
send_closure_later(it->second, &Td::request, request.id, std::move(request.request));
}
requests_.clear();
}
@ -146,9 +152,21 @@ class ClientManager::Impl final {
} else {
ConcurrentScheduler::emscripten_clear_main_timeout();
}
if (response.request_id == 0 && response.object != nullptr &&
response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
static_cast<const td::td_api::updateAuthorizationState *>(response.object.get())
->authorization_state_->get_id() == td::td_api::authorizationStateClosed::ID) {
auto it = tds_.find(response.client_id);
CHECK(it != tds_.end());
it->second.reset();
}
if (response.object == nullptr && response.client_id != 0 && response.request_id == 0) {
auto guard = concurrent_scheduler_->get_main_guard();
tds_.erase(response.client_id);
auto it = tds_.find(response.client_id);
CHECK(it != tds_.end());
CHECK(it->second.empty());
tds_.erase(it);
response.client_id = 0;
}
return response;
}
@ -161,7 +179,7 @@ class ClientManager::Impl final {
{
auto guard = concurrent_scheduler_->get_main_guard();
for (auto &td : tds_) {
td.second = {};
td.second.reset();
}
}
while (!tds_.empty()) {
@ -177,7 +195,7 @@ class ClientManager::Impl final {
RequestId id;
td_api::object_ptr<td_api::Function> request;
};
td::vector<Request> requests_;
vector<Request> requests_;
unique_ptr<ConcurrentScheduler> concurrent_scheduler_;
ClientId client_id_{0};
Td::Options options_;
@ -186,12 +204,11 @@ class ClientManager::Impl final {
class Client::Impl final {
public:
Impl() {
client_id_ = impl_.create_client();
Impl() : client_id_(impl_.create_client()) {
}
void send(Request request) {
impl_.send(client_id_, request.id, std::move(request.request));
impl_.send(client_id_, request.id, std::move(request.function));
}
Response receive(double timeout) {
@ -201,7 +218,7 @@ class Client::Impl final {
Response receive(double timeout, bool include_responses, bool include_updates) {
auto response = impl_.receive(timeout, include_responses, include_updates);
Response old_response;
old_response.id = response.id;
old_response.id = response.request_id;
old_response.object = std::move(response.object);
return old_response;
}
@ -238,8 +255,8 @@ class MultiTd : public Actor {
}
void close(int32 td_id) {
// no check that td_id hasn't been deleted before
tds_.erase(td_id);
size_t erased = tds_.erase(td_id);
CHECK(erased > 0);
}
private:
@ -410,6 +427,10 @@ class MultiImpl {
return id;
}
static bool is_valid_client_id(int32 client_id) {
return client_id > 0 && client_id < current_id_.load();
}
void send(ClientManager::ClientId client_id, ClientManager::RequestId request_id,
td_api::object_ptr<td_api::Function> &&request) {
auto guard = concurrent_scheduler_->get_send_guard();
@ -436,9 +457,10 @@ class MultiImpl {
thread scheduler_thread_;
ActorOwn<MultiTd> multi_td_;
static std::atomic<int32> current_id_;
static int32 create_id() {
static std::atomic<int32> current_id{1};
return current_id.fetch_add(1);
return current_id_.fetch_add(1);
}
void create(int32 td_id, unique_ptr<TdCallback> callback) {
@ -447,6 +469,8 @@ class MultiImpl {
}
};
std::atomic<int32> MultiImpl::current_id_{1};
class MultiImplPool {
public:
std::shared_ptr<MultiImpl> get() {
@ -458,12 +482,12 @@ class MultiImplPool {
}
auto &impl = *std::min_element(impls_.begin(), impls_.end(),
[](auto &a, auto &b) { return a.lock().use_count() < b.lock().use_count(); });
auto res = impl.lock();
if (!res) {
res = std::make_shared<MultiImpl>(net_query_stats_);
impl = res;
auto result = impl.lock();
if (!result) {
result = std::make_shared<MultiImpl>(net_query_stats_);
impl = result;
}
return res;
return result;
}
private:
@ -479,20 +503,24 @@ class ClientManager::Impl final {
auto client_id = impl->create(*receiver_);
{
auto lock = impls_mutex_.lock_write().move_as_ok();
impls_[client_id] = std::move(impl);
impls_[client_id].impl = std::move(impl);
}
return client_id;
}
void send(ClientId client_id, RequestId request_id, td_api::object_ptr<td_api::Function> &&request) {
auto lock = impls_mutex_.lock_read().move_as_ok();
auto it = impls_.find(client_id);
if (it == impls_.end()) {
if (!MultiImpl::is_valid_client_id(client_id)) {
receiver_->add_response(client_id, request_id,
td_api::make_object<td_api::error>(400, "Invalid TDLib instance specified"));
return;
}
it->second->send(client_id, request_id, std::move(request));
auto it = impls_.find(client_id);
if (it == impls_.end() || it->second.is_closed) {
receiver_->add_response(client_id, request_id, td_api::make_object<td_api::error>(500, "Request aborted"));
return;
}
it->second.impl->send(client_id, request_id, std::move(request));
}
Response receive(double timeout) {
@ -501,13 +529,33 @@ class ClientManager::Impl final {
Response receive(double timeout, bool include_responses, bool include_updates) {
auto response = receiver_->receive(timeout, include_responses, include_updates);
if (response.request_id == 0 && response.object != nullptr &&
response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
static_cast<const td::td_api::updateAuthorizationState *>(response.object.get())
->authorization_state_->get_id() == td::td_api::authorizationStateClosed::ID) {
auto lock = impls_mutex_.lock_write().move_as_ok();
close_impl(response.client_id);
}
if (response.object == nullptr && response.client_id != 0 && response.request_id == 0) {
auto lock = impls_mutex_.lock_write().move_as_ok();
impls_.erase(response.client_id);
auto it = impls_.find(response.client_id);
CHECK(it != impls_.end());
CHECK(it->second.is_closed);
impls_.erase(it);
response.client_id = 0;
}
return response;
}
void close_impl(ClientId client_id) {
auto it = impls_.find(client_id);
CHECK(it != impls_.end());
if (!it->second.is_closed) {
it->second.is_closed = true;
it->second.impl->close(client_id);
}
}
Impl() = default;
Impl(const Impl &) = delete;
Impl &operator=(const Impl &) = delete;
@ -515,7 +563,7 @@ class ClientManager::Impl final {
Impl &operator=(Impl &&) = delete;
~Impl() {
for (auto &it : impls_) {
it.second->close(it.first);
close_impl(it.first);
}
while (!impls_.empty()) {
receive(10, false, true);
@ -525,7 +573,11 @@ class ClientManager::Impl final {
private:
MultiImplPool pool_;
RwMutex impls_mutex_;
std::unordered_map<ClientId, std::shared_ptr<MultiImpl>> impls_;
struct MultiImplInfo {
std::shared_ptr<MultiImpl> impl;
bool is_closed = false;
};
std::unordered_map<ClientId, MultiImplInfo> impls_;
unique_ptr<TdReceiver> receiver_{make_unique<TdReceiver>()};
};
@ -538,7 +590,7 @@ class Client::Impl final {
td_id_ = multi_impl_->create(*receiver_);
}
void send(Client::Request request) {
void send(Request request) {
if (request.id == 0 || request.function == nullptr) {
LOG(ERROR) << "Drop wrong request " << request.id;
return;
@ -547,17 +599,17 @@ class Client::Impl final {
multi_impl_->send(td_id_, request.id, std::move(request.function));
}
Client::Response receive(double timeout) {
Response receive(double timeout) {
return receive(timeout, true, true);
}
Client::Response receive(double timeout, bool include_responses, bool include_updates) {
auto res = receiver_->receive(timeout, include_responses, include_updates);
Response receive(double timeout, bool include_responses, bool include_updates) {
auto response = receiver_->receive(timeout, include_responses, include_updates);
Client::Response old_res;
old_res.id = res.request_id;
old_res.object = std::move(res.object);
return old_res;
Response old_response;
old_response.id = response.request_id;
old_response.object = std::move(response.object);
return old_response;
}
Impl(const Impl &) = delete;

View File

@ -114,7 +114,7 @@ void SecretChatsManager::cancel_chat(SecretChatId secret_chat_id, Promise<> prom
void SecretChatsManager::send_message(SecretChatId secret_chat_id, tl_object_ptr<secret_api::decryptedMessage> message,
tl_object_ptr<telegram_api::InputEncryptedFile> file, Promise<> promise) {
// message->message_ = Random::fast(0, 1) ? string(1, static_cast<char>(0x80)) : "a";
// message->message_ = Random::fast_bool() ? string(1, static_cast<char>(0x80)) : "a";
auto actor = get_chat_actor(secret_chat_id.get());
auto safe_promise = SafePromise<>(std::move(promise), Status::Error(400, "Can't find secret chat"));
send_closure(actor, &SecretChatActor::send_message, std::move(message), std::move(file), std::move(safe_promise));

View File

@ -1113,7 +1113,7 @@ class CliClient final : public Actor {
std::tie(excluded_chat_ids, filter) = split(filter);
auto rand_bool = [] {
return Random::fast(0, 1) == 1;
return Random::fast_bool();
};
return td_api::make_object<td_api::chatFilter>(
@ -2753,7 +2753,7 @@ class CliClient final : public Actor {
auto chat = as_chat_id(chat_id);
send_request(td_api::make_object<td_api::forwardMessages>(
chat, as_chat_id(from_chat_id), as_message_ids(message_ids), default_message_send_options(), op[0] == 'c',
Random::fast(0, 1) == 1));
Random::fast_bool()));
} else if (op == "resend") {
string chat_id;
string message_ids;
@ -2777,7 +2777,7 @@ class CliClient final : public Actor {
} else if (op == "cc" || op == "CreateCall") {
send_request(td_api::make_object<td_api::createCall>(
as_user_id(args), td_api::make_object<td_api::callProtocol>(true, true, 65, 65, vector<string>{"2.6", "3.0"}),
Random::fast(0, 1) == 1));
Random::fast_bool()));
} else if (op == "ac" || op == "AcceptCall") {
send_request(td_api::make_object<td_api::acceptCall>(
as_call_id(args),
@ -2790,7 +2790,7 @@ class CliClient final : public Actor {
std::tie(call_id, is_disconnected) = split(args);
send_request(td_api::make_object<td_api::discardCall>(as_call_id(call_id), as_bool(is_disconnected), 0,
Random::fast(0, 1) == 1, 0));
Random::fast_bool(), 0));
} else if (op == "scr" || op == "SendCallRating") {
string call_id;
string rating;
@ -3285,8 +3285,7 @@ class CliClient final : public Actor {
td_api::object_ptr<td_api::messageCopyOptions> copy_options;
if (op == "scopy") {
copy_options =
td_api::make_object<td_api::messageCopyOptions>(true, Random::fast(0, 1) == 0, as_caption("_as_d"));
copy_options = td_api::make_object<td_api::messageCopyOptions>(true, Random::fast_bool(), as_caption("_as_d"));
}
send_message(chat_id,
@ -4353,7 +4352,7 @@ class CliClient final : public Actor {
}
BufferSlice block(it->part_size);
FileFd::open(it->source, FileFd::Flags::Read).move_as_ok().pread(block.as_slice(), it->local_size).ensure();
if (Random::fast(0, 1) == 0) {
if (Random::fast_bool()) {
auto open_flags = FileFd::Flags::Write | (it->local_size ? 0 : FileFd::Flags::Truncate | FileFd::Flags::Create);
FileFd::open(it->destination, open_flags).move_as_ok().pwrite(block.as_slice(), it->local_size).ensure();
} else {

View File

@ -13,22 +13,23 @@
extern "C" {
EMSCRIPTEN_KEEPALIVE void *td_create() {
return td_json_client_create();
EMSCRIPTEN_KEEPALIVE double td_emscripten_create() {
return td_create_client();
}
EMSCRIPTEN_KEEPALIVE void td_send(void *client, const char *query) {
td_json_client_send(client, query);
EMSCRIPTEN_KEEPALIVE void td_emscripten_send(double client_id, const char *query) {
td_send(static_cast<int>(client_id), query);
}
EMSCRIPTEN_KEEPALIVE const char *td_receive(void *client) {
return td_json_client_receive(client, 0);
EMSCRIPTEN_KEEPALIVE const char *td_emscripten_receive() {
return td_receive(0);
}
EMSCRIPTEN_KEEPALIVE const char *td_execute(void *client, const char *query) {
return td_json_client_execute(client, query);
EMSCRIPTEN_KEEPALIVE const char *td_emscripten_execute(const char *query) {
return td_execute(query);
}
EMSCRIPTEN_KEEPALIVE void td_destroy(void *client) {
td_json_client_destroy(client);
}
EMSCRIPTEN_KEEPALIVE double td_get_timeout() {
EMSCRIPTEN_KEEPALIVE double td_emscripten_get_timeout() {
return td::ConcurrentScheduler::emscripten_get_main_timeout();
}
}

View File

@ -261,7 +261,7 @@ class MainQueryActor final : public Actor {
void wakeup() override {
int cnt = 100000;
while (out_cnt_ < in_cnt_ + 100 && out_cnt_ < cnt) {
if (Random::fast(0, 1)) {
if (Random::fast_bool()) {
send_closure(rand_elem(actors_), &QueryActor::query, create_query());
} else {
send_closure_later(rand_elem(actors_), &QueryActor::query, create_query());
@ -306,7 +306,7 @@ class SimpleActor final : public Actor {
return;
}
q_++;
p_ = Random::fast(0, 1) ? 1 : 10000;
p_ = Random::fast_bool() ? 1 : 10000;
auto future = Random::fast(0, 3) == 0 ? send_promise<ActorSendType::Immediate>(worker_, &Worker::query, q_, p_)
: send_promise<ActorSendType::Later>(worker_, &Worker::query, q_, p_);
if (future.is_ready()) {

View File

@ -148,6 +148,10 @@ double Random::fast(double min, double max) {
return min + fast_uint32() * 1.0 / std::numeric_limits<uint32>::max() * (max - min);
}
bool Random::fast_bool() {
return (fast_uint32() & 1) != 0;
}
Random::Xorshift128plus::Xorshift128plus(uint64 seed) {
auto next = [&] {
// splitmix64

View File

@ -35,6 +35,7 @@ class Random {
// distribution is not uniform, min and max are included
static int fast(int min, int max);
static double fast(double min, double max);
static bool fast_bool();
class Fast {
public:

View File

@ -34,7 +34,7 @@ vector<string> rand_split(Slice str) {
size_t pos = 0;
while (pos < str.size()) {
size_t len;
if (Random::fast(0, 1) == 1) {
if (Random::fast_bool()) {
len = Random::fast(1, 10);
} else {
len = Random::fast(100, 200);

View File

@ -42,7 +42,7 @@ TEST(EpochBaseMemoryReclamation, stress) {
locker.retire();
}
if (td::Random::fast(0, 5) == 0) {
std::string *new_str = new std::string(td::Random::fast(0, 1) == 0 ? "one" : "twotwo");
std::string *new_str = new std::string(td::Random::fast_bool() ? "one" : "twotwo");
if (node.name_.compare_exchange_strong(str, new_str, std::memory_order_acq_rel)) {
locker.retire(str);
} else {

View File

@ -36,7 +36,7 @@ TEST(HazardPointers, stress) {
}
holder.clear();
if (td::Random::fast(0, 5) == 0) {
std::string *new_str = new std::string(td::Random::fast(0, 1) == 0 ? "one" : "twotwo");
std::string *new_str = new std::string(td::Random::fast_bool() ? "one" : "twotwo");
if (node.name_.compare_exchange_strong(str, new_str, std::memory_order_acq_rel)) {
hazard_pointers.retire(thread_id, str);
} else {

View File

@ -18,7 +18,7 @@ TEST(OrderedEventsProcessor, random) {
int offset = 1000000;
std::vector<std::pair<int, int>> v;
for (int i = 0; i < n; i++) {
auto shift = td::Random::fast(0, 1) ? td::Random::fast(0, d) : td::Random::fast(0, 1) * d;
auto shift = td::Random::fast_bool() ? td::Random::fast(0, d) : td::Random::fast(0, 1) * d;
v.push_back({i + shift, i + offset});
}
std::sort(v.begin(), v.end());

View File

@ -37,16 +37,16 @@ TEST(Buffer, buffer_builder) {
int r = l;
BufferBuilder builder(splitted_str[l], 123, 1000);
while (l != 0 || r != static_cast<int32>(splitted_str.size()) - 1) {
if (l == 0 || (Random::fast(0, 1) == 1 && r != static_cast<int32>(splitted_str.size() - 1))) {
if (l == 0 || (Random::fast_bool() && r != static_cast<int32>(splitted_str.size() - 1))) {
r++;
if (Random::fast(0, 1) == 1) {
if (Random::fast_bool()) {
builder.append(splitted_str[r]);
} else {
builder.append(BufferSlice(splitted_str[r]));
}
} else {
l--;
if (Random::fast(0, 1) == 1) {
if (Random::fast_bool()) {
builder.prepend(splitted_str[l]);
} else {
builder.prepend(BufferSlice(splitted_str[l]));

View File

@ -6,8 +6,6 @@
//
#include "data.h"
namespace td {
static const char thumbnail_arr[] =
"_9j_4AAQSkZJRgABAQEASABIAAD_2wBDAAICAgICAQICAgIDAgIDAwYEAwMDAwcFBQQGCAcJCAgHCAgJCg0LCQoMCggICw8LDA0ODg8OCQsQERAOEQ"
"0ODg7_2wBDAQIDAwMDAwcEBAcOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7_wAARCAAyADIDASIA"
@ -157,5 +155,3 @@ static const char sqlite_sample_db_arr[] =
const char *sqlite_sample_db = sqlite_sample_db_arr;
const size_t sqlite_sample_db_size = sizeof(sqlite_sample_db_arr) - 1;
} // namespace td

View File

@ -8,8 +8,6 @@
#include "td/utils/common.h"
namespace td {
extern const char *thumbnail;
extern const size_t thumbnail_size;
@ -18,5 +16,3 @@ extern const size_t gzip_bomb_size;
extern const char *sqlite_sample_db;
extern const size_t sqlite_sample_db_size;
} // namespace td

View File

@ -99,8 +99,8 @@ static string make_http_query(string content, bool is_chunked, bool is_gzip, dou
}
static string rand_http_query(string content) {
bool is_chunked = Random::fast(0, 1) == 0;
bool is_gzip = Random::fast(0, 1) == 0;
bool is_chunked = Random::fast_bool();
bool is_gzip = Random::fast_bool();
return make_http_query(std::move(content), is_chunked, is_gzip);
}

View File

@ -964,7 +964,7 @@ TEST(MessageEntities, fix_formatted_text) {
{td::MessageEntity::Type::Italic, 2, 11}});
for (size_t test_n = 0; test_n < 100000; test_n++) {
bool is_url = td::Random::fast(0, 1) == 1;
bool is_url = td::Random::fast_bool();
td::int32 url_offset = 0;
td::int32 url_end = 0;
if (is_url) {

View File

@ -786,7 +786,7 @@ class Master : public Actor {
return false;
}
void send_net_query(NetQueryPtr query, ActorShared<NetQueryCallback> callback, bool ordered) {
if (can_fail(query) && Random::fast(0, 1) == 0) {
if (can_fail(query) && Random::fast_bool()) {
LOG(INFO) << "Fail query " << query;
auto resend_promise =
PromiseCreator::lambda([id = actor_shared(this, get_link_token()), callback_actor = callback.get(),

File diff suppressed because it is too large Load Diff