Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2021-07-23 15:19:00 +02:00
commit a580242be1
10 changed files with 274 additions and 273 deletions

View File

@ -46,20 +46,19 @@ static Result<typename T::ReturnType> fetch_result(Slice message, bool check_end
return std::move(result); return std::move(result);
} }
AuthKeyHandshake::AuthKeyHandshake(int32 dc_id, int32 expires_in)
: mode_(expires_in == 0 ? Mode::Main : Mode::Temp), dc_id_(dc_id), expires_in_(expires_in) {
}
void AuthKeyHandshake::clear() { void AuthKeyHandshake::clear() {
last_query_ = BufferSlice(); last_query_ = BufferSlice();
state_ = Start; state_ = Start;
} }
bool AuthKeyHandshake::is_ready_for_start() const {
return state_ == Start;
}
bool AuthKeyHandshake::is_ready_for_message(const UInt128 &message_nonce) const {
return state_ != Finish && state_ != Start && nonce_ == message_nonce;
}
bool AuthKeyHandshake::is_ready_for_finish() const { bool AuthKeyHandshake::is_ready_for_finish() const {
return state_ == Finish; return state_ == Finish;
} }
void AuthKeyHandshake::on_finish() { void AuthKeyHandshake::on_finish() {
clear(); clear();
} }
@ -105,7 +104,6 @@ Status AuthKeyHandshake::on_res_pq(Slice message, Callback *connection, PublicRs
dc_id_, expires_in_)); dc_id_, expires_in_));
expires_at_ = Time::now() + expires_in_; expires_at_ = Time::now() + expires_in_;
break; break;
case Mode::Unknown:
default: default:
UNREACHABLE(); UNREACHABLE();
} }
@ -266,17 +264,6 @@ void AuthKeyHandshake::do_send(Callback *connection, const Storer &storer) {
return connection->send_no_crypto(storer); return connection->send_no_crypto(storer);
} }
Status AuthKeyHandshake::start_main(Callback *connection) {
mode_ = Mode::Main;
return on_start(connection);
}
Status AuthKeyHandshake::start_tmp(Callback *connection, int32 expires_in) {
mode_ = Mode::Temp;
expires_in_ = expires_in;
return on_start(connection);
}
void AuthKeyHandshake::resume(Callback *connection) { void AuthKeyHandshake::resume(Callback *connection) {
if (state_ == Start) { if (state_ == Start) {
return on_start(connection).ignore(); return on_start(connection).ignore();
@ -289,7 +276,7 @@ void AuthKeyHandshake::resume(Callback *connection) {
LOG(ERROR) << "Last query empty! UNREACHABLE " << state_; LOG(ERROR) << "Last query empty! UNREACHABLE " << state_;
return clear(); return clear();
} }
LOG(INFO) << "RESUME"; LOG(INFO) << "Resume handshake";
do_send(connection, create_storer(last_query_.as_slice())); do_send(connection, create_storer(last_query_.as_slice()));
} }

View File

@ -33,8 +33,6 @@ class AuthKeyHandshakeContext {
}; };
class AuthKeyHandshake { class AuthKeyHandshake {
enum class Mode { Unknown, Main, Temp };
public: public:
class Callback { class Callback {
public: public:
@ -45,44 +43,16 @@ class AuthKeyHandshake {
virtual void send_no_crypto(const Storer &storer) = 0; virtual void send_no_crypto(const Storer &storer) = 0;
}; };
AuthKeyHandshake(int32 dc_id, int32 expires_in) { AuthKeyHandshake(int32 dc_id, int32 expires_in);
dc_id_ = dc_id;
if (expires_in == 0) {
mode_ = Mode::Main;
} else {
mode_ = Mode::Temp;
expires_in_ = expires_in;
}
}
bool is_ready_for_start() const;
Status start_main(Callback *connection) TD_WARN_UNUSED_RESULT;
Status start_tmp(Callback *connection, int32 expires_in) TD_WARN_UNUSED_RESULT;
bool is_ready_for_message(const UInt128 &message_nonce) const;
bool is_ready_for_finish() const; bool is_ready_for_finish() const;
void on_finish(); void on_finish();
void init_main() {
clear();
mode_ = Mode::Main;
}
void init_temp(int32 expires_in) {
clear();
mode_ = Mode::Temp;
expires_in_ = expires_in;
}
void resume(Callback *connection); void resume(Callback *connection);
Status on_message(Slice message, Callback *connection, AuthKeyHandshakeContext *context) TD_WARN_UNUSED_RESULT; Status on_message(Slice message, Callback *connection, AuthKeyHandshakeContext *context) TD_WARN_UNUSED_RESULT;
bool is_ready() const {
return is_ready_for_finish();
}
void clear(); void clear();
const AuthKey &get_auth_key() const { const AuthKey &get_auth_key() const {
@ -102,9 +72,10 @@ class AuthKeyHandshake {
} }
private: private:
using State = enum { Start, ResPQ, ServerDHParams, DHGenResponse, Finish }; enum State : int32 { Start, ResPQ, ServerDHParams, DHGenResponse, Finish };
State state_ = Start; State state_ = Start;
Mode mode_ = Mode::Unknown; enum class Mode : int32 { Main, Temp };
Mode mode_ = Mode::Main;
int32 dc_id_ = 0; int32 dc_id_ = 0;
int32 expires_in_ = 0; int32 expires_in_ = 0;
double expires_at_ = 0; double expires_at_ = 0;

View File

@ -8416,13 +8416,14 @@ void ContactsManager::load_user_from_database_impl(UserId user_id, Promise<Unit>
G()->td_db()->get_sqlite_pmc()->get(get_user_database_key(user_id), PromiseCreator::lambda([user_id](string value) { G()->td_db()->get_sqlite_pmc()->get(get_user_database_key(user_id), PromiseCreator::lambda([user_id](string value) {
send_closure(G()->contacts_manager(), send_closure(G()->contacts_manager(),
&ContactsManager::on_load_user_from_database, user_id, &ContactsManager::on_load_user_from_database, user_id,
std::move(value)); std::move(value), false);
})); }));
} }
} }
void ContactsManager::on_load_user_from_database(UserId user_id, string value) { void ContactsManager::on_load_user_from_database(UserId user_id, string value, bool force) {
if (G()->close_flag()) { if (G()->close_flag() && !force) {
// the user is in Binlog and will be saved after restart
return; return;
} }
@ -8554,7 +8555,7 @@ ContactsManager::User *ContactsManager::get_user_force_impl(UserId user_id) {
} }
LOG(INFO) << "Trying to load " << user_id << " from database"; LOG(INFO) << "Trying to load " << user_id << " from database";
on_load_user_from_database(user_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_user_database_key(user_id))); on_load_user_from_database(user_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_user_database_key(user_id)), true);
return get_user(user_id); return get_user(user_id);
} }
@ -8709,13 +8710,14 @@ void ContactsManager::load_chat_from_database_impl(ChatId chat_id, Promise<Unit>
G()->td_db()->get_sqlite_pmc()->get(get_chat_database_key(chat_id), PromiseCreator::lambda([chat_id](string value) { G()->td_db()->get_sqlite_pmc()->get(get_chat_database_key(chat_id), PromiseCreator::lambda([chat_id](string value) {
send_closure(G()->contacts_manager(), send_closure(G()->contacts_manager(),
&ContactsManager::on_load_chat_from_database, chat_id, &ContactsManager::on_load_chat_from_database, chat_id,
std::move(value)); std::move(value), false);
})); }));
} }
} }
void ContactsManager::on_load_chat_from_database(ChatId chat_id, string value) { void ContactsManager::on_load_chat_from_database(ChatId chat_id, string value, bool force) {
if (G()->close_flag()) { if (G()->close_flag() && !force) {
// the chat is in Binlog and will be saved after restart
return; return;
} }
@ -8791,7 +8793,7 @@ ContactsManager::Chat *ContactsManager::get_chat_force(ChatId chat_id) {
} }
LOG(INFO) << "Trying to load " << chat_id << " from database"; LOG(INFO) << "Trying to load " << chat_id << " from database";
on_load_chat_from_database(chat_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_chat_database_key(chat_id))); on_load_chat_from_database(chat_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_chat_database_key(chat_id)), true);
return get_chat(chat_id); return get_chat(chat_id);
} }
@ -8947,13 +8949,14 @@ void ContactsManager::load_channel_from_database_impl(ChannelId channel_id, Prom
G()->td_db()->get_sqlite_pmc()->get( G()->td_db()->get_sqlite_pmc()->get(
get_channel_database_key(channel_id), PromiseCreator::lambda([channel_id](string value) { get_channel_database_key(channel_id), PromiseCreator::lambda([channel_id](string value) {
send_closure(G()->contacts_manager(), &ContactsManager::on_load_channel_from_database, channel_id, send_closure(G()->contacts_manager(), &ContactsManager::on_load_channel_from_database, channel_id,
std::move(value)); std::move(value), false);
})); }));
} }
} }
void ContactsManager::on_load_channel_from_database(ChannelId channel_id, string value) { void ContactsManager::on_load_channel_from_database(ChannelId channel_id, string value, bool force) {
if (G()->close_flag()) { if (G()->close_flag() && !force) {
// the channel is in Binlog and will be saved after restart
return; return;
} }
@ -9044,7 +9047,7 @@ ContactsManager::Channel *ContactsManager::get_channel_force(ChannelId channel_i
LOG(INFO) << "Trying to load " << channel_id << " from database"; LOG(INFO) << "Trying to load " << channel_id << " from database";
on_load_channel_from_database(channel_id, on_load_channel_from_database(channel_id,
G()->td_db()->get_sqlite_sync_pmc()->get(get_channel_database_key(channel_id))); G()->td_db()->get_sqlite_sync_pmc()->get(get_channel_database_key(channel_id)), true);
return get_channel(channel_id); return get_channel(channel_id);
} }
@ -9202,13 +9205,14 @@ void ContactsManager::load_secret_chat_from_database_impl(SecretChatId secret_ch
G()->td_db()->get_sqlite_pmc()->get( G()->td_db()->get_sqlite_pmc()->get(
get_secret_chat_database_key(secret_chat_id), PromiseCreator::lambda([secret_chat_id](string value) { get_secret_chat_database_key(secret_chat_id), PromiseCreator::lambda([secret_chat_id](string value) {
send_closure(G()->contacts_manager(), &ContactsManager::on_load_secret_chat_from_database, secret_chat_id, send_closure(G()->contacts_manager(), &ContactsManager::on_load_secret_chat_from_database, secret_chat_id,
std::move(value)); std::move(value), false);
})); }));
} }
} }
void ContactsManager::on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value) { void ContactsManager::on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value, bool force) {
if (G()->close_flag()) { if (G()->close_flag() && !force) {
// the secret chat is in Binlog and will be saved after restart
return; return;
} }
@ -9285,7 +9289,7 @@ ContactsManager::SecretChat *ContactsManager::get_secret_chat_force(SecretChatId
LOG(INFO) << "Trying to load " << secret_chat_id << " from database"; LOG(INFO) << "Trying to load " << secret_chat_id << " from database";
on_load_secret_chat_from_database( on_load_secret_chat_from_database(
secret_chat_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_secret_chat_database_key(secret_chat_id))); secret_chat_id, G()->td_db()->get_sqlite_sync_pmc()->get(get_secret_chat_database_key(secret_chat_id)), true);
return get_secret_chat(secret_chat_id); return get_secret_chat(secret_chat_id);
} }
@ -14686,68 +14690,81 @@ void ContactsManager::ban_dialog_participant(DialogId dialog_id,
} }
} }
DialogParticipant ContactsManager::get_dialog_participant(DialogId dialog_id, void ContactsManager::get_dialog_participant(DialogId dialog_id,
const tl_object_ptr<td_api::MessageSender> &participant_id, const tl_object_ptr<td_api::MessageSender> &participant_id,
int64 &random_id, bool force, Promise<Unit> &&promise) { Promise<td_api::object_ptr<td_api::chatMember>> &&promise) {
// TODO TRY_RESULT_PROMISE(promise, participant_dialog_id, get_participant_dialog_id(participant_id)); TRY_RESULT_PROMISE(promise, participant_dialog_id, get_participant_dialog_id(participant_id));
auto r_participant_dialog_id = get_participant_dialog_id(participant_id);
if (r_participant_dialog_id.is_error()) {
promise.set_error(r_participant_dialog_id.move_as_error());
return {};
}
auto participant_dialog_id = r_participant_dialog_id.move_as_ok();
LOG(INFO) << "Receive GetChatMember request to get " << participant_dialog_id << " in " << dialog_id auto new_promise = PromiseCreator::lambda(
<< " with random_id " << random_id; [actor_id = actor_id(this), promise = std::move(promise)](Result<DialogParticipant> &&result) mutable {
TRY_RESULT_PROMISE(promise, dialog_participant, std::move(result));
send_closure(actor_id, &ContactsManager::finish_get_dialog_participant, std::move(dialog_participant),
std::move(promise));
});
get_dialog_participant(dialog_id, participant_dialog_id, std::move(new_promise));
}
void ContactsManager::finish_get_dialog_participant(DialogParticipant &&dialog_participant,
Promise<td_api::object_ptr<td_api::chatMember>> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
auto participant_dialog_id = dialog_participant.dialog_id;
bool is_user = participant_dialog_id.get_type() == DialogType::User;
if ((is_user && !have_user(participant_dialog_id.get_user_id())) ||
(!is_user && !td_->messages_manager_->have_dialog(participant_dialog_id))) {
return promise.set_error(Status::Error(400, "Member not found"));
}
promise.set_value(get_chat_member_object(dialog_participant));
}
void ContactsManager::get_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id,
Promise<DialogParticipant> &&promise) {
LOG(INFO) << "Receive GetChatMember request to get " << participant_dialog_id << " in " << dialog_id;
if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_dialog_participant")) { if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_dialog_participant")) {
promise.set_error(Status::Error(3, "Chat not found")); return promise.set_error(Status::Error(3, "Chat not found"));
return DialogParticipant();
} }
switch (dialog_id.get_type()) { switch (dialog_id.get_type()) {
case DialogType::User: case DialogType::User:
if (participant_dialog_id == DialogId(get_my_id())) { if (participant_dialog_id == DialogId(get_my_id())) {
promise.set_value(Unit()); return promise.set_value(
return {participant_dialog_id, dialog_id.get_user_id(), 0, DialogParticipantStatus::Member()}; DialogParticipant{participant_dialog_id, dialog_id.get_user_id(), 0, DialogParticipantStatus::Member()});
} }
if (participant_dialog_id == dialog_id) { if (participant_dialog_id == dialog_id) {
promise.set_value(Unit()); return promise.set_value(
return {participant_dialog_id, get_my_id(), 0, DialogParticipantStatus::Member()}; DialogParticipant{participant_dialog_id, get_my_id(), 0, DialogParticipantStatus::Member()});
} }
promise.set_error(Status::Error(3, "Member not found")); return promise.set_error(Status::Error(3, "Member not found"));
break;
case DialogType::Chat: case DialogType::Chat:
if (participant_dialog_id.get_type() != DialogType::User) { if (participant_dialog_id.get_type() != DialogType::User) {
promise.set_value(Unit()); return promise.set_value(DialogParticipant::left(participant_dialog_id));
return DialogParticipant::left(participant_dialog_id);
} }
return get_chat_participant(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), force, return get_chat_participant(dialog_id.get_chat_id(), participant_dialog_id.get_user_id(), std::move(promise));
std::move(promise));
case DialogType::Channel: case DialogType::Channel:
return get_channel_participant(dialog_id.get_channel_id(), participant_dialog_id, random_id, force, return get_channel_participant(dialog_id.get_channel_id(), participant_dialog_id, std::move(promise));
std::move(promise));
case DialogType::SecretChat: { case DialogType::SecretChat: {
auto peer_user_id = get_secret_chat_user_id(dialog_id.get_secret_chat_id()); auto peer_user_id = get_secret_chat_user_id(dialog_id.get_secret_chat_id());
if (participant_dialog_id == DialogId(get_my_id())) { if (participant_dialog_id == DialogId(get_my_id())) {
promise.set_value(Unit()); return promise.set_value(DialogParticipant{participant_dialog_id,
return {participant_dialog_id, peer_user_id.is_valid() ? peer_user_id : get_my_id(), 0, peer_user_id.is_valid() ? peer_user_id : get_my_id(), 0,
DialogParticipantStatus::Member()}; DialogParticipantStatus::Member()});
} }
if (participant_dialog_id == DialogId(peer_user_id)) { if (participant_dialog_id == DialogId(peer_user_id)) {
promise.set_value(Unit()); return promise.set_value(
return {participant_dialog_id, get_my_id(), 0, DialogParticipantStatus::Member()}; DialogParticipant{participant_dialog_id, get_my_id(), 0, DialogParticipantStatus::Member()});
} }
promise.set_error(Status::Error(3, "Member not found")); return promise.set_error(Status::Error(3, "Member not found"));
break;
} }
case DialogType::None: case DialogType::None:
default: default:
UNREACHABLE(); UNREACHABLE();
promise.set_error(Status::Error(500, "Wrong chat type")); return promise.set_error(Status::Error(500, "Wrong chat type"));
} }
return DialogParticipant();
} }
DialogParticipants ContactsManager::search_private_chat_participants(UserId my_user_id, UserId peer_user_id, DialogParticipants ContactsManager::search_private_chat_participants(UserId my_user_id, UserId peer_user_id,
@ -14874,22 +14891,43 @@ void ContactsManager::search_dialog_participants(DialogId dialog_id, const strin
} }
} }
DialogParticipant ContactsManager::get_chat_participant(ChatId chat_id, UserId user_id, bool force, void ContactsManager::get_chat_participant(ChatId chat_id, UserId user_id, Promise<DialogParticipant> &&promise) {
Promise<Unit> &&promise) {
LOG(INFO) << "Trying to get " << user_id << " as member of " << chat_id; LOG(INFO) << "Trying to get " << user_id << " as member of " << chat_id;
if (force) {
promise.set_value(Unit());
} else if (!load_chat_full(chat_id, force, std::move(promise), "get_chat_participant")) {
return DialogParticipant();
}
// promise is already set
auto result = get_chat_participant(chat_id, user_id); auto c = get_chat(chat_id);
if (result == nullptr) { if (c == nullptr) {
return DialogParticipant::left(DialogId(user_id)); return promise.set_error(Status::Error(6, "Group not found"));
} }
return *result; auto chat_full = get_chat_full_force(chat_id, "get_chat_participant");
if (chat_full == nullptr || (td_->auth_manager_->is_bot() && is_chat_full_outdated(chat_full, c, chat_id))) {
auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), chat_id, user_id, promise = std::move(promise)](Result<Unit> &&result) mutable {
TRY_STATUS_PROMISE(promise, std::move(result));
send_closure(actor_id, &ContactsManager::finish_get_chat_participant, chat_id, user_id, std::move(promise));
});
send_get_chat_full_query(chat_id, std::move(query_promise), "get_chat_participant");
}
if (is_chat_full_outdated(chat_full, c, chat_id)) {
send_get_chat_full_query(chat_id, Auto(), "get_chat_participant lazy");
}
finish_get_chat_participant(chat_id, user_id, std::move(promise));
}
void ContactsManager::finish_get_chat_participant(ChatId chat_id, UserId user_id,
Promise<DialogParticipant> &&promise) {
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
const auto *participant = get_chat_participant(chat_id, user_id);
if (participant == nullptr) {
return promise.set_value(DialogParticipant::left(DialogId(user_id)));
}
promise.set_value(DialogParticipant(*participant));
} }
void ContactsManager::search_chat_participants(ChatId chat_id, const string &query, int32 limit, void ContactsManager::search_chat_participants(ChatId chat_id, const string &query, int32 limit,
@ -14959,77 +14997,46 @@ void ContactsManager::do_search_chat_participants(ChatId chat_id, const string &
})}); })});
} }
DialogParticipant ContactsManager::get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id, void ContactsManager::get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
int64 &random_id, bool force, Promise<Unit> &&promise) { Promise<DialogParticipant> &&promise) {
LOG(INFO) << "Trying to get " << participant_dialog_id << " as member of " << channel_id << " with random_id " LOG(INFO) << "Trying to get " << participant_dialog_id << " as member of " << channel_id;
<< random_id;
if (random_id != 0) {
// request has already been sent before
auto it = received_channel_participant_.find(random_id);
CHECK(it != received_channel_participant_.end());
auto result = std::move(it->second);
result.status.update_restrictions();
received_channel_participant_.erase(it);
promise.set_value(Unit());
return result;
}
auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read); auto input_peer = td_->messages_manager_->get_input_peer(participant_dialog_id, AccessRights::Read);
if (input_peer == nullptr) { if (input_peer == nullptr) {
promise.set_error(Status::Error(6, "User not found")); return promise.set_error(Status::Error(6, "User not found"));
return DialogParticipant();
} }
if (have_channel_participant_cache(channel_id)) { if (have_channel_participant_cache(channel_id)) {
auto *participant = get_channel_participant_from_cache(channel_id, participant_dialog_id); auto *participant = get_channel_participant_from_cache(channel_id, participant_dialog_id);
if (participant != nullptr) { if (participant != nullptr) {
promise.set_value(Unit()); return promise.set_value(DialogParticipant{*participant});
return *participant;
} }
} }
do { auto on_result_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, promise = std::move(promise)](
random_id = Random::secure_int64(); Result<DialogParticipant> r_dialog_participant) mutable {
} while (random_id == 0 || received_channel_participant_.find(random_id) != received_channel_participant_.end()); TRY_RESULT_PROMISE(promise, dialog_participant, std::move(r_dialog_participant));
received_channel_participant_[random_id]; // reserve place for result send_closure(actor_id, &ContactsManager::finish_get_channel_participant, channel_id, std::move(dialog_participant),
std::move(promise));
LOG(DEBUG) << "Get info about " << participant_dialog_id << " membership in the " << channel_id << " with random_id "
<< random_id;
auto on_result_promise =
PromiseCreator::lambda([actor_id = actor_id(this), channel_id, random_id,
promise = std::move(promise)](Result<DialogParticipant> r_dialog_participant) mutable {
send_closure(actor_id, &ContactsManager::on_get_channel_participant, channel_id, random_id,
std::move(r_dialog_participant), std::move(promise));
}); });
td_->create_handler<GetChannelParticipantQuery>(std::move(on_result_promise)) td_->create_handler<GetChannelParticipantQuery>(std::move(on_result_promise))
->send(channel_id, participant_dialog_id, std::move(input_peer)); ->send(channel_id, participant_dialog_id, std::move(input_peer));
return DialogParticipant();
} }
void ContactsManager::on_get_channel_participant(ChannelId channel_id, int64 random_id, void ContactsManager::finish_get_channel_participant(ChannelId channel_id, DialogParticipant &&dialog_participant,
Result<DialogParticipant> r_dialog_participant, Promise<DialogParticipant> &&promise) {
Promise<Unit> &&promise) {
if (G()->close_flag()) { if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted")); return promise.set_error(Status::Error(500, "Request aborted"));
} }
LOG(INFO) << "Receive a member of a channel " << channel_id << " with random_id " << random_id; LOG(INFO) << "Receive a member " << dialog_participant.dialog_id << " of a channel " << channel_id;
auto it = received_channel_participant_.find(random_id); dialog_participant.status.update_restrictions();
CHECK(it != received_channel_participant_.end());
if (r_dialog_participant.is_error()) {
received_channel_participant_.erase(it);
promise.set_error(r_dialog_participant.move_as_error());
} else {
it->second = r_dialog_participant.move_as_ok();
if (have_channel_participant_cache(channel_id)) { if (have_channel_participant_cache(channel_id)) {
add_channel_participant_to_cache(channel_id, it->second, false); add_channel_participant_to_cache(channel_id, dialog_participant, false);
}
promise.set_value(Unit());
} }
promise.set_value(std::move(dialog_participant));
} }
void ContactsManager::get_channel_participants(ChannelId channel_id, void ContactsManager::get_channel_participants(ChannelId channel_id,

View File

@ -524,9 +524,8 @@ class ContactsManager final : public Actor {
void ban_dialog_participant(DialogId dialog_id, const tl_object_ptr<td_api::MessageSender> &participant_id, void ban_dialog_participant(DialogId dialog_id, const tl_object_ptr<td_api::MessageSender> &participant_id,
int32 banned_until_date, bool revoke_messages, Promise<Unit> &&promise); int32 banned_until_date, bool revoke_messages, Promise<Unit> &&promise);
DialogParticipant get_dialog_participant(DialogId dialog_id, void get_dialog_participant(DialogId dialog_id, const tl_object_ptr<td_api::MessageSender> &participant_id,
const tl_object_ptr<td_api::MessageSender> &participant_id, int64 &random_id, Promise<td_api::object_ptr<td_api::chatMember>> &&promise);
bool force, Promise<Unit> &&promise);
void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantsFilter filter, void search_dialog_participants(DialogId dialog_id, const string &query, int32 limit, DialogParticipantsFilter filter,
Promise<DialogParticipants> &&promise); Promise<DialogParticipants> &&promise);
@ -1275,7 +1274,7 @@ class ContactsManager final : public Actor {
void on_save_user_to_database(UserId user_id, bool success); void on_save_user_to_database(UserId user_id, bool success);
void load_user_from_database(User *u, UserId user_id, Promise<Unit> promise); void load_user_from_database(User *u, UserId user_id, Promise<Unit> promise);
void load_user_from_database_impl(UserId user_id, Promise<Unit> promise); void load_user_from_database_impl(UserId user_id, Promise<Unit> promise);
void on_load_user_from_database(UserId user_id, string value); void on_load_user_from_database(UserId user_id, string value, bool force);
void save_chat(Chat *c, ChatId chat_id, bool from_binlog); void save_chat(Chat *c, ChatId chat_id, bool from_binlog);
static string get_chat_database_key(ChatId chat_id); static string get_chat_database_key(ChatId chat_id);
@ -1285,7 +1284,7 @@ class ContactsManager final : public Actor {
void on_save_chat_to_database(ChatId chat_id, bool success); void on_save_chat_to_database(ChatId chat_id, bool success);
void load_chat_from_database(Chat *c, ChatId chat_id, Promise<Unit> promise); void load_chat_from_database(Chat *c, ChatId chat_id, Promise<Unit> promise);
void load_chat_from_database_impl(ChatId chat_id, Promise<Unit> promise); void load_chat_from_database_impl(ChatId chat_id, Promise<Unit> promise);
void on_load_chat_from_database(ChatId chat_id, string value); void on_load_chat_from_database(ChatId chat_id, string value, bool force);
void save_channel(Channel *c, ChannelId channel_id, bool from_binlog); void save_channel(Channel *c, ChannelId channel_id, bool from_binlog);
static string get_channel_database_key(ChannelId channel_id); static string get_channel_database_key(ChannelId channel_id);
@ -1295,7 +1294,7 @@ class ContactsManager final : public Actor {
void on_save_channel_to_database(ChannelId channel_id, bool success); void on_save_channel_to_database(ChannelId channel_id, bool success);
void load_channel_from_database(Channel *c, ChannelId channel_id, Promise<Unit> promise); void load_channel_from_database(Channel *c, ChannelId channel_id, Promise<Unit> promise);
void load_channel_from_database_impl(ChannelId channel_id, Promise<Unit> promise); void load_channel_from_database_impl(ChannelId channel_id, Promise<Unit> promise);
void on_load_channel_from_database(ChannelId channel_id, string value); void on_load_channel_from_database(ChannelId channel_id, string value, bool force);
void save_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog); void save_secret_chat(SecretChat *c, SecretChatId secret_chat_id, bool from_binlog);
static string get_secret_chat_database_key(SecretChatId secret_chat_id); static string get_secret_chat_database_key(SecretChatId secret_chat_id);
@ -1305,7 +1304,7 @@ class ContactsManager final : public Actor {
void on_save_secret_chat_to_database(SecretChatId secret_chat_id, bool success); void on_save_secret_chat_to_database(SecretChatId secret_chat_id, bool success);
void load_secret_chat_from_database(SecretChat *c, SecretChatId secret_chat_id, Promise<Unit> promise); void load_secret_chat_from_database(SecretChat *c, SecretChatId secret_chat_id, Promise<Unit> promise);
void load_secret_chat_from_database_impl(SecretChatId secret_chat_id, Promise<Unit> promise); void load_secret_chat_from_database_impl(SecretChatId secret_chat_id, Promise<Unit> promise);
void on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value); void on_load_secret_chat_from_database(SecretChatId secret_chat_id, string value, bool force);
void save_user_full(const UserFull *user_full, UserId user_id); void save_user_full(const UserFull *user_full, UserId user_id);
static string get_user_full_database_key(UserId user_id); static string get_user_full_database_key(UserId user_id);
@ -1414,10 +1413,20 @@ class ContactsManager final : public Actor {
DialogParticipants search_private_chat_participants(UserId my_user_id, UserId peer_user_id, const string &query, DialogParticipants search_private_chat_participants(UserId my_user_id, UserId peer_user_id, const string &query,
int32 limit, DialogParticipantsFilter filter) const; int32 limit, DialogParticipantsFilter filter) const;
DialogParticipant get_chat_participant(ChatId chat_id, UserId user_id, bool force, Promise<Unit> &&promise); void get_dialog_participant(DialogId dialog_id, DialogId participant_dialog_id, Promise<DialogParticipant> &&promise);
DialogParticipant get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id, int64 &random_id, void finish_get_dialog_participant(DialogParticipant &&dialog_participant,
bool force, Promise<Unit> &&promise); Promise<td_api::object_ptr<td_api::chatMember>> &&promise);
void get_chat_participant(ChatId chat_id, UserId user_id, Promise<DialogParticipant> &&promise);
void finish_get_chat_participant(ChatId chat_id, UserId user_id, Promise<DialogParticipant> &&promise);
void get_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
Promise<DialogParticipant> &&promise);
void finish_get_channel_participant(ChannelId channel_id, DialogParticipant &&dialog_participant,
Promise<DialogParticipant> &&promise);
static string get_dialog_administrators_database_key(DialogId dialog_id); static string get_dialog_administrators_database_key(DialogId dialog_id);
@ -1480,9 +1489,6 @@ class ContactsManager final : public Actor {
void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise); void delete_chat_participant(ChatId chat_id, UserId user_id, bool revoke_messages, Promise<Unit> &&promise);
void on_get_channel_participant(ChannelId channel_id, int64 random_id, Result<DialogParticipant> r_dialog_participant,
Promise<Unit> &&promise);
void search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantsFilter filter, void search_chat_participants(ChatId chat_id, const string &query, int32 limit, DialogParticipantsFilter filter,
Promise<DialogParticipants> &&promise); Promise<DialogParticipants> &&promise);
@ -1655,8 +1661,6 @@ class ContactsManager final : public Actor {
std::unordered_map<int64, std::pair<vector<UserId>, vector<int32>>> imported_contacts_; std::unordered_map<int64, std::pair<vector<UserId>, vector<int32>>> imported_contacts_;
std::unordered_map<int64, DialogParticipant> received_channel_participant_;
std::unordered_map<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_; std::unordered_map<ChannelId, vector<DialogParticipant>, ChannelIdHash> cached_channel_participants_;
// bot-administrators only // bot-administrators only

View File

@ -14616,6 +14616,7 @@ void MessagesManager::on_get_dialogs(FolderId folder_id, vector<tl_object_ptr<te
added_dialog_ids.push_back(dialog_id); added_dialog_ids.push_back(dialog_id);
Dialog *d = get_dialog_force(dialog_id, "on_get_dialogs"); Dialog *d = get_dialog_force(dialog_id, "on_get_dialogs");
bool need_update_dialog_pos = false; bool need_update_dialog_pos = false;
CHECK(!being_added_dialog_id_.is_valid());
being_added_dialog_id_ = dialog_id; being_added_dialog_id_ = dialog_id;
if (d == nullptr) { if (d == nullptr) {
d = add_dialog(dialog_id, "on_get_dialogs"); d = add_dialog(dialog_id, "on_get_dialogs");
@ -20552,7 +20553,7 @@ tl_object_ptr<td_api::messages> MessagesManager::get_dialog_history(DialogId dia
if (from_the_end) { if (from_the_end) {
from_message_id = MessageId(); from_message_id = MessageId();
} }
send_closure_later(actor_id(this), &MessagesManager::load_messages, d->dialog_id, from_message_id, offset, send_closure_later(actor_id(this), &MessagesManager::load_messages, dialog_id, from_message_id, offset,
limit - static_cast<int32>(messages.size()), left_tries, only_local, std::move(promise)); limit - static_cast<int32>(messages.size()), left_tries, only_local, std::move(promise));
return nullptr; return nullptr;
} }
@ -22221,7 +22222,7 @@ void MessagesManager::preload_newer_messages(const Dialog *d, MessageId max_mess
if (limit > 0 && (d->last_message_id == MessageId() || max_message_id < d->last_message_id)) { if (limit > 0 && (d->last_message_id == MessageId() || max_message_id < d->last_message_id)) {
// need to preload some new messages // need to preload some new messages
LOG(INFO) << "Preloading newer after " << max_message_id; LOG(INFO) << "Preloading newer after " << max_message_id;
load_messages(d->dialog_id, max_message_id, -MAX_GET_HISTORY + 1, MAX_GET_HISTORY, 3, false, Promise<Unit>()); load_messages_impl(d, max_message_id, -MAX_GET_HISTORY + 1, MAX_GET_HISTORY, 3, false, Promise<Unit>());
} }
} }
@ -22247,7 +22248,7 @@ void MessagesManager::preload_older_messages(const Dialog *d, MessageId min_mess
if (limit > 0) { if (limit > 0) {
// need to preload some old messages // need to preload some old messages
LOG(INFO) << "Preloading older before " << min_message_id; LOG(INFO) << "Preloading older before " << min_message_id;
load_messages(d->dialog_id, min_message_id, 0, MAX_GET_HISTORY / 2, 3, false, Promise<Unit>()); load_messages_impl(d, min_message_id, 0, MAX_GET_HISTORY / 2, 3, false, Promise<Unit>());
} }
} }
@ -22273,9 +22274,10 @@ unique_ptr<MessagesManager::Message> MessagesManager::parse_message(DialogId dia
return m; return m;
} }
void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId from_message_id, int32 offset, void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId from_message_id,
int32 limit, bool from_the_end, bool only_local, MessageId old_last_database_message_id, int32 offset, int32 limit,
vector<BufferSlice> &&messages, Promise<Unit> &&promise) { bool from_the_end, bool only_local, vector<BufferSlice> &&messages,
Promise<Unit> &&promise) {
CHECK(-limit < offset && offset <= 0); CHECK(-limit < offset && offset <= 0);
CHECK(offset < 0 || from_the_end); CHECK(offset < 0 || from_the_end);
CHECK(!from_message_id.is_scheduled()); CHECK(!from_message_id.is_scheduled());
@ -22302,6 +22304,17 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId
<< d->first_database_message_id << ", last database message is " << d->last_database_message_id << d->first_database_message_id << ", last database message is " << d->last_database_message_id
<< ", have_full_history = " << d->have_full_history; << ", have_full_history = " << d->have_full_history;
if (old_last_database_message_id < d->last_database_message_id && old_last_database_message_id < from_message_id) {
// new messages where added to the database since the request was sent
// they should have been received from the database, so we must repeat the request to get them
if (from_the_end) {
get_history_from_the_end_impl(d, true, only_local, std::move(promise));
} else {
get_history_impl(d, from_message_id, offset, limit, true, only_local, std::move(promise));
}
return;
}
if (messages.empty() && from_the_end && d->messages == nullptr) { if (messages.empty() && from_the_end && d->messages == nullptr) {
if (d->have_full_history) { if (d->have_full_history) {
set_dialog_is_empty(d, "on_get_history_from_database empty"); set_dialog_is_empty(d, "on_get_history_from_database empty");
@ -22419,18 +22432,24 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId
if (last_received_message_id < d->last_database_message_id) { if (last_received_message_id < d->last_database_message_id) {
set_dialog_last_database_message_id(d, last_received_message_id, "on_get_history_from_database 12"); set_dialog_last_database_message_id(d, last_received_message_id, "on_get_history_from_database 12");
get_history_from_the_end(dialog_id, true, only_local, std::move(promise)); get_history_from_the_end_impl(d, true, only_local, std::move(promise));
return; return;
} }
if (limit > 1) { if (limit > 1) {
// we expected to have messages [first_database_message_id, last_database_message_id] in the database, but // we expected to have messages [first_database_message_id, last_database_message_id] in the database, but
// received newer messages [last_received_message_id, ...], none of which can be added // received no messages or newer messages [last_received_message_id, ...], none of which can be added
// first_database_message_id and last_database_message_id are very wrong, so it is better to drop them, // first_database_message_id and last_database_message_id are very wrong, so it is better to drop them,
// pretending that the database has no usable messages // pretending that the database has no usable messages
LOG(ERROR) << "Receive unusable messages up to " << last_received_message_id << " in " << dialog_id if (last_received_message_id == MessageId::max()) {
LOG(ERROR) << "Receive no usable messages in " << dialog_id
<< " from database from the end, but expected messages from " << d->last_database_message_id << " from database from the end, but expected messages from " << d->last_database_message_id
<< " up to " << d->first_database_message_id; << " up to " << d->first_database_message_id;
} else {
LOG(ERROR) << "Receive " << messages.size() << " unusable messages up to " << last_received_message_id
<< " in " << dialog_id << " from database from the end, but expected messages from "
<< d->last_database_message_id << " up to " << d->first_database_message_id;
}
set_dialog_first_database_message_id(d, MessageId(), "on_get_history_from_database 13"); set_dialog_first_database_message_id(d, MessageId(), "on_get_history_from_database 13");
set_dialog_last_database_message_id(d, MessageId(), "on_get_history_from_database 14"); set_dialog_last_database_message_id(d, MessageId(), "on_get_history_from_database 14");
} }
@ -22441,7 +22460,7 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId
if (from_the_end) { if (from_the_end) {
from_message_id = MessageId(); from_message_id = MessageId();
} }
load_messages(dialog_id, from_message_id, offset, limit, 1, false, std::move(promise)); load_messages_impl(d, from_message_id, offset, limit, 1, false, std::move(promise));
return; return;
} }
@ -22496,14 +22515,21 @@ void MessagesManager::on_get_history_from_database(DialogId dialog_id, MessageId
void MessagesManager::get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local, void MessagesManager::get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
CHECK(dialog_id.is_valid()); get_history_from_the_end_impl(get_dialog(dialog_id), from_database, only_local, std::move(promise));
if (G()->close_flag()) { }
return promise.set_error(Status::Error(500, "Request aborted"));
} void MessagesManager::get_history_from_the_end_impl(const Dialog *d, bool from_database, bool only_local,
Promise<Unit> &&promise) {
CHECK(d != nullptr);
auto dialog_id = d->dialog_id;
if (!have_input_peer(dialog_id, AccessRights::Read)) { if (!have_input_peer(dialog_id, AccessRights::Read)) {
// can't get history in dialogs without read access // can't get history in dialogs without read access
return promise.set_value(Unit()); return promise.set_value(Unit());
} }
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
int32 limit = MAX_GET_HISTORY; int32 limit = MAX_GET_HISTORY;
if (from_database && G()->parameters().use_message_db) { if (from_database && G()->parameters().use_message_db) {
if (!promise) { if (!promise) {
@ -22516,10 +22542,12 @@ void MessagesManager::get_history_from_the_end(DialogId dialog_id, bool from_dat
db_query.from_message_id = MessageId::max(); db_query.from_message_id = MessageId::max();
db_query.limit = limit; db_query.limit = limit;
G()->td_db()->get_messages_db_async()->get_messages( G()->td_db()->get_messages_db_async()->get_messages(
db_query, PromiseCreator::lambda([dialog_id, only_local, limit, actor_id = actor_id(this), db_query, PromiseCreator::lambda([dialog_id, old_last_database_message_id = d->last_database_message_id,
only_local, limit, actor_id = actor_id(this),
promise = std::move(promise)](std::vector<BufferSlice> messages) mutable { promise = std::move(promise)](std::vector<BufferSlice> messages) mutable {
send_closure(actor_id, &MessagesManager::on_get_history_from_database, dialog_id, MessageId::max(), 0, limit, send_closure(actor_id, &MessagesManager::on_get_history_from_database, dialog_id, MessageId::max(),
true, only_local, std::move(messages), std::move(promise)); old_last_database_message_id, 0, limit, true, only_local, std::move(messages),
std::move(promise));
})); }));
} else { } else {
if (only_local || dialog_id.get_type() == DialogType::SecretChat) { if (only_local || dialog_id.get_type() == DialogType::SecretChat) {
@ -22534,8 +22562,16 @@ void MessagesManager::get_history_from_the_end(DialogId dialog_id, bool from_dat
void MessagesManager::get_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, void MessagesManager::get_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit,
bool from_database, bool only_local, Promise<Unit> &&promise) { bool from_database, bool only_local, Promise<Unit> &&promise) {
CHECK(dialog_id.is_valid()); get_history_impl(get_dialog(dialog_id), from_message_id, offset, limit, from_database, only_local,
std::move(promise));
}
void MessagesManager::get_history_impl(const Dialog *d, MessageId from_message_id, int32 offset, int32 limit,
bool from_database, bool only_local, Promise<Unit> &&promise) {
CHECK(d != nullptr);
CHECK(from_message_id.is_valid()); CHECK(from_message_id.is_valid());
auto dialog_id = d->dialog_id;
if (!have_input_peer(dialog_id, AccessRights::Read)) { if (!have_input_peer(dialog_id, AccessRights::Read)) {
// can't get history in dialogs without read access // can't get history in dialogs without read access
return promise.set_value(Unit()); return promise.set_value(Unit());
@ -22553,10 +22589,12 @@ void MessagesManager::get_history(DialogId dialog_id, MessageId from_message_id,
db_query.limit = limit; db_query.limit = limit;
G()->td_db()->get_messages_db_async()->get_messages( G()->td_db()->get_messages_db_async()->get_messages(
db_query, db_query,
PromiseCreator::lambda([dialog_id, from_message_id, offset, limit, only_local, actor_id = actor_id(this), PromiseCreator::lambda([dialog_id, from_message_id, old_last_database_message_id = d->last_database_message_id,
offset, limit, only_local, actor_id = actor_id(this),
promise = std::move(promise)](std::vector<BufferSlice> messages) mutable { promise = std::move(promise)](std::vector<BufferSlice> messages) mutable {
send_closure(actor_id, &MessagesManager::on_get_history_from_database, dialog_id, from_message_id, offset, send_closure(actor_id, &MessagesManager::on_get_history_from_database, dialog_id, from_message_id,
limit, false, only_local, std::move(messages), std::move(promise)); old_last_database_message_id, offset, limit, false, only_local, std::move(messages),
std::move(promise));
})); }));
} else { } else {
if (only_local || dialog_id.get_type() == DialogType::SecretChat) { if (only_local || dialog_id.get_type() == DialogType::SecretChat) {
@ -22572,24 +22610,28 @@ void MessagesManager::get_history(DialogId dialog_id, MessageId from_message_id,
void MessagesManager::load_messages(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, void MessagesManager::load_messages(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit,
int left_tries, bool only_local, Promise<Unit> &&promise) { int left_tries, bool only_local, Promise<Unit> &&promise) {
LOG(INFO) << "Load " << (only_local ? "local " : "") << "messages in " << dialog_id << " from " << from_message_id load_messages_impl(get_dialog(dialog_id), from_message_id, offset, limit, left_tries, only_local, std::move(promise));
<< " with offset = " << offset << " and limit = " << limit << ". " << left_tries << " tries left"; }
void MessagesManager::load_messages_impl(const Dialog *d, MessageId from_message_id, int32 offset, int32 limit,
int left_tries, bool only_local, Promise<Unit> &&promise) {
CHECK(d != nullptr);
CHECK(offset <= 0); CHECK(offset <= 0);
CHECK(left_tries > 0); CHECK(left_tries > 0);
auto dialog_id = d->dialog_id;
LOG(INFO) << "Load " << (only_local ? "local " : "") << "messages in " << dialog_id << " from " << from_message_id
<< " with offset = " << offset << " and limit = " << limit << ". " << left_tries << " tries left";
only_local |= dialog_id.get_type() == DialogType::SecretChat; only_local |= dialog_id.get_type() == DialogType::SecretChat;
if (!only_local) { if (!only_local && d->have_full_history) {
Dialog *d = get_dialog(dialog_id);
if (d != nullptr && d->have_full_history) {
LOG(INFO) << "Have full history in " << dialog_id << ", so don't need to get chat history from server"; LOG(INFO) << "Have full history in " << dialog_id << ", so don't need to get chat history from server";
only_local = true; only_local = true;
} }
}
bool from_database = (left_tries > 2 || only_local) && G()->parameters().use_message_db; bool from_database = (left_tries > 2 || only_local) && G()->parameters().use_message_db;
// TODO do not send requests to database if (from_message_id < d->first_database_message_id || // TODO do not send requests to database if (from_message_id < d->first_database_message_id ||
// !d->first_database_message_id.is_valid()) && !d->have_full_history // !d->first_database_message_id.is_valid()) && !d->have_full_history
if (from_message_id == MessageId()) { if (from_message_id == MessageId()) {
get_history_from_the_end(dialog_id, from_database, only_local, std::move(promise)); get_history_from_the_end_impl(d, from_database, only_local, std::move(promise));
return; return;
} }
if (offset >= -1) { if (offset >= -1) {
@ -22603,7 +22645,7 @@ void MessagesManager::load_messages(DialogId dialog_id, MessageId from_message_i
offset -= max_add; offset -= max_add;
limit = MAX_GET_HISTORY; limit = MAX_GET_HISTORY;
} }
get_history(dialog_id, from_message_id, offset, limit, from_database, only_local, std::move(promise)); get_history_impl(d, from_message_id, offset, limit, from_database, only_local, std::move(promise));
} }
vector<MessageId> MessagesManager::get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result, vector<MessageId> MessagesManager::get_dialog_scheduled_messages(DialogId dialog_id, bool force, bool ignore_result,
@ -31952,8 +31994,13 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(DialogId dialog
Dialog *d = get_dialog_force(dialog_id, source); Dialog *d = get_dialog_force(dialog_id, source);
if (d == nullptr) { if (d == nullptr) {
if (from_update) {
CHECK(!being_added_by_new_message_dialog_id_.is_valid());
being_added_by_new_message_dialog_id_ = dialog_id;
}
d = add_dialog(dialog_id, "add_message_to_dialog"); d = add_dialog(dialog_id, "add_message_to_dialog");
*need_update_dialog_pos = true; *need_update_dialog_pos = true;
being_added_by_new_message_dialog_id_ = DialogId();
} else { } else {
CHECK(d->dialog_id == dialog_id); CHECK(d->dialog_id == dialog_id);
} }
@ -33861,14 +33908,14 @@ void MessagesManager::force_create_dialog(DialogId dialog_id, const char *source
} }
MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id, const char *source) { MessagesManager::Dialog *MessagesManager::add_dialog(DialogId dialog_id, const char *source) {
LOG(DEBUG) << "Creating " << dialog_id; LOG(DEBUG) << "Creating " << dialog_id << " from " << source;
CHECK(!have_dialog(dialog_id)); CHECK(!have_dialog(dialog_id));
if (G()->parameters().use_message_db) { if (G()->parameters().use_message_db) {
// TODO preload dialog asynchronously, remove loading from this function // TODO preload dialog asynchronously, remove loading from this function
auto r_value = G()->td_db()->get_dialog_db_sync()->get_dialog(dialog_id); auto r_value = G()->td_db()->get_dialog_db_sync()->get_dialog(dialog_id);
if (r_value.is_ok()) { if (r_value.is_ok()) {
LOG(INFO) << "Synchronously loaded " << dialog_id << " from database"; LOG(INFO) << "Synchronously loaded " << dialog_id << " from database from " << source;
return add_new_dialog(parse_dialog(dialog_id, r_value.ok(), source), true, source); return add_new_dialog(parse_dialog(dialog_id, r_value.ok(), source), true, source);
} }
} }
@ -33913,7 +33960,7 @@ MessagesManager::Dialog *MessagesManager::add_new_dialog(unique_ptr<Dialog> &&d,
} }
case DialogType::SecretChat: case DialogType::SecretChat:
if (d->last_new_message_id.get() <= MessageId::min().get()) { if (d->last_new_message_id.get() <= MessageId::min().get()) {
LOG(INFO) << "Set " << d->dialog_id << " last new message in add_new_dialog"; LOG(INFO) << "Set " << d->dialog_id << " last new message in add_new_dialog from " << source;
d->last_new_message_id = MessageId::min().get_next_message_id(MessageType::Local); d->last_new_message_id = MessageId::min().get_next_message_id(MessageType::Local);
} }
@ -34332,8 +34379,9 @@ void MessagesManager::fix_new_dialog(Dialog *d, unique_ptr<Message> &&last_datab
d->pending_read_channel_inbox_pts = 0; d->pending_read_channel_inbox_pts = 0;
} }
if (need_get_history && !td_->auth_manager_->is_bot() && dialog_id != being_added_dialog_id_ && if (need_get_history && !td_->auth_manager_->is_bot() && dialog_id != being_added_dialog_id_ &&
have_input_peer(dialog_id, AccessRights::Read) && (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) { dialog_id != being_added_by_new_message_dialog_id_ && have_input_peer(dialog_id, AccessRights::Read) &&
get_history_from_the_end(dialog_id, true, false, Auto()); (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) {
get_history_from_the_end_impl(d, true, false, Auto());
} }
if (d->need_repair_server_unread_count && need_unread_counter(d->order)) { if (d->need_repair_server_unread_count && need_unread_counter(d->order)) {
CHECK(dialog_type != DialogType::SecretChat); CHECK(dialog_type != DialogType::SecretChat);
@ -34350,6 +34398,7 @@ void MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr<Mes
CHECK(last_database_message->left == nullptr); CHECK(last_database_message->left == nullptr);
CHECK(last_database_message->right == nullptr); CHECK(last_database_message->right == nullptr);
auto dialog_id = d->dialog_id;
auto message_id = last_database_message->message_id; auto message_id = last_database_message->message_id;
CHECK(message_id.is_valid()); CHECK(message_id.is_valid());
LOG_CHECK(d->last_database_message_id == message_id) LOG_CHECK(d->last_database_message_id == message_id)
@ -34357,7 +34406,7 @@ void MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr<Mes
bool need_update_dialog_pos = false; bool need_update_dialog_pos = false;
const Message *m = nullptr; const Message *m = nullptr;
if (have_input_peer(d->dialog_id, AccessRights::Read)) { if (have_input_peer(dialog_id, AccessRights::Read)) {
bool need_update = false; bool need_update = false;
last_database_message->have_previous = false; last_database_message->have_previous = false;
last_database_message->have_next = false; last_database_message->have_next = false;
@ -34365,7 +34414,7 @@ void MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr<Mes
m = add_message_to_dialog(d, std::move(last_database_message), false, &need_update, &need_update_dialog_pos, m = add_message_to_dialog(d, std::move(last_database_message), false, &need_update, &need_update_dialog_pos,
"add_dialog_last_database_message 1"); "add_dialog_last_database_message 1");
if (need_update_dialog_pos) { if (need_update_dialog_pos) {
LOG(ERROR) << "Need to update pos in " << d->dialog_id; LOG(ERROR) << "Need to update pos in " << dialog_id;
} }
} }
if (m != nullptr) { if (m != nullptr) {
@ -34377,11 +34426,12 @@ void MessagesManager::add_dialog_last_database_message(Dialog *d, unique_ptr<Mes
d->pending_last_message_id = MessageId(); d->pending_last_message_id = MessageId();
need_update_dialog_pos = true; need_update_dialog_pos = true;
} }
on_dialog_updated(d->dialog_id, "add_dialog_last_database_message 4"); // resave without last database message on_dialog_updated(dialog_id, "add_dialog_last_database_message 4"); // resave without last database message
if (!td_->auth_manager_->is_bot() && d->dialog_id != being_added_dialog_id_ && if (!td_->auth_manager_->is_bot() && dialog_id != being_added_dialog_id_ &&
have_input_peer(d->dialog_id, AccessRights::Read) && (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) { dialog_id != being_added_by_new_message_dialog_id_ && have_input_peer(dialog_id, AccessRights::Read) &&
get_history_from_the_end(d->dialog_id, true, false, Auto()); (d->order != DEFAULT_ORDER || is_dialog_sponsored(d))) {
get_history_from_the_end_impl(d, true, false, Auto());
} }
} }
@ -37263,10 +37313,10 @@ void MessagesManager::suffix_load_loop(Dialog *d) {
d->suffix_load_has_query_ = true; d->suffix_load_has_query_ = true;
d->suffix_load_query_message_id_ = from_message_id; d->suffix_load_query_message_id_ = from_message_id;
if (from_message_id.is_valid()) { if (from_message_id.is_valid()) {
get_history(dialog_id, from_message_id, -1, 100, true, true, std::move(promise)); get_history_impl(d, from_message_id, -1, 100, true, true, std::move(promise));
} else { } else {
CHECK(from_message_id == MessageId()); CHECK(from_message_id == MessageId());
get_history_from_the_end(dialog_id, true, true, std::move(promise)); get_history_from_the_end_impl(d, true, true, std::move(promise));
} }
} }

View File

@ -2006,18 +2006,27 @@ class MessagesManager final : public Actor {
void preload_older_messages(const Dialog *d, MessageId min_message_id); void preload_older_messages(const Dialog *d, MessageId min_message_id);
void on_get_history_from_database(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, void on_get_history_from_database(DialogId dialog_id, MessageId from_message_id,
MessageId old_last_database_message_id, int32 offset, int32 limit,
bool from_the_end, bool only_local, vector<BufferSlice> &&messages, bool from_the_end, bool only_local, vector<BufferSlice> &&messages,
Promise<Unit> &&promise); Promise<Unit> &&promise);
void get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local, Promise<Unit> &&promise); void get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local, Promise<Unit> &&promise);
void get_history_from_the_end_impl(const Dialog *d, bool from_database, bool only_local, Promise<Unit> &&promise);
void get_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, bool from_database, void get_history(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, bool from_database,
bool only_local, Promise<Unit> &&promise); bool only_local, Promise<Unit> &&promise);
void get_history_impl(const Dialog *d, MessageId from_message_id, int32 offset, int32 limit, bool from_database,
bool only_local, Promise<Unit> &&promise);
void load_messages(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, int left_tries, void load_messages(DialogId dialog_id, MessageId from_message_id, int32 offset, int32 limit, int left_tries,
bool only_local, Promise<Unit> &&promise); bool only_local, Promise<Unit> &&promise);
void load_messages_impl(const Dialog *d, MessageId from_message_id, int32 offset, int32 limit, int left_tries,
bool only_local, Promise<Unit> &&promise);
void load_dialog_scheduled_messages(DialogId dialog_id, bool from_database, int32 hash, Promise<Unit> &&promise); void load_dialog_scheduled_messages(DialogId dialog_id, bool from_database, int32 hash, Promise<Unit> &&promise);
void on_get_scheduled_messages_from_database(DialogId dialog_id, vector<BufferSlice> &&messages); void on_get_scheduled_messages_from_database(DialogId dialog_id, vector<BufferSlice> &&messages);
@ -3339,6 +3348,7 @@ class MessagesManager final : public Actor {
FullMessageId being_readded_message_id_; FullMessageId being_readded_message_id_;
DialogId being_added_dialog_id_; DialogId being_added_dialog_id_;
DialogId being_added_by_new_message_dialog_id_;
DialogId debug_channel_difference_dialog_; DialogId debug_channel_difference_dialog_;

View File

@ -215,7 +215,7 @@ Result<BufferSlice> SecretChatActor::create_encrypted_message(int32 my_in_seq_no
auto out_seq_no = my_out_seq_no * 2 - 1 - auth_state_.x; auto out_seq_no = my_out_seq_no * 2 - 1 - auth_state_.x;
auto layer = current_layer(); auto layer = current_layer();
BufferSlice random_bytes(32); BufferSlice random_bytes(31);
Random::secure_bytes(random_bytes.as_slice().ubegin(), random_bytes.size()); Random::secure_bytes(random_bytes.as_slice().ubegin(), random_bytes.size());
auto message_with_layer = secret_api::make_object<secret_api::decryptedMessageLayer>( auto message_with_layer = secret_api::make_object<secret_api::decryptedMessageLayer>(
std::move(random_bytes), layer, in_seq_no, out_seq_no, std::move(message)); std::move(random_bytes), layer, in_seq_no, out_seq_no, std::move(message));
@ -797,7 +797,9 @@ Result<std::tuple<uint64, BufferSlice, int32>> SecretChatActor::decrypt(BufferSl
info.is_creator = auth_state_.x == 0; info.is_creator = auth_state_.x == 0;
r_read_result = mtproto::Transport::read(data, *auth_key, &info); r_read_result = mtproto::Transport::read(data, *auth_key, &info);
if (i + 1 != versions.size() && r_read_result.is_error()) { if (i + 1 != versions.size() && r_read_result.is_error()) {
if (config_state_.his_layer >= static_cast<int32>(SecretChatLayer::Mtproto2)) {
LOG(WARNING) << tag("mtproto", mtproto_version) << " decryption failed " << r_read_result.error(); LOG(WARNING) << tag("mtproto", mtproto_version) << " decryption failed " << r_read_result.error();
}
continue; continue;
} }
break; break;
@ -1933,13 +1935,13 @@ void SecretChatActor::get_dh_config() {
} }
auto version = auth_state_.dh_config.version; auto version = auth_state_.dh_config.version;
int32 random_length = 0; int32 random_length = 256; // ignored server-side, always returns 256 random bytes
auto query = create_net_query(QueryType::DhConfig, telegram_api::messages_getDhConfig(version, random_length)); auto query = create_net_query(QueryType::DhConfig, telegram_api::messages_getDhConfig(version, random_length));
context_->send_net_query(std::move(query), actor_shared(this), false); context_->send_net_query(std::move(query), actor_shared(this), false);
} }
Status SecretChatActor::on_dh_config(NetQueryPtr query) { Status SecretChatActor::on_dh_config(NetQueryPtr query) {
LOG(INFO) << "Got dh config"; LOG(INFO) << "Got DH config";
TRY_RESULT(config, fetch_result<telegram_api::messages_getDhConfig>(std::move(query))); TRY_RESULT(config, fetch_result<telegram_api::messages_getDhConfig>(std::move(query)));
downcast_call(*config, [&](auto &obj) { this->on_dh_config(obj); }); downcast_call(*config, [&](auto &obj) { this->on_dh_config(obj); });
TRY_STATUS(mtproto::DhHandshake::check_config(auth_state_.dh_config.g, auth_state_.dh_config.prime, TRY_STATUS(mtproto::DhHandshake::check_config(auth_state_.dh_config.g, auth_state_.dh_config.prime,

View File

@ -1947,39 +1947,6 @@ class UpgradeGroupChatToSupergroupChatRequest final : public RequestActor<> {
} }
}; };
class GetChatMemberRequest final : public RequestActor<> {
DialogId dialog_id_;
tl_object_ptr<td_api::MessageSender> participant_id_;
int64 random_id_;
DialogParticipant dialog_participant_;
void do_run(Promise<Unit> &&promise) final {
dialog_participant_ = td->contacts_manager_->get_dialog_participant(dialog_id_, participant_id_, random_id_,
get_tries() < 3, std::move(promise));
}
void do_send_result() final {
auto participant_dialog_id = dialog_participant_.dialog_id;
bool is_user = participant_dialog_id.get_type() == DialogType::User;
if ((is_user && !td->contacts_manager_->have_user(participant_dialog_id.get_user_id())) ||
(!is_user && !td->messages_manager_->have_dialog(participant_dialog_id))) {
return send_error(Status::Error(3, "Member not found"));
}
send_result(td->contacts_manager_->get_chat_member_object(dialog_participant_));
}
public:
GetChatMemberRequest(ActorShared<Td> td, uint64 request_id, int64 dialog_id,
tl_object_ptr<td_api::MessageSender> participant_id)
: RequestActor(std::move(td), request_id)
, dialog_id_(dialog_id)
, participant_id_(std::move(participant_id))
, random_id_(0) {
set_tries(3);
}
};
class GetChatAdministratorsRequest final : public RequestActor<> { class GetChatAdministratorsRequest final : public RequestActor<> {
DialogId dialog_id_; DialogId dialog_id_;
@ -6564,7 +6531,9 @@ void Td::on_request(uint64 id, td_api::transferChatOwnership &request) {
} }
void Td::on_request(uint64 id, td_api::getChatMember &request) { void Td::on_request(uint64 id, td_api::getChatMember &request) {
CREATE_REQUEST(GetChatMemberRequest, request.chat_id_, std::move(request.member_id_)); CREATE_REQUEST_PROMISE();
contacts_manager_->get_dialog_participant(DialogId(request.chat_id_), std::move(request.member_id_),
std::move(promise));
} }
void Td::on_request(uint64 id, td_api::searchChatMembers &request) { void Td::on_request(uint64 id, td_api::searchChatMembers &request) {

View File

@ -40,7 +40,7 @@
{ \ { \
auto try_status = (status); \ auto try_status = (status); \
if (try_status.is_error()) { \ if (try_status.is_error()) { \
promise_name.set_error(std::move(try_status)); \ promise_name.set_error(try_status.move_as_error()); \
return; \ return; \
} \ } \
} }

View File

@ -27,10 +27,11 @@ namespace td {
namespace { namespace {
void print_backtrace(void) { void print_backtrace(void) {
void *buffer[128];
#if TD_PORT_WINDOWS #if TD_PORT_WINDOWS
void *buffer[128];
USHORT nptrs = CaptureStackBackTrace(0, 128, buffer, nullptr); USHORT nptrs = CaptureStackBackTrace(0, 128, buffer, nullptr);
#elif __GLIBC__ #elif __GLIBC__
void *buffer[128];
int nptrs = backtrace(buffer, 128); int nptrs = backtrace(buffer, 128);
#else #else
return; return;