Merge remote-tracking branch 'td/master'
This commit is contained in:
commit
5f5fa9afa2
@ -382,16 +382,17 @@ set(TDLIB_SOURCE
|
||||
td/telegram/Logging.cpp
|
||||
td/telegram/MessageContent.cpp
|
||||
td/telegram/MessageContentType.cpp
|
||||
td/telegram/MessageDb.cpp
|
||||
td/telegram/MessageEntity.cpp
|
||||
td/telegram/MessageExtendedMedia.cpp
|
||||
td/telegram/MessageId.cpp
|
||||
td/telegram/MessageReaction.cpp
|
||||
td/telegram/MessageReplyHeader.cpp
|
||||
td/telegram/MessageReplyInfo.cpp
|
||||
td/telegram/MessagesDb.cpp
|
||||
td/telegram/MessageSearchFilter.cpp
|
||||
td/telegram/MessageSender.cpp
|
||||
td/telegram/MessagesManager.cpp
|
||||
td/telegram/MessageThreadDb.cpp
|
||||
td/telegram/MessageTtl.cpp
|
||||
td/telegram/misc.cpp
|
||||
td/telegram/net/AuthDataShared.cpp
|
||||
@ -624,6 +625,7 @@ set(TDLIB_SOURCE
|
||||
td/telegram/MessageContent.h
|
||||
td/telegram/MessageContentType.h
|
||||
td/telegram/MessageCopyOptions.h
|
||||
td/telegram/MessageDb.h
|
||||
td/telegram/MessageEntity.h
|
||||
td/telegram/MessageExtendedMedia.h
|
||||
td/telegram/MessageId.h
|
||||
@ -631,11 +633,11 @@ set(TDLIB_SOURCE
|
||||
td/telegram/MessageReaction.h
|
||||
td/telegram/MessageReplyHeader.h
|
||||
td/telegram/MessageReplyInfo.h
|
||||
td/telegram/MessageThreadInfo.h
|
||||
td/telegram/MessagesDb.h
|
||||
td/telegram/MessageSearchFilter.h
|
||||
td/telegram/MessageSender.h
|
||||
td/telegram/MessagesManager.h
|
||||
td/telegram/MessageThreadDb.h
|
||||
td/telegram/MessageThreadInfo.h
|
||||
td/telegram/MessageTtl.h
|
||||
td/telegram/MinChannel.h
|
||||
td/telegram/misc.h
|
||||
|
@ -5,8 +5,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/MessageDb.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/MessagesDb.h"
|
||||
#include "td/telegram/NotificationId.h"
|
||||
#include "td/telegram/ServerMessageId.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
@ -36,10 +36,10 @@ static td::Status init_db(td::SqliteDb &db) {
|
||||
return td::Status::OK();
|
||||
}
|
||||
|
||||
class MessagesDbBench final : public td::Benchmark {
|
||||
class MessageDbBench final : public td::Benchmark {
|
||||
public:
|
||||
td::string get_description() const final {
|
||||
return "MessagesDb";
|
||||
return "MessageDb";
|
||||
}
|
||||
void start_up() final {
|
||||
LOG(ERROR) << "START UP";
|
||||
@ -60,9 +60,9 @@ class MessagesDbBench final : public td::Benchmark {
|
||||
auto data = td::BufferSlice(td::Random::fast(100, 299));
|
||||
|
||||
// use async on same thread.
|
||||
messages_db_async_->add_message({dialog_id, message_id}, unique_message_id, sender_dialog_id, random_id,
|
||||
ttl_expires_at, 0, 0, "", td::NotificationId(), td::MessageId(),
|
||||
std::move(data), td::Promise<>());
|
||||
message_db_async_->add_message({dialog_id, message_id}, unique_message_id, sender_dialog_id, random_id,
|
||||
ttl_expires_at, 0, 0, "", td::NotificationId(), td::MessageId(), std::move(data),
|
||||
td::Promise<>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,8 +71,8 @@ class MessagesDbBench final : public td::Benchmark {
|
||||
{
|
||||
auto guard = scheduler_->get_main_guard();
|
||||
sql_connection_.reset();
|
||||
messages_db_sync_safe_.reset();
|
||||
messages_db_async_.reset();
|
||||
message_db_sync_safe_.reset();
|
||||
message_db_async_.reset();
|
||||
}
|
||||
|
||||
scheduler_->finish();
|
||||
@ -83,8 +83,8 @@ class MessagesDbBench final : public td::Benchmark {
|
||||
private:
|
||||
td::unique_ptr<td::ConcurrentScheduler> scheduler_;
|
||||
std::shared_ptr<td::SqliteConnectionSafe> sql_connection_;
|
||||
std::shared_ptr<td::MessagesDbSyncSafeInterface> messages_db_sync_safe_;
|
||||
std::shared_ptr<td::MessagesDbAsyncInterface> messages_db_async_;
|
||||
std::shared_ptr<td::MessageDbSyncSafeInterface> message_db_sync_safe_;
|
||||
std::shared_ptr<td::MessageDbAsyncInterface> message_db_async_;
|
||||
|
||||
td::Status do_start_up() {
|
||||
scheduler_ = td::make_unique<td::ConcurrentScheduler>(1, 0);
|
||||
@ -98,16 +98,16 @@ class MessagesDbBench final : public td::Benchmark {
|
||||
|
||||
db.exec("BEGIN TRANSACTION").ensure();
|
||||
// version == 0 ==> db will be destroyed
|
||||
TRY_STATUS(init_messages_db(db, 0));
|
||||
TRY_STATUS(init_message_db(db, 0));
|
||||
db.exec("COMMIT TRANSACTION").ensure();
|
||||
|
||||
messages_db_sync_safe_ = td::create_messages_db_sync(sql_connection_);
|
||||
messages_db_async_ = td::create_messages_db_async(messages_db_sync_safe_, 0);
|
||||
message_db_sync_safe_ = td::create_message_db_sync(sql_connection_);
|
||||
message_db_async_ = td::create_message_db_async(message_db_sync_safe_, 0);
|
||||
return td::Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING));
|
||||
td::bench(MessagesDbBench());
|
||||
td::bench(MessageDbBench());
|
||||
}
|
||||
|
@ -25,19 +25,19 @@
|
||||
//#define CREATE_MAP(num) CREATE_MAP_IMPL(num)
|
||||
#define CREATE_MAP(num)
|
||||
|
||||
#define CREATE_MAP_IMPL(num) \
|
||||
int f_##num() { \
|
||||
test_map<int, std::array<char, num>> m; \
|
||||
m.emplace(1, std::array<char, num>{}); \
|
||||
int sum = 0; \
|
||||
for (auto &it : m) { \
|
||||
sum += it.first; \
|
||||
} \
|
||||
auto it = m.find(1); \
|
||||
sum += it->first; \
|
||||
m.erase(it); \
|
||||
return sum; \
|
||||
} \
|
||||
#define CREATE_MAP_IMPL(num) \
|
||||
int f_##num() { \
|
||||
test_map<td::int32, std::array<char, num>> m; \
|
||||
m.emplace(1, std::array<char, num>{}); \
|
||||
int sum = 0; \
|
||||
for (auto &it : m) { \
|
||||
sum += it.first; \
|
||||
} \
|
||||
auto it = m.find(1); \
|
||||
sum += it->first; \
|
||||
m.erase(it); \
|
||||
return sum; \
|
||||
} \
|
||||
int x_##num = f_##num()
|
||||
|
||||
CREATE_MAP(__LINE__);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/FlatHashMapChunks.h"
|
||||
#include "td/utils/FlatHashTable.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/MapNode.h"
|
||||
#include "td/utils/misc.h"
|
||||
@ -77,9 +78,9 @@ class IntGenerator {
|
||||
};
|
||||
|
||||
template <>
|
||||
class Generator<td::uint32> final : public IntGenerator<td::uint32> {};
|
||||
class Generator<td::int32> final : public IntGenerator<td::int32> {};
|
||||
template <>
|
||||
class Generator<td::uint64> final : public IntGenerator<td::uint64> {};
|
||||
class Generator<td::int64> final : public IntGenerator<td::int64> {};
|
||||
|
||||
template <class T>
|
||||
class Generator<td::unique_ptr<T>> {
|
||||
@ -159,14 +160,14 @@ void print_memory_stats(td::Slice name) {
|
||||
td::string big_buff(1 << 16, '\0');
|
||||
td::StringBuilder sb(big_buff, false);
|
||||
#define MEASURE(KeyT, ValueT) measure<T<KeyT, ValueT>, KeyT, ValueT>(sb, name, #KeyT, #ValueT);
|
||||
MEASURE(td::uint32, td::uint32);
|
||||
MEASURE(td::uint64, td::unique_ptr<Bytes<360>>);
|
||||
MEASURE(td::int32, td::int32);
|
||||
MEASURE(td::int64, td::unique_ptr<Bytes<360>>);
|
||||
if (!sb.as_cslice().empty()) {
|
||||
LOG(PLAIN) << '\n' << sb.as_cslice() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
template <class KeyT, class ValueT, class HashT = std::hash<KeyT>, class EqT = std::equal_to<KeyT>>
|
||||
template <class KeyT, class ValueT, class HashT = td::Hash<KeyT>, class EqT = std::equal_to<KeyT>>
|
||||
using FlatHashMapImpl = td::FlatHashTable<td::MapNode<KeyT, ValueT>, HashT, EqT>;
|
||||
|
||||
#define FOR_EACH_TABLE(F) \
|
||||
|
@ -4914,7 +4914,7 @@ getMessage chat_id:int53 message_id:int53 = Message;
|
||||
//@description Returns information about a message, if it is available without sending network request. This is an offline request @chat_id Identifier of the chat the message belongs to @message_id Identifier of the message to get
|
||||
getMessageLocally chat_id:int53 message_id:int53 = Message;
|
||||
|
||||
//@description Returns information about a message that is replied by a given message. Also returns the pinned message, the game message, and the invoice message for messages of the types messagePinMessage, messageGameScore, and messagePaymentSuccessful respectively
|
||||
//@description Returns information about a message that is replied by a given message. Also returns the pinned message, the game message, the invoice message, and the topic creation message for messages of the types messagePinMessage, messageGameScore, messagePaymentSuccessful, and topic messages without replied message respectively
|
||||
//@chat_id Identifier of the chat the message belongs to @message_id Identifier of the reply message
|
||||
getRepliedMessage chat_id:int53 message_id:int53 = Message;
|
||||
|
||||
|
@ -258,9 +258,9 @@ FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) {
|
||||
CHECK(new_animation == nullptr);
|
||||
new_animation = make_unique<Animation>(*old_animation);
|
||||
new_animation->file_id = new_id;
|
||||
new_animation->thumbnail.file_id = td_->file_manager_->dup_file_id(new_animation->thumbnail.file_id);
|
||||
new_animation->thumbnail.file_id = td_->file_manager_->dup_file_id(new_animation->thumbnail.file_id, "dup_animation");
|
||||
new_animation->animated_thumbnail.file_id =
|
||||
td_->file_manager_->dup_file_id(new_animation->animated_thumbnail.file_id);
|
||||
td_->file_manager_->dup_file_id(new_animation->animated_thumbnail.file_id, "dup_animation");
|
||||
return new_id;
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ FileId AudiosManager::dup_audio(FileId new_id, FileId old_id) {
|
||||
CHECK(new_audio == nullptr);
|
||||
new_audio = make_unique<Audio>(*old_audio);
|
||||
new_audio->file_id = new_id;
|
||||
new_audio->thumbnail.file_id = td_->file_manager_->dup_file_id(new_audio->thumbnail.file_id);
|
||||
new_audio->thumbnail.file_id = td_->file_manager_->dup_file_id(new_audio->thumbnail.file_id, "dup_audio");
|
||||
return new_id;
|
||||
}
|
||||
|
||||
|
@ -1121,28 +1121,8 @@ bool AuthManager::load_state() {
|
||||
LOG(INFO) << "Ignore auth_state: api_id or api_hash changed";
|
||||
return false;
|
||||
}
|
||||
if (!db_state.state_timestamp_.is_in_past()) {
|
||||
LOG(INFO) << "Ignore auth_state: timestamp in the future";
|
||||
return false;
|
||||
}
|
||||
auto state_timeout = [state = db_state.state_] {
|
||||
switch (state) {
|
||||
case State::WaitPassword:
|
||||
case State::WaitRegistration:
|
||||
return 86400;
|
||||
case State::WaitEmailAddress:
|
||||
case State::WaitEmailCode:
|
||||
case State::WaitCode:
|
||||
case State::WaitQrCodeConfirmation:
|
||||
return 5 * 60;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}();
|
||||
|
||||
if (Timestamp::at(db_state.state_timestamp_.at() + state_timeout).is_in_past()) {
|
||||
LOG(INFO) << "Ignore auth_state: expired " << db_state.state_timestamp_.in();
|
||||
if (db_state.expires_at_ <= Time::now()) {
|
||||
LOG(INFO) << "Ignore auth_state: expired";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ class AuthManager final : public NetActor {
|
||||
State state_;
|
||||
int32 api_id_;
|
||||
string api_hash_;
|
||||
Timestamp state_timestamp_;
|
||||
double expires_at_;
|
||||
|
||||
// WaitEmailAddress and WaitEmailCode
|
||||
bool allow_apple_id_ = false;
|
||||
@ -202,7 +202,23 @@ class AuthManager final : public NetActor {
|
||||
|
||||
private:
|
||||
DbState(State state, int32 api_id, string &&api_hash)
|
||||
: state_(state), api_id_(api_id), api_hash_(std::move(api_hash)), state_timestamp_(Timestamp::now()) {
|
||||
: state_(state), api_id_(api_id), api_hash_(std::move(api_hash)) {
|
||||
auto state_timeout = [state] {
|
||||
switch (state) {
|
||||
case State::WaitPassword:
|
||||
case State::WaitRegistration:
|
||||
return 86400;
|
||||
case State::WaitEmailAddress:
|
||||
case State::WaitEmailCode:
|
||||
case State::WaitCode:
|
||||
case State::WaitQrCodeConfirmation:
|
||||
return 5 * 60;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}();
|
||||
expires_at_ = Time::now() + state_timeout;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -70,7 +70,7 @@ void AuthManager::DbState::store(StorerT &storer) const {
|
||||
store(state_, storer);
|
||||
store(api_id_, storer);
|
||||
store(api_hash_, storer);
|
||||
store_time(state_timestamp_.at(), storer);
|
||||
store_time(expires_at_, storer);
|
||||
|
||||
if (has_terms_of_service) {
|
||||
store(terms_of_service_, storer);
|
||||
@ -133,9 +133,7 @@ void AuthManager::DbState::parse(ParserT &parser) {
|
||||
parse(state_, parser);
|
||||
parse(api_id_, parser);
|
||||
parse(api_hash_, parser);
|
||||
double state_timestamp = 0.0;
|
||||
parse_time(state_timestamp, parser);
|
||||
state_timestamp_ = Timestamp::at(state_timestamp);
|
||||
parse_time(expires_at_, parser);
|
||||
|
||||
if (has_terms_of_service) {
|
||||
parse(terms_of_service_, parser);
|
||||
|
@ -7,10 +7,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -58,8 +58,8 @@ class BackgroundId {
|
||||
};
|
||||
|
||||
struct BackgroundIdHash {
|
||||
std::size_t operator()(BackgroundId background_id) const {
|
||||
return std::hash<int64>()(background_id.get());
|
||||
uint32 operator()(BackgroundId background_id) const {
|
||||
return Hash<int64>()(background_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -126,13 +126,14 @@ class InstallBackgroundQuery final : public Td::ResultHandler {
|
||||
};
|
||||
|
||||
class UploadBackgroundQuery final : public Td::ResultHandler {
|
||||
Promise<Unit> promise_;
|
||||
Promise<td_api::object_ptr<td_api::background>> promise_;
|
||||
FileId file_id_;
|
||||
BackgroundType type_;
|
||||
bool for_dark_theme_;
|
||||
|
||||
public:
|
||||
explicit UploadBackgroundQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
||||
explicit UploadBackgroundQuery(Promise<td_api::object_ptr<td_api::background>> &&promise)
|
||||
: promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(FileId file_id, tl_object_ptr<telegram_api::InputFile> &&input_file, const BackgroundType &type,
|
||||
@ -605,15 +606,14 @@ BackgroundId BackgroundManager::add_local_background(const BackgroundType &type)
|
||||
return background.id;
|
||||
}
|
||||
|
||||
BackgroundId BackgroundManager::set_background(const td_api::InputBackground *input_background,
|
||||
const td_api::BackgroundType *background_type, bool for_dark_theme,
|
||||
Promise<Unit> &&promise) {
|
||||
void BackgroundManager::set_background(const td_api::InputBackground *input_background,
|
||||
const td_api::BackgroundType *background_type, bool for_dark_theme,
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise) {
|
||||
BackgroundType type;
|
||||
if (background_type != nullptr) {
|
||||
auto r_type = BackgroundType::get_background_type(background_type);
|
||||
if (r_type.is_error()) {
|
||||
promise.set_error(r_type.move_as_error());
|
||||
return BackgroundId();
|
||||
return promise.set_error(r_type.move_as_error());
|
||||
}
|
||||
type = r_type.move_as_ok();
|
||||
} else {
|
||||
@ -623,12 +623,10 @@ BackgroundId BackgroundManager::set_background(const td_api::InputBackground *in
|
||||
if (input_background == nullptr) {
|
||||
if (background_type == nullptr) {
|
||||
set_background_id(BackgroundId(), BackgroundType(), for_dark_theme);
|
||||
promise.set_value(Unit());
|
||||
return BackgroundId();
|
||||
return promise.set_value(nullptr);
|
||||
}
|
||||
if (type.has_file()) {
|
||||
promise.set_error(Status::Error(400, "Input background must be non-empty for the background type"));
|
||||
return BackgroundId();
|
||||
return promise.set_error(Status::Error(400, "Input background must be non-empty for the background type"));
|
||||
}
|
||||
|
||||
auto background_id = add_local_background(type);
|
||||
@ -637,23 +635,20 @@ BackgroundId BackgroundManager::set_background(const td_api::InputBackground *in
|
||||
local_background_ids_[for_dark_theme].insert(local_background_ids_[for_dark_theme].begin(), background_id);
|
||||
save_local_backgrounds(for_dark_theme);
|
||||
|
||||
promise.set_value(Unit());
|
||||
return background_id;
|
||||
return promise.set_value(get_background_object(background_id, for_dark_theme, nullptr));
|
||||
}
|
||||
|
||||
switch (input_background->get_id()) {
|
||||
case td_api::inputBackgroundLocal::ID: {
|
||||
if (!type.has_file()) {
|
||||
promise.set_error(Status::Error(400, "Can't specify local file for the background type"));
|
||||
return BackgroundId();
|
||||
return promise.set_error(Status::Error(400, "Can't specify local file for the background type"));
|
||||
}
|
||||
CHECK(background_type != nullptr);
|
||||
|
||||
auto background_local = static_cast<const td_api::inputBackgroundLocal *>(input_background);
|
||||
auto r_file_id = prepare_input_file(background_local->background_);
|
||||
if (r_file_id.is_error()) {
|
||||
promise.set_error(r_file_id.move_as_error());
|
||||
return BackgroundId();
|
||||
return promise.set_error(r_file_id.move_as_error());
|
||||
}
|
||||
auto file_id = r_file_id.move_as_ok();
|
||||
LOG(INFO) << "Receive file " << file_id << " for input background";
|
||||
@ -675,34 +670,29 @@ BackgroundId BackgroundManager::set_background(const td_api::InputBackground *in
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return BackgroundId();
|
||||
}
|
||||
|
||||
BackgroundId BackgroundManager::set_background(BackgroundId background_id, BackgroundType type, bool for_dark_theme,
|
||||
Promise<Unit> &&promise) {
|
||||
void BackgroundManager::set_background(BackgroundId background_id, BackgroundType type, bool for_dark_theme,
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise) {
|
||||
LOG(INFO) << "Set " << background_id << " with " << type;
|
||||
const auto *background = get_background(background_id);
|
||||
if (background == nullptr) {
|
||||
promise.set_error(Status::Error(400, "Background to set not found"));
|
||||
return BackgroundId();
|
||||
return promise.set_error(Status::Error(400, "Background to set not found"));
|
||||
}
|
||||
if (!type.has_file()) {
|
||||
type = background->type;
|
||||
} else if (!background->type.has_equal_type(type)) {
|
||||
promise.set_error(Status::Error(400, "Background type mismatch"));
|
||||
return BackgroundId();
|
||||
return promise.set_error(Status::Error(400, "Background type mismatch"));
|
||||
}
|
||||
if (set_background_id_[for_dark_theme] == background_id && set_background_type_[for_dark_theme] == type) {
|
||||
promise.set_value(Unit());
|
||||
return background_id;
|
||||
return promise.set_value(get_background_object(background_id, for_dark_theme, nullptr));
|
||||
}
|
||||
|
||||
LOG(INFO) << "Install " << background_id << " with " << type;
|
||||
|
||||
if (!type.has_file()) {
|
||||
set_background_id(background_id, type, for_dark_theme);
|
||||
promise.set_value(Unit());
|
||||
return background_id;
|
||||
return promise.set_value(get_background_object(background_id, for_dark_theme, nullptr));
|
||||
}
|
||||
|
||||
auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), background_id, type, for_dark_theme,
|
||||
@ -713,11 +703,11 @@ BackgroundId BackgroundManager::set_background(BackgroundId background_id, Backg
|
||||
td_->create_handler<InstallBackgroundQuery>(std::move(query_promise))
|
||||
->send(telegram_api::make_object<telegram_api::inputWallPaper>(background_id.get(), background->access_hash),
|
||||
type);
|
||||
return BackgroundId();
|
||||
}
|
||||
|
||||
void BackgroundManager::on_installed_background(BackgroundId background_id, BackgroundType type, bool for_dark_theme,
|
||||
Result<Unit> &&result, Promise<Unit> &&promise) {
|
||||
Result<Unit> &&result,
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise) {
|
||||
if (result.is_error()) {
|
||||
return promise.set_error(result.move_as_error());
|
||||
}
|
||||
@ -733,7 +723,7 @@ void BackgroundManager::on_installed_background(BackgroundId background_id, Back
|
||||
installed_backgrounds_.insert(installed_backgrounds_.begin(), {background_id, type});
|
||||
}
|
||||
set_background_id(background_id, type, for_dark_theme);
|
||||
promise.set_value(Unit());
|
||||
promise.set_value(get_background_object(background_id, for_dark_theme, nullptr));
|
||||
}
|
||||
|
||||
string BackgroundManager::get_background_database_key(bool for_dark_theme) {
|
||||
@ -790,8 +780,8 @@ void BackgroundManager::save_local_backgrounds(bool for_dark_theme) {
|
||||
}
|
||||
|
||||
void BackgroundManager::upload_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme,
|
||||
Promise<Unit> &&promise) {
|
||||
auto upload_file_id = td_->file_manager_->dup_file_id(file_id);
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise) {
|
||||
auto upload_file_id = td_->file_manager_->dup_file_id(file_id, "upload_background_file");
|
||||
bool is_inserted =
|
||||
being_uploaded_files_.emplace(upload_file_id, UploadedFileInfo(type, for_dark_theme, std::move(promise))).second;
|
||||
CHECK(is_inserted);
|
||||
@ -836,14 +826,13 @@ void BackgroundManager::on_upload_background_file_error(FileId file_id, Status s
|
||||
|
||||
void BackgroundManager::do_upload_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme,
|
||||
tl_object_ptr<telegram_api::InputFile> &&input_file,
|
||||
Promise<Unit> &&promise) {
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise) {
|
||||
if (input_file == nullptr) {
|
||||
FileView file_view = td_->file_manager_->get_file_view(file_id);
|
||||
file_id = file_view.get_main_file_id();
|
||||
auto it = file_id_to_background_id_.find(file_id);
|
||||
if (it != file_id_to_background_id_.end()) {
|
||||
set_background(it->second, type, for_dark_theme, std::move(promise));
|
||||
return;
|
||||
return set_background(it->second, type, for_dark_theme, std::move(promise));
|
||||
}
|
||||
return promise.set_error(Status::Error(500, "Failed to reupload background"));
|
||||
}
|
||||
@ -854,7 +843,7 @@ void BackgroundManager::do_upload_background_file(FileId file_id, const Backgrou
|
||||
|
||||
void BackgroundManager::on_uploaded_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme,
|
||||
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper,
|
||||
Promise<Unit> &&promise) {
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise) {
|
||||
CHECK(wallpaper != nullptr);
|
||||
|
||||
auto added_background = on_get_background(BackgroundId(), string(), std::move(wallpaper), true);
|
||||
@ -874,7 +863,7 @@ void BackgroundManager::on_uploaded_background_file(FileId file_id, const Backgr
|
||||
}
|
||||
LOG_STATUS(td_->file_manager_->merge(background->file_id, file_id));
|
||||
set_background_id(background_id, type, for_dark_theme);
|
||||
promise.set_value(Unit());
|
||||
promise.set_value(get_background_object(background_id, for_dark_theme, nullptr));
|
||||
}
|
||||
|
||||
void BackgroundManager::remove_background(BackgroundId background_id, Promise<Unit> &&promise) {
|
||||
|
@ -41,9 +41,8 @@ class BackgroundManager final : public Actor {
|
||||
|
||||
std::pair<BackgroundId, BackgroundType> search_background(const string &name, Promise<Unit> &&promise);
|
||||
|
||||
BackgroundId set_background(const td_api::InputBackground *input_background,
|
||||
const td_api::BackgroundType *background_type, bool for_dark_theme,
|
||||
Promise<Unit> &&promise);
|
||||
void set_background(const td_api::InputBackground *input_background, const td_api::BackgroundType *background_type,
|
||||
bool for_dark_theme, Promise<td_api::object_ptr<td_api::background>> &&promise);
|
||||
|
||||
void remove_background(BackgroundId background_id, Promise<Unit> &&promise);
|
||||
|
||||
@ -60,7 +59,7 @@ class BackgroundManager final : public Actor {
|
||||
|
||||
void on_uploaded_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme,
|
||||
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper,
|
||||
Promise<Unit> &&promise);
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise);
|
||||
|
||||
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
|
||||
|
||||
@ -137,11 +136,11 @@ class BackgroundManager final : public Actor {
|
||||
|
||||
Result<FileId> prepare_input_file(const tl_object_ptr<td_api::InputFile> &input_file);
|
||||
|
||||
BackgroundId set_background(BackgroundId background_id, BackgroundType type, bool for_dark_theme,
|
||||
Promise<Unit> &&promise);
|
||||
void set_background(BackgroundId background_id, BackgroundType type, bool for_dark_theme,
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise);
|
||||
|
||||
void on_installed_background(BackgroundId background_id, BackgroundType type, bool for_dark_theme,
|
||||
Result<Unit> &&result, Promise<Unit> &&promise);
|
||||
Result<Unit> &&result, Promise<td_api::object_ptr<td_api::background>> &&promise);
|
||||
|
||||
void set_background_id(BackgroundId background_id, const BackgroundType &type, bool for_dark_theme);
|
||||
|
||||
@ -149,14 +148,16 @@ class BackgroundManager final : public Actor {
|
||||
|
||||
void on_reset_background(Result<Unit> &&result, Promise<Unit> &&promise);
|
||||
|
||||
void upload_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme, Promise<Unit> &&promise);
|
||||
void upload_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme,
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise);
|
||||
|
||||
void on_upload_background_file(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file);
|
||||
|
||||
void on_upload_background_file_error(FileId file_id, Status status);
|
||||
|
||||
void do_upload_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme,
|
||||
tl_object_ptr<telegram_api::InputFile> &&input_file, Promise<Unit> &&promise);
|
||||
tl_object_ptr<telegram_api::InputFile> &&input_file,
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise);
|
||||
|
||||
FlatHashMap<BackgroundId, unique_ptr<Background>, BackgroundIdHash> backgrounds_;
|
||||
|
||||
@ -182,9 +183,10 @@ class BackgroundManager final : public Actor {
|
||||
struct UploadedFileInfo {
|
||||
BackgroundType type_;
|
||||
bool for_dark_theme_;
|
||||
Promise<Unit> promise_;
|
||||
Promise<td_api::object_ptr<td_api::background>> promise_;
|
||||
|
||||
UploadedFileInfo(BackgroundType type, bool for_dark_theme, Promise<Unit> &&promise)
|
||||
UploadedFileInfo(BackgroundType type, bool for_dark_theme,
|
||||
Promise<td_api::object_ptr<td_api::background>> &&promise)
|
||||
: type_(type), for_dark_theme_(for_dark_theme), promise_(std::move(promise)) {
|
||||
}
|
||||
};
|
||||
|
@ -377,7 +377,7 @@ void CallActor::send_call_log(td_api::object_ptr<td_api::InputFile> log_file, Pr
|
||||
|
||||
void CallActor::upload_log_file(FileId file_id, Promise<Unit> &&promise) {
|
||||
auto *file_manager = G()->td().get_actor_unsafe()->file_manager_.get();
|
||||
auto upload_file_id = file_manager->dup_file_id(file_id);
|
||||
auto upload_file_id = file_manager->dup_file_id(file_id, "upload_log_file");
|
||||
LOG(INFO) << "Ask to upload call log file " << upload_file_id;
|
||||
|
||||
class UploadLogFileCallback final : public FileManager::UploadCallback {
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include "td/telegram/td_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -47,8 +47,8 @@ class CallId {
|
||||
};
|
||||
|
||||
struct CallIdHash {
|
||||
std::size_t operator()(CallId call_id) const {
|
||||
return std::hash<int32>()(call_id.get());
|
||||
uint32 operator()(CallId call_id) const {
|
||||
return Hash<int32>()(call_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -15,8 +15,7 @@
|
||||
#include "td/telegram/PollId.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
|
||||
#include <functional>
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
@ -47,7 +46,7 @@ class ChainId {
|
||||
ChainId(PollId poll_id) : id(static_cast<uint64>(poll_id.get())) {
|
||||
}
|
||||
|
||||
ChainId(const string &str) : id(std::hash<string>()(str)) {
|
||||
ChainId(const string &str) : id(Hash<string>()(str)) {
|
||||
}
|
||||
|
||||
uint64 get() const {
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -62,8 +62,8 @@ class ChannelId {
|
||||
};
|
||||
|
||||
struct ChannelIdHash {
|
||||
std::size_t operator()(ChannelId channel_id) const {
|
||||
return std::hash<int64>()(channel_id.get());
|
||||
uint32 operator()(ChannelId channel_id) const {
|
||||
return Hash<int64>()(channel_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -61,8 +61,8 @@ class ChatId {
|
||||
};
|
||||
|
||||
struct ChatIdHash {
|
||||
std::size_t operator()(ChatId chat_id) const {
|
||||
return std::hash<int64>()(chat_id.get());
|
||||
uint32 operator()(ChatId chat_id) const {
|
||||
return Hash<int64>()(chat_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "td/mtproto/TransportType.h"
|
||||
|
||||
#if !TD_EMSCRIPTEN //FIXME
|
||||
#include "td/net/SslStream.h"
|
||||
#include "td/net/SslCtx.h"
|
||||
#include "td/net/Wget.h"
|
||||
#endif
|
||||
|
||||
@ -239,7 +239,7 @@ static ActorOwn<> get_simple_config_impl(Promise<SimpleConfigResult> promise, in
|
||||
return std::move(res);
|
||||
}());
|
||||
}),
|
||||
std::move(url), std::move(headers), timeout, ttl, prefer_ipv6, SslStream::VerifyPeer::Off, std::move(content),
|
||||
std::move(url), std::move(headers), timeout, ttl, prefer_ipv6, SslCtx::VerifyPeer::Off, std::move(content),
|
||||
std::move(content_type)));
|
||||
#endif
|
||||
}
|
||||
@ -955,7 +955,7 @@ void ConfigManager::request_config(bool reopen_sessions) {
|
||||
return;
|
||||
}
|
||||
|
||||
lazy_request_flood_control_.add_event(static_cast<int32>(Timestamp::now().at()));
|
||||
lazy_request_flood_control_.add_event(Time::now());
|
||||
request_config_from_dc_impl(DcId::main(), reopen_sessions);
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,11 @@
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
|
||||
namespace td {
|
||||
@ -128,18 +128,16 @@ bool operator!=(const Contact &lhs, const Contact &rhs);
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const Contact &contact);
|
||||
|
||||
struct ContactEqual {
|
||||
std::size_t operator()(const Contact &lhs, const Contact &rhs) const {
|
||||
bool operator()(const Contact &lhs, const Contact &rhs) const {
|
||||
return std::tie(lhs.phone_number_, lhs.first_name_, lhs.last_name_) ==
|
||||
std::tie(rhs.phone_number_, rhs.first_name_, rhs.last_name_);
|
||||
}
|
||||
};
|
||||
|
||||
struct ContactHash {
|
||||
std::size_t operator()(const Contact &contact) const {
|
||||
return (std::hash<std::string>()(contact.phone_number_) * 2023654985u +
|
||||
std::hash<std::string>()(contact.first_name_)) *
|
||||
2023654985u +
|
||||
std::hash<std::string>()(contact.last_name_);
|
||||
uint32 operator()(const Contact &contact) const {
|
||||
return (Hash<string>()(contact.phone_number_) * 2023654985u + Hash<string>()(contact.first_name_)) * 2023654985u +
|
||||
Hash<string>()(contact.last_name_);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "td/telegram/PasswordManager.h"
|
||||
#include "td/telegram/Photo.h"
|
||||
#include "td/telegram/Photo.hpp"
|
||||
#include "td/telegram/PhotoSize.h"
|
||||
#include "td/telegram/PremiumGiftOption.hpp"
|
||||
#include "td/telegram/SecretChatLayer.h"
|
||||
#include "td/telegram/SecretChatsManager.h"
|
||||
@ -2492,14 +2493,14 @@ class InviteToChannelQuery final : public Td::ResultHandler {
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for InviteToChannelQuery: " << to_string(ptr);
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false);
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "InviteToChannelQuery");
|
||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "InviteToChannelQuery");
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "InviteToChannelQuery");
|
||||
promise_.set_error(std::move(status));
|
||||
td_->updates_manager_->get_difference("InviteToChannelQuery");
|
||||
}
|
||||
};
|
||||
|
||||
@ -2532,15 +2533,15 @@ class EditChannelAdminQuery final : public Td::ResultHandler {
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for EditChannelAdminQuery: " << to_string(ptr);
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false);
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelAdminQuery");
|
||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
||||
td_->contacts_manager_->on_set_channel_participant_status(channel_id_, DialogId(user_id_), status_);
|
||||
}
|
||||
|
||||
void on_error(Status status) final {
|
||||
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelAdminQuery");
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelAdminQuery");
|
||||
promise_.set_error(std::move(status));
|
||||
td_->updates_manager_->get_difference("EditChannelAdminQuery");
|
||||
}
|
||||
};
|
||||
|
||||
@ -2573,7 +2574,7 @@ class EditChannelBannedQuery final : public Td::ResultHandler {
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for EditChannelBannedQuery: " << to_string(ptr);
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false);
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelBannedQuery");
|
||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
||||
td_->contacts_manager_->on_set_channel_participant_status(channel_id_, participant_dialog_id_, status_);
|
||||
}
|
||||
@ -2582,8 +2583,8 @@ class EditChannelBannedQuery final : public Td::ResultHandler {
|
||||
if (participant_dialog_id_.get_type() != DialogType::Channel) {
|
||||
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "EditChannelBannedQuery");
|
||||
}
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelBannedQuery");
|
||||
promise_.set_error(std::move(status));
|
||||
td_->updates_manager_->get_difference("EditChannelBannedQuery");
|
||||
}
|
||||
};
|
||||
|
||||
@ -2685,7 +2686,7 @@ class EditChannelCreatorQuery final : public Td::ResultHandler {
|
||||
|
||||
auto ptr = result_ptr.move_as_ok();
|
||||
LOG(INFO) << "Receive result for EditChannelCreatorQuery: " << to_string(ptr);
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false);
|
||||
td_->contacts_manager_->invalidate_channel_full(channel_id_, false, "EditChannelCreatorQuery");
|
||||
td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_));
|
||||
}
|
||||
|
||||
@ -3708,10 +3709,10 @@ void ContactsManager::start_up() {
|
||||
void ContactsManager::tear_down() {
|
||||
parent_.reset();
|
||||
|
||||
LOG(DEBUG) << "Have " << users_.size() << " users, " << chats_.size() << " basic groups, " << channels_.size()
|
||||
<< " supergroups and " << secret_chats_.size() << " secret chats to free";
|
||||
LOG(DEBUG) << "Have " << users_full_.size() << " full users, " << chats_full_.size() << " full basic groups and "
|
||||
<< channels_full_.size() << " full supergroups to free";
|
||||
LOG(DEBUG) << "Have " << users_.calc_size() << " users, " << chats_.calc_size() << " basic groups, "
|
||||
<< channels_.calc_size() << " supergroups and " << secret_chats_.calc_size() << " secret chats to free";
|
||||
LOG(DEBUG) << "Have " << users_full_.calc_size() << " full users, " << chats_full_.calc_size()
|
||||
<< " full basic groups and " << channels_full_.calc_size() << " full supergroups to free";
|
||||
}
|
||||
|
||||
UserId ContactsManager::load_my_id() {
|
||||
@ -3810,7 +3811,7 @@ void ContactsManager::on_channel_unban_timeout(ChannelId channel_id) {
|
||||
|
||||
LOG(INFO) << "Update " << channel_id << " status";
|
||||
c->is_status_changed = true;
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled, "on_channel_unban_timeout");
|
||||
update_channel(c, channel_id); // always call, because in case of failure we need to reactivate timeout
|
||||
}
|
||||
|
||||
@ -5158,10 +5159,9 @@ void ContactsManager::apply_pending_user_photo(User *u, UserId user_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = pending_user_photos_.find(user_id);
|
||||
if (it != pending_user_photos_.end()) {
|
||||
do_update_user_photo(u, user_id, std::move(it->second), "apply_pending_user_photo");
|
||||
pending_user_photos_.erase(it);
|
||||
if (pending_user_photos_.count(user_id) > 0) {
|
||||
do_update_user_photo(u, user_id, std::move(pending_user_photos_[user_id]), "apply_pending_user_photo");
|
||||
pending_user_photos_.erase(user_id);
|
||||
update_user(u, user_id);
|
||||
}
|
||||
}
|
||||
@ -6095,7 +6095,7 @@ std::pair<vector<UserId>, vector<int32>> ContactsManager::change_imported_contac
|
||||
vector<Contact> unique_new_contacts;
|
||||
unique_new_contacts.reserve(contacts.size());
|
||||
std::unordered_map<Contact, size_t, ContactHash, ContactEqual> different_new_contacts;
|
||||
std::unordered_set<string> different_new_phone_numbers;
|
||||
std::unordered_set<string, Hash<string>> different_new_phone_numbers;
|
||||
size_t unique_size = 0;
|
||||
for (size_t i = 0; i < contacts.size(); i++) {
|
||||
auto it_success = different_new_contacts.emplace(std::move(contacts[i]), unique_size);
|
||||
@ -6778,7 +6778,8 @@ void ContactsManager::set_profile_photo(const td_api::object_ptr<td_api::InputCh
|
||||
if (!file_id.is_valid()) {
|
||||
return promise.set_error(Status::Error(400, "Unknown profile photo ID specified"));
|
||||
}
|
||||
return send_update_profile_photo_query(td_->file_manager_->dup_file_id(file_id), photo_id, std::move(promise));
|
||||
return send_update_profile_photo_query(td_->file_manager_->dup_file_id(file_id, "set_profile_photo"), photo_id,
|
||||
std::move(promise));
|
||||
}
|
||||
case td_api::inputChatPhotoStatic::ID: {
|
||||
auto photo = static_cast<const td_api::inputChatPhotoStatic *>(input_photo.get());
|
||||
@ -6811,8 +6812,8 @@ void ContactsManager::set_profile_photo(const td_api::object_ptr<td_api::InputCh
|
||||
FileId file_id = r_file_id.ok();
|
||||
CHECK(file_id.is_valid());
|
||||
|
||||
upload_profile_photo(td_->file_manager_->dup_file_id(file_id), is_animation, main_frame_timestamp,
|
||||
std::move(promise));
|
||||
upload_profile_photo(td_->file_manager_->dup_file_id(file_id, "set_profile_photo"), is_animation,
|
||||
main_frame_timestamp, std::move(promise));
|
||||
}
|
||||
|
||||
void ContactsManager::send_update_profile_photo_query(FileId file_id, int64 old_photo_id, Promise<Unit> &&promise) {
|
||||
@ -7757,6 +7758,9 @@ void ContactsManager::add_channel_participants(ChannelId channel_id, const vecto
|
||||
continue;
|
||||
}
|
||||
input_users.push_back(r_input_user.move_as_ok());
|
||||
|
||||
speculative_add_channel_user(channel_id, user_id, DialogParticipantStatus::Member(),
|
||||
DialogParticipantStatus::Left());
|
||||
}
|
||||
|
||||
if (input_users.empty()) {
|
||||
@ -7806,53 +7810,54 @@ void ContactsManager::set_channel_participant_status(ChannelId channel_id, Dialo
|
||||
}
|
||||
|
||||
void ContactsManager::set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
|
||||
DialogParticipantStatus status,
|
||||
DialogParticipantStatus new_status,
|
||||
DialogParticipantStatus old_status, Promise<Unit> &&promise) {
|
||||
if (old_status == status && !old_status.is_creator()) {
|
||||
if (old_status == new_status && !old_status.is_creator()) {
|
||||
return promise.set_value(Unit());
|
||||
}
|
||||
CHECK(participant_dialog_id.get_type() == DialogType::User);
|
||||
|
||||
LOG(INFO) << "Change status of " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
|
||||
<< status;
|
||||
<< new_status;
|
||||
bool need_add = false;
|
||||
bool need_promote = false;
|
||||
bool need_restrict = false;
|
||||
if (status.is_creator() || old_status.is_creator()) {
|
||||
if (new_status.is_creator() || old_status.is_creator()) {
|
||||
if (!old_status.is_creator()) {
|
||||
return promise.set_error(Status::Error(400, "Can't add another owner to the chat"));
|
||||
}
|
||||
if (!status.is_creator()) {
|
||||
if (!new_status.is_creator()) {
|
||||
return promise.set_error(Status::Error(400, "Can't remove chat owner"));
|
||||
}
|
||||
auto user_id = get_my_id();
|
||||
if (participant_dialog_id != DialogId(user_id)) {
|
||||
return promise.set_error(Status::Error(400, "Not enough rights to edit chat owner rights"));
|
||||
}
|
||||
if (status.is_member() == old_status.is_member()) {
|
||||
if (new_status.is_member() == old_status.is_member()) {
|
||||
// change rank and is_anonymous
|
||||
auto r_input_user = get_input_user(user_id);
|
||||
CHECK(r_input_user.is_ok());
|
||||
td_->create_handler<EditChannelAdminQuery>(std::move(promise))
|
||||
->send(channel_id, user_id, r_input_user.move_as_ok(), status);
|
||||
->send(channel_id, user_id, r_input_user.move_as_ok(), new_status);
|
||||
return;
|
||||
}
|
||||
if (status.is_member()) {
|
||||
if (new_status.is_member()) {
|
||||
// creator not member -> creator member
|
||||
need_add = true;
|
||||
} else {
|
||||
// creator member -> creator not member
|
||||
need_restrict = true;
|
||||
}
|
||||
} else if (status.is_administrator()) {
|
||||
} else if (new_status.is_administrator()) {
|
||||
need_promote = true;
|
||||
} else if (!status.is_member() || status.is_restricted()) {
|
||||
if (status.is_member() && !old_status.is_member()) {
|
||||
} else if (!new_status.is_member() || new_status.is_restricted()) {
|
||||
if (new_status.is_member() && !old_status.is_member()) {
|
||||
// TODO there is no way in server API to invite someone and change restrictions
|
||||
// we need to first add user and change restrictions again after that
|
||||
// but if restrictions aren't changed, then adding is enough
|
||||
auto copy_old_status = old_status;
|
||||
copy_old_status.set_is_member(true);
|
||||
if (copy_old_status == status) {
|
||||
if (copy_old_status == new_status) {
|
||||
need_add = true;
|
||||
} else {
|
||||
need_restrict = true;
|
||||
@ -7876,10 +7881,10 @@ void ContactsManager::set_channel_participant_status_impl(ChannelId channel_id,
|
||||
if (participant_dialog_id.get_type() != DialogType::User) {
|
||||
return promise.set_error(Status::Error(400, "Can't promote chats to chat administrators"));
|
||||
}
|
||||
return promote_channel_participant(channel_id, participant_dialog_id.get_user_id(), status, old_status,
|
||||
return promote_channel_participant(channel_id, participant_dialog_id.get_user_id(), new_status, old_status,
|
||||
std::move(promise));
|
||||
} else if (need_restrict) {
|
||||
return restrict_channel_participant(channel_id, participant_dialog_id, std::move(status), std::move(old_status),
|
||||
return restrict_channel_participant(channel_id, participant_dialog_id, std::move(new_status), std::move(old_status),
|
||||
std::move(promise));
|
||||
} else {
|
||||
CHECK(need_add);
|
||||
@ -7891,17 +7896,17 @@ void ContactsManager::set_channel_participant_status_impl(ChannelId channel_id,
|
||||
}
|
||||
|
||||
void ContactsManager::promote_channel_participant(ChannelId channel_id, UserId user_id,
|
||||
const DialogParticipantStatus &status,
|
||||
const DialogParticipantStatus &new_status,
|
||||
const DialogParticipantStatus &old_status, Promise<Unit> &&promise) {
|
||||
LOG(INFO) << "Promote " << user_id << " in " << channel_id << " from " << old_status << " to " << status;
|
||||
LOG(INFO) << "Promote " << user_id << " in " << channel_id << " from " << old_status << " to " << new_status;
|
||||
const Channel *c = get_channel(channel_id);
|
||||
CHECK(c != nullptr);
|
||||
|
||||
if (user_id == get_my_id()) {
|
||||
if (status.is_administrator()) {
|
||||
if (new_status.is_administrator()) {
|
||||
return promise.set_error(Status::Error(400, "Can't promote self"));
|
||||
}
|
||||
CHECK(status.is_member());
|
||||
CHECK(new_status.is_member());
|
||||
// allow to demote self. TODO is it allowed server-side?
|
||||
} else {
|
||||
if (!get_channel_permissions(c).can_promote_members()) {
|
||||
@ -7909,14 +7914,14 @@ void ContactsManager::promote_channel_participant(ChannelId channel_id, UserId u
|
||||
}
|
||||
|
||||
CHECK(!old_status.is_creator());
|
||||
CHECK(!status.is_creator());
|
||||
CHECK(!new_status.is_creator());
|
||||
}
|
||||
|
||||
TRY_RESULT_PROMISE(promise, input_user, get_input_user(user_id));
|
||||
|
||||
speculative_add_channel_user(channel_id, user_id, status, old_status);
|
||||
speculative_add_channel_user(channel_id, user_id, new_status, old_status);
|
||||
td_->create_handler<EditChannelAdminQuery>(std::move(promise))
|
||||
->send(channel_id, user_id, std::move(input_user), status);
|
||||
->send(channel_id, user_id, std::move(input_user), new_status);
|
||||
}
|
||||
|
||||
void ContactsManager::set_chat_participant_status(ChatId chat_id, UserId user_id, DialogParticipantStatus status,
|
||||
@ -8394,19 +8399,19 @@ void ContactsManager::delete_chat_participant(ChatId chat_id, UserId user_id, bo
|
||||
}
|
||||
|
||||
void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
|
||||
DialogParticipantStatus &&status,
|
||||
DialogParticipantStatus &&new_status,
|
||||
DialogParticipantStatus &&old_status, Promise<Unit> &&promise) {
|
||||
TRY_STATUS_PROMISE(promise, G()->close_status());
|
||||
|
||||
LOG(INFO) << "Restrict " << participant_dialog_id << " in " << channel_id << " from " << old_status << " to "
|
||||
<< status;
|
||||
<< new_status;
|
||||
const Channel *c = get_channel(channel_id);
|
||||
if (c == nullptr) {
|
||||
return promise.set_error(Status::Error(400, "Chat info not found"));
|
||||
}
|
||||
if (!c->status.is_member() && !c->status.is_creator()) {
|
||||
if (participant_dialog_id == DialogId(get_my_id())) {
|
||||
if (status.is_member()) {
|
||||
if (new_status.is_member()) {
|
||||
return promise.set_error(Status::Error(400, "Can't unrestrict self"));
|
||||
}
|
||||
return promise.set_value(Unit());
|
||||
@ -8420,15 +8425,15 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogI
|
||||
}
|
||||
|
||||
if (participant_dialog_id == DialogId(get_my_id())) {
|
||||
if (status.is_restricted() || status.is_banned()) {
|
||||
if (new_status.is_restricted() || new_status.is_banned()) {
|
||||
return promise.set_error(Status::Error(400, "Can't restrict self"));
|
||||
}
|
||||
if (status.is_member()) {
|
||||
if (new_status.is_member()) {
|
||||
return promise.set_error(Status::Error(400, "Can't unrestrict self"));
|
||||
}
|
||||
|
||||
// leave the channel
|
||||
speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), status, c->status);
|
||||
speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), new_status, c->status);
|
||||
td_->create_handler<LeaveChannelQuery>(std::move(promise))->send(channel_id);
|
||||
return;
|
||||
}
|
||||
@ -8438,7 +8443,7 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogI
|
||||
// ok;
|
||||
break;
|
||||
case DialogType::Channel:
|
||||
if (status.is_administrator() || status.is_member() || status.is_restricted()) {
|
||||
if (new_status.is_administrator() || new_status.is_member() || new_status.is_restricted()) {
|
||||
return promise.set_error(Status::Error(400, "Other chats can be only banned or unbanned"));
|
||||
}
|
||||
break;
|
||||
@ -8447,16 +8452,16 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogI
|
||||
}
|
||||
|
||||
CHECK(!old_status.is_creator());
|
||||
CHECK(!status.is_creator());
|
||||
CHECK(!new_status.is_creator());
|
||||
|
||||
if (!get_channel_permissions(c).can_restrict_members()) {
|
||||
return promise.set_error(Status::Error(400, "Not enough rights to restrict/unrestrict chat member"));
|
||||
}
|
||||
|
||||
if (old_status.is_member() && !status.is_member() && !status.is_banned()) {
|
||||
if (old_status.is_member() && !new_status.is_member() && !new_status.is_banned()) {
|
||||
// we can't make participant Left without kicking it first
|
||||
auto on_result_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id,
|
||||
status = std::move(status),
|
||||
new_status = std::move(new_status),
|
||||
promise = std::move(promise)](Result<> result) mutable {
|
||||
if (result.is_error()) {
|
||||
return promise.set_error(result.move_as_error());
|
||||
@ -8464,27 +8469,56 @@ void ContactsManager::restrict_channel_participant(ChannelId channel_id, DialogI
|
||||
|
||||
create_actor<SleepActor>(
|
||||
"RestrictChannelParticipantSleepActor", 1.0,
|
||||
PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, status = std::move(status),
|
||||
PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, new_status = std::move(new_status),
|
||||
promise = std::move(promise)](Result<> result) mutable {
|
||||
if (result.is_error()) {
|
||||
return promise.set_error(result.move_as_error());
|
||||
}
|
||||
|
||||
send_closure(actor_id, &ContactsManager::restrict_channel_participant, channel_id, participant_dialog_id,
|
||||
std::move(status), DialogParticipantStatus::Banned(0), std::move(promise));
|
||||
std::move(new_status), DialogParticipantStatus::Banned(0), std::move(promise));
|
||||
}))
|
||||
.release();
|
||||
});
|
||||
|
||||
promise = std::move(on_result_promise);
|
||||
status = DialogParticipantStatus::Banned(G()->unix_time() + 60);
|
||||
new_status = DialogParticipantStatus::Banned(G()->unix_time() + 60);
|
||||
}
|
||||
|
||||
if (new_status.is_member() && !old_status.is_member()) {
|
||||
// there is no way in server API to invite someone and change restrictions
|
||||
// we need to first change restrictions and then try to add the user
|
||||
CHECK(participant_dialog_id.get_type() == DialogType::User);
|
||||
new_status.set_is_member(false);
|
||||
auto on_result_promise =
|
||||
PromiseCreator::lambda([actor_id = actor_id(this), channel_id, participant_dialog_id, old_status = new_status,
|
||||
promise = std::move(promise)](Result<> result) mutable {
|
||||
if (result.is_error()) {
|
||||
return promise.set_error(result.move_as_error());
|
||||
}
|
||||
|
||||
create_actor<SleepActor>(
|
||||
"AddChannelParticipantSleepActor", 1.0,
|
||||
PromiseCreator::lambda([actor_id, channel_id, participant_dialog_id, old_status = std::move(old_status),
|
||||
promise = std::move(promise)](Result<> result) mutable {
|
||||
if (result.is_error()) {
|
||||
return promise.set_error(result.move_as_error());
|
||||
}
|
||||
|
||||
send_closure(actor_id, &ContactsManager::add_channel_participant, channel_id,
|
||||
participant_dialog_id.get_user_id(), old_status, std::move(promise));
|
||||
}))
|
||||
.release();
|
||||
});
|
||||
|
||||
promise = std::move(on_result_promise);
|
||||
}
|
||||
|
||||
if (participant_dialog_id.get_type() == DialogType::User) {
|
||||
speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), status, old_status);
|
||||
speculative_add_channel_user(channel_id, participant_dialog_id.get_user_id(), new_status, old_status);
|
||||
}
|
||||
td_->create_handler<EditChannelBannedQuery>(std::move(promise))
|
||||
->send(channel_id, participant_dialog_id, std::move(input_peer), status);
|
||||
->send(channel_id, participant_dialog_id, std::move(input_peer), new_status);
|
||||
}
|
||||
|
||||
void ContactsManager::on_set_channel_participant_status(ChannelId channel_id, DialogId participant_dialog_id,
|
||||
@ -8891,12 +8925,12 @@ void ContactsManager::on_import_contacts_finished(int64 random_id, vector<UserId
|
||||
CHECK(unimported_contact_invites.size() == add_size);
|
||||
CHECK(imported_contacts_unique_id_.size() == result_size);
|
||||
|
||||
std::unordered_map<size_t, int32> unique_id_to_unimported_contact_invites;
|
||||
std::unordered_map<int64, int32, Hash<int64>> unique_id_to_unimported_contact_invites;
|
||||
for (size_t i = 0; i < add_size; i++) {
|
||||
auto unique_id = imported_contacts_pos_[i];
|
||||
get_user_id_object(imported_contact_user_ids[i], "on_import_contacts_finished"); // to ensure updateUser
|
||||
all_imported_contacts_[unique_id].set_user_id(imported_contact_user_ids[i]);
|
||||
unique_id_to_unimported_contact_invites[unique_id] = unimported_contact_invites[i];
|
||||
unique_id_to_unimported_contact_invites[narrow_cast<int64>(unique_id)] = unimported_contact_invites[i];
|
||||
}
|
||||
|
||||
if (G()->parameters().use_chat_info_db) {
|
||||
@ -8913,7 +8947,7 @@ void ContactsManager::on_import_contacts_finished(int64 random_id, vector<UserId
|
||||
auto unique_id = imported_contacts_unique_id_[i];
|
||||
CHECK(unique_id < unique_size);
|
||||
imported_contact_user_ids_[i] = all_imported_contacts_[unique_id].get_user_id();
|
||||
auto it = unique_id_to_unimported_contact_invites.find(unique_id);
|
||||
auto it = unique_id_to_unimported_contact_invites.find(narrow_cast<int64>(unique_id));
|
||||
if (it == unique_id_to_unimported_contact_invites.end()) {
|
||||
unimported_contact_invites_[i] = 0;
|
||||
} else {
|
||||
@ -11110,6 +11144,11 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_channel_public(c) && !c->has_linked_channel) {
|
||||
send_closure_later(G()->messages_manager(), &MessagesManager::on_update_dialog_default_send_message_as_dialog_id,
|
||||
DialogId(channel_id), DialogId(), false);
|
||||
}
|
||||
|
||||
if (need_update_channel_full) {
|
||||
auto channel_full = get_channel_full(channel_id, true, "update_channel");
|
||||
CHECK(channel_full != nullptr);
|
||||
@ -11537,6 +11576,14 @@ void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&u
|
||||
td_->messages_manager_->on_get_peer_settings(DialogId(user_id), std::move(user->settings_));
|
||||
}
|
||||
|
||||
ContactsManager::UserPhotos *ContactsManager::add_user_photos(UserId user_id) {
|
||||
auto &user_photos_ptr = user_photos_[user_id];
|
||||
if (user_photos_ptr == nullptr) {
|
||||
user_photos_ptr = make_unique<UserPhotos>();
|
||||
}
|
||||
return user_photos_ptr.get();
|
||||
}
|
||||
|
||||
void ContactsManager::on_get_user_photos(UserId user_id, int32 offset, int32 limit, int32 total_count,
|
||||
vector<tl_object_ptr<telegram_api::Photo>> photos) {
|
||||
auto photo_count = narrow_cast<int32>(photos.size());
|
||||
@ -11580,7 +11627,7 @@ void ContactsManager::on_get_user_photos(UserId user_id, int32 offset, int32 lim
|
||||
|
||||
LOG(INFO) << "Receive " << photo_count << " photos of " << user_id << " out of " << total_count << " with offset "
|
||||
<< offset << " and limit " << limit;
|
||||
UserPhotos *user_photos = &user_photos_[user_id];
|
||||
UserPhotos *user_photos = add_user_photos(user_id);
|
||||
user_photos->count = total_count;
|
||||
CHECK(user_photos->getting_now);
|
||||
user_photos->getting_now = false;
|
||||
@ -12659,9 +12706,8 @@ void ContactsManager::add_profile_photo_to_cache(UserId user_id, Photo &&photo)
|
||||
LOG(INFO) << "Add profile photo " << photo.id.get() << " to cache";
|
||||
|
||||
// update photo list
|
||||
auto it = user_photos_.find(user_id);
|
||||
if (it != user_photos_.end() && it->second.count != -1) {
|
||||
auto user_photos = &it->second;
|
||||
auto user_photos = user_photos_.get_pointer(user_id);
|
||||
if (user_photos != nullptr && user_photos->count != -1) {
|
||||
if (user_photos->offset == 0) {
|
||||
if (user_photos->photos.empty() || user_photos->photos[0].id.get() != photo.id.get()) {
|
||||
user_photos->photos.insert(user_photos->photos.begin(), photo);
|
||||
@ -12704,9 +12750,8 @@ bool ContactsManager::delete_profile_photo_from_cache(UserId user_id, int64 prof
|
||||
bool is_main_photo_deleted = u != nullptr && u->photo.id == profile_photo_id;
|
||||
|
||||
// update photo list
|
||||
auto it = user_photos_.find(user_id);
|
||||
if (it != user_photos_.end() && it->second.count > 0) {
|
||||
auto user_photos = &it->second;
|
||||
auto user_photos = user_photos_.get_pointer(user_id);
|
||||
if (user_photos != nullptr && user_photos->count > 0) {
|
||||
auto old_size = user_photos->photos.size();
|
||||
if (td::remove_if(user_photos->photos,
|
||||
[profile_photo_id](const auto &photo) { return photo.id.get() == profile_photo_id; })) {
|
||||
@ -12726,7 +12771,7 @@ bool ContactsManager::delete_profile_photo_from_cache(UserId user_id, int64 prof
|
||||
}
|
||||
}
|
||||
bool have_new_photo =
|
||||
it != user_photos_.end() && it->second.count != -1 && it->second.offset == 0 && !it->second.photos.empty();
|
||||
user_photos != nullptr && user_photos->count != -1 && user_photos->offset == 0 && !user_photos->photos.empty();
|
||||
|
||||
auto user_full = get_user_full_force(user_id);
|
||||
if (user_full != nullptr && user_full->photo.id.get() == profile_photo_id) {
|
||||
@ -12739,11 +12784,11 @@ bool ContactsManager::delete_profile_photo_from_cache(UserId user_id, int64 prof
|
||||
if (is_main_photo_deleted) {
|
||||
if (have_new_photo) {
|
||||
do_update_user_photo(u, user_id,
|
||||
as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, it->second.photos[0]),
|
||||
as_profile_photo(td_->file_manager_.get(), user_id, u->access_hash, user_photos->photos[0]),
|
||||
false, "delete_profile_photo_from_cache");
|
||||
} else {
|
||||
do_update_user_photo(u, user_id, ProfilePhoto(), false, "delete_profile_photo_from_cache 2");
|
||||
need_reget_user = it == user_photos_.end() || it->second.count != 0;
|
||||
need_reget_user = user_photos == nullptr || user_photos->count != 0;
|
||||
}
|
||||
if (send_updates) {
|
||||
update_user(u, user_id);
|
||||
@ -12752,8 +12797,8 @@ bool ContactsManager::delete_profile_photo_from_cache(UserId user_id, int64 prof
|
||||
// update Photo in UserFull
|
||||
if (user_full != nullptr) {
|
||||
if (have_new_photo) {
|
||||
if (it->second.photos[0] != user_full->photo) {
|
||||
user_full->photo = it->second.photos[0];
|
||||
if (user_photos->photos[0] != user_full->photo) {
|
||||
user_full->photo = user_photos->photos[0];
|
||||
user_full->is_changed = true;
|
||||
}
|
||||
} else {
|
||||
@ -12780,9 +12825,8 @@ bool ContactsManager::delete_profile_photo_from_cache(UserId user_id, int64 prof
|
||||
|
||||
void ContactsManager::drop_user_photos(UserId user_id, bool is_empty, bool drop_user_full_photo, const char *source) {
|
||||
LOG(INFO) << "Drop user photos to " << (is_empty ? "empty" : "unknown") << " from " << source;
|
||||
auto it = user_photos_.find(user_id);
|
||||
if (it != user_photos_.end()) {
|
||||
auto user_photos = &it->second;
|
||||
auto user_photos = user_photos_.get_pointer(user_id);
|
||||
if (user_photos != nullptr) {
|
||||
int32 new_count = is_empty ? 0 : -1;
|
||||
if (user_photos->count == new_count) {
|
||||
CHECK(user_photos->photos.empty());
|
||||
@ -13059,7 +13103,7 @@ tl_object_ptr<td_api::chatMember> ContactsManager::get_chat_member_object(
|
||||
dialog_participant.joined_date_, dialog_participant.status_.get_chat_member_status_object());
|
||||
}
|
||||
|
||||
bool ContactsManager::on_get_channel_error(ChannelId channel_id, const Status &status, const string &source) {
|
||||
bool ContactsManager::on_get_channel_error(ChannelId channel_id, const Status &status, const char *source) {
|
||||
LOG(INFO) << "Receive " << status << " in " << channel_id << " from " << source;
|
||||
if (status.message() == CSlice("BOT_METHOD_INVALID")) {
|
||||
LOG(ERROR) << "Receive BOT_METHOD_INVALID from " << source;
|
||||
@ -13076,7 +13120,8 @@ bool ContactsManager::on_get_channel_error(ChannelId channel_id, const Status &s
|
||||
|
||||
auto c = get_channel(channel_id);
|
||||
if (c == nullptr) {
|
||||
if (source == "GetChannelDifferenceQuery" || (td_->auth_manager_->is_bot() && source == "GetChannelsQuery")) {
|
||||
if (Slice(source) == Slice("GetChannelDifferenceQuery") ||
|
||||
(td_->auth_manager_->is_bot() && Slice(source) == Slice("GetChannelsQuery"))) {
|
||||
// get channel difference after restart
|
||||
// get channel from server by its identifier
|
||||
return true;
|
||||
@ -13112,7 +13157,7 @@ bool ContactsManager::on_get_channel_error(ChannelId channel_id, const Status &s
|
||||
|
||||
remove_dialog_access_by_invite_link(DialogId(channel_id));
|
||||
}
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled, source);
|
||||
LOG_IF(ERROR, have_input_peer_channel(c, channel_id, AccessRights::Read))
|
||||
<< "Have read access to channel after receiving CHANNEL_PRIVATE. Channel state: "
|
||||
<< oneline(to_string(get_supergroup_object(channel_id, c)))
|
||||
@ -13411,6 +13456,9 @@ void ContactsManager::speculative_add_channel_participants(ChannelId channel_id,
|
||||
update_channel_online_member_count(channel_id, false);
|
||||
}
|
||||
if (channel_full != nullptr) {
|
||||
if (channel_full->is_changed) {
|
||||
channel_full->speculative_version++;
|
||||
}
|
||||
update_channel_full(channel_full, channel_id, "speculative_add_channel_participants");
|
||||
}
|
||||
if (delta_participant_count == 0) {
|
||||
@ -13455,7 +13503,7 @@ void ContactsManager::speculative_add_channel_participant_count(ChannelId channe
|
||||
bool by_me) {
|
||||
if (by_me) {
|
||||
// Currently ignore all changes made by the current user, because they may be already counted
|
||||
invalidate_channel_full(channel_id, false); // just in case
|
||||
invalidate_channel_full(channel_id, false, "speculative_add_channel_participant_count"); // just in case
|
||||
return;
|
||||
}
|
||||
|
||||
@ -13491,6 +13539,8 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId
|
||||
// must copy the initial c->participant_count before it is speculatibely updated
|
||||
auto channel_full = get_channel_full_force(channel_id, true, "speculative_add_channel_user");
|
||||
int32 min_count = 0;
|
||||
LOG(INFO) << "Speculatively change status of " << user_id << " in " << channel_id << " from " << old_status << " to "
|
||||
<< new_status;
|
||||
if (channel_full != nullptr) {
|
||||
channel_full->is_changed |= speculative_add_count(channel_full->administrator_count,
|
||||
new_status.is_administrator() - old_status.is_administrator());
|
||||
@ -13599,12 +13649,13 @@ void ContactsManager::speculative_add_channel_user(ChannelId channel_id, UserId
|
||||
update_channel_full(channel_full, channel_id, "speculative_add_channel_user");
|
||||
}
|
||||
|
||||
void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay) {
|
||||
LOG(INFO) << "Invalidate supergroup full for " << channel_id;
|
||||
void ContactsManager::invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay,
|
||||
const char *source) {
|
||||
LOG(INFO) << "Invalidate supergroup full for " << channel_id << " from " << source;
|
||||
auto channel_full = get_channel_full(channel_id, true, "invalidate_channel_full"); // must not load ChannelFull
|
||||
if (channel_full != nullptr) {
|
||||
do_invalidate_channel_full(channel_full, channel_id, need_drop_slow_mode_delay);
|
||||
update_channel_full(channel_full, channel_id, "invalidate_channel_full");
|
||||
update_channel_full(channel_full, channel_id, source);
|
||||
} else if (channel_id.is_valid()) {
|
||||
invalidated_channels_full_.insert(channel_id);
|
||||
}
|
||||
@ -14649,7 +14700,7 @@ void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id
|
||||
update_channel_full(channel_full, channel_id, "on_channel_status_changed");
|
||||
}
|
||||
} else {
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled, "on_channel_status_changed");
|
||||
}
|
||||
|
||||
if (old_status.is_creator() != new_status.is_creator()) {
|
||||
@ -14755,7 +14806,7 @@ void ContactsManager::on_channel_usernames_changed(const Channel *c, ChannelId c
|
||||
bool have_channel_full = get_channel_full(channel_id) != nullptr;
|
||||
if (!old_usernames.has_first_username() || !new_usernames.has_first_username()) {
|
||||
// moving channel from private to public can change availability of chat members
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled, "on_channel_usernames_changed");
|
||||
}
|
||||
|
||||
// must not load ChannelFull, because must not change the Channel
|
||||
@ -15364,7 +15415,7 @@ std::pair<int32, vector<const Photo *>> ContactsManager::get_user_profile_photos
|
||||
|
||||
apply_pending_user_photo(get_user(user_id), user_id);
|
||||
|
||||
auto user_photos = &user_photos_[user_id];
|
||||
auto user_photos = add_user_photos(user_id);
|
||||
if (user_photos->getting_now) {
|
||||
promise.set_error(Status::Error(400, "Request for new profile photos has already been sent"));
|
||||
return result;
|
||||
@ -17030,7 +17081,7 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
|
||||
c->is_forum = is_forum;
|
||||
|
||||
c->is_changed = true;
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled, "on_min_channel");
|
||||
}
|
||||
if (c->join_to_send != join_to_send || c->join_request != join_request) {
|
||||
c->join_to_send = join_to_send;
|
||||
@ -17152,7 +17203,7 @@ void ContactsManager::on_chat_update(telegram_api::channel &channel, const char
|
||||
}
|
||||
|
||||
if (need_invalidate_channel_full) {
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled, "on_chat_update");
|
||||
}
|
||||
|
||||
bool has_active_group_call = (channel.flags_ & CHANNEL_FLAG_HAS_ACTIVE_GROUP_CALL) != 0;
|
||||
@ -17266,16 +17317,16 @@ void ContactsManager::on_chat_update(telegram_api::channelForbidden &channel, co
|
||||
update_channel(c, channel_id);
|
||||
|
||||
if (need_drop_participant_count) {
|
||||
auto channel_full = get_channel_full(channel_id, true, "on_chat_update");
|
||||
auto channel_full = get_channel_full(channel_id, true, "on_channel_forbidden");
|
||||
if (channel_full != nullptr && channel_full->participant_count != 0) {
|
||||
channel_full->participant_count = 0;
|
||||
channel_full->administrator_count = 0;
|
||||
channel_full->is_changed = true;
|
||||
update_channel_full(channel_full, channel_id, "on_chat_update 2");
|
||||
update_channel_full(channel_full, channel_id, "on_channel_forbidden 2");
|
||||
}
|
||||
}
|
||||
if (need_invalidate_channel_full) {
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled);
|
||||
invalidate_channel_full(channel_id, !c->is_slow_mode_enabled, "on_channel_forbidden 3");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/FlatHashSet.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/Hints.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Status.h"
|
||||
@ -240,9 +241,9 @@ class ContactsManager final : public Actor {
|
||||
|
||||
void speculative_delete_channel_participant(ChannelId channel_id, UserId deleted_user_id, bool by_me);
|
||||
|
||||
void invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay);
|
||||
void invalidate_channel_full(ChannelId channel_id, bool need_drop_slow_mode_delay, const char *source);
|
||||
|
||||
bool on_get_channel_error(ChannelId channel_id, const Status &status, const string &source);
|
||||
bool on_get_channel_error(ChannelId channel_id, const Status &status, const char *source);
|
||||
|
||||
void on_get_permanent_dialog_invite_link(DialogId dialog_id, const DialogInviteLink &invite_link);
|
||||
|
||||
@ -1331,6 +1332,7 @@ class ContactsManager final : public Actor {
|
||||
void on_update_user_full_need_phone_number_privacy_exception(UserFull *user_full, UserId user_id,
|
||||
bool need_phone_number_privacy_exception) const;
|
||||
|
||||
UserPhotos *add_user_photos(UserId user_id);
|
||||
void add_profile_photo_to_cache(UserId user_id, Photo &&photo);
|
||||
bool delete_profile_photo_from_cache(UserId user_id, int64 profile_photo_id, bool send_updates);
|
||||
void drop_user_photos(UserId user_id, bool is_empty, bool drop_user_full_photo, const char *source);
|
||||
@ -1697,14 +1699,14 @@ class ContactsManager final : public Actor {
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void set_channel_participant_status_impl(ChannelId channel_id, DialogId participant_dialog_id,
|
||||
DialogParticipantStatus status, DialogParticipantStatus old_status,
|
||||
DialogParticipantStatus new_status, DialogParticipantStatus old_status,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void promote_channel_participant(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &status,
|
||||
void promote_channel_participant(ChannelId channel_id, UserId user_id, const DialogParticipantStatus &new_status,
|
||||
const DialogParticipantStatus &old_status, Promise<Unit> &&promise);
|
||||
|
||||
void restrict_channel_participant(ChannelId channel_id, DialogId participant_dialog_id,
|
||||
DialogParticipantStatus &&status, DialogParticipantStatus &&old_status,
|
||||
DialogParticipantStatus &&new_status, DialogParticipantStatus &&old_status,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void transfer_channel_ownership(ChannelId channel_id, UserId user_id,
|
||||
@ -1768,12 +1770,12 @@ class ContactsManager final : public Actor {
|
||||
|
||||
WaitFreeHashMap<UserId, unique_ptr<User>, UserIdHash> users_;
|
||||
WaitFreeHashMap<UserId, unique_ptr<UserFull>, UserIdHash> users_full_;
|
||||
FlatHashMap<UserId, UserPhotos, UserIdHash> user_photos_;
|
||||
WaitFreeHashMap<UserId, unique_ptr<UserPhotos>, UserIdHash> user_photos_;
|
||||
mutable FlatHashSet<UserId, UserIdHash> unknown_users_;
|
||||
FlatHashMap<UserId, tl_object_ptr<telegram_api::UserProfilePhoto>, UserIdHash> pending_user_photos_;
|
||||
WaitFreeHashMap<UserId, tl_object_ptr<telegram_api::UserProfilePhoto>, UserIdHash> pending_user_photos_;
|
||||
struct UserIdPhotoIdHash {
|
||||
std::size_t operator()(const std::pair<UserId, int64> &pair) const {
|
||||
return UserIdHash()(pair.first) * 2023654985u + std::hash<int64>()(pair.second);
|
||||
uint32 operator()(const std::pair<UserId, int64> &pair) const {
|
||||
return UserIdHash()(pair.first) * 2023654985u + Hash<int64>()(pair.second);
|
||||
}
|
||||
};
|
||||
WaitFreeHashMap<std::pair<UserId, int64>, FileSourceId, UserIdPhotoIdHash> user_profile_photo_file_source_ids_;
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -53,8 +53,8 @@ class CustomEmojiId {
|
||||
};
|
||||
|
||||
struct CustomEmojiIdHash {
|
||||
std::size_t operator()(CustomEmojiId custom_emoji_id) const {
|
||||
return std::hash<int64>()(custom_emoji_id.get());
|
||||
uint32 operator()(CustomEmojiId custom_emoji_id) const {
|
||||
return Hash<int64>()(custom_emoji_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -10,9 +10,10 @@
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/ServerMessageId.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
||||
namespace td {
|
||||
@ -60,8 +61,8 @@ const DialogDate MAX_DIALOG_DATE(0, DialogId());
|
||||
const int64 DEFAULT_ORDER = -1;
|
||||
|
||||
struct DialogDateHash {
|
||||
std::size_t operator()(const DialogDate &dialog_date) const {
|
||||
return std::hash<int64>()(dialog_date.get_order()) * 2023654985u + DialogIdHash()(dialog_date.get_dialog_id());
|
||||
uint32 operator()(const DialogDate &dialog_date) const {
|
||||
return Hash<int64>()(dialog_date.get_order()) * 2023654985u + DialogIdHash()(dialog_date.get_dialog_id());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -377,6 +377,10 @@ class DialogDbAsync final : public DialogDbAsyncInterface {
|
||||
send_closure_later(impl_, &Impl::close, std::move(promise));
|
||||
}
|
||||
|
||||
void force_flush() final {
|
||||
send_closure_later(impl_, &Impl::force_flush);
|
||||
}
|
||||
|
||||
private:
|
||||
class Impl final : public Actor {
|
||||
public:
|
||||
@ -432,6 +436,11 @@ class DialogDbAsync final : public DialogDbAsyncInterface {
|
||||
stop();
|
||||
}
|
||||
|
||||
void force_flush() {
|
||||
do_flush();
|
||||
LOG(INFO) << "DialogDb flushed";
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<DialogDbSyncSafeInterface> sync_db_safe_;
|
||||
DialogDbSyncInterface *sync_db_ = nullptr;
|
||||
@ -467,15 +476,9 @@ class DialogDbAsync final : public DialogDbAsyncInterface {
|
||||
return;
|
||||
}
|
||||
sync_db_->begin_write_transaction().ensure();
|
||||
for (auto &query : pending_writes_) {
|
||||
query.set_value(Unit());
|
||||
}
|
||||
set_promises(pending_writes_);
|
||||
sync_db_->commit_transaction().ensure();
|
||||
pending_writes_.clear();
|
||||
for (auto &promise : finished_writes_) {
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
finished_writes_.clear();
|
||||
set_promises(finished_writes_);
|
||||
cancel_timeout();
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,8 @@ class DialogDbAsyncInterface {
|
||||
virtual void get_secret_chat_count(FolderId folder_id, Promise<int32> promise) = 0;
|
||||
|
||||
virtual void close(Promise<Unit> promise) = 0;
|
||||
|
||||
virtual void force_flush() = 0;
|
||||
};
|
||||
|
||||
Status init_dialog_db(SqliteDb &db, int version, KeyValueSyncInterface &binlog_pmc,
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -61,8 +61,8 @@ class DialogFilterId {
|
||||
};
|
||||
|
||||
struct DialogFilterIdHash {
|
||||
std::size_t operator()(DialogFilterId dialog_filter_id) const {
|
||||
return std::hash<int32>()(dialog_filter_id.get());
|
||||
uint32 operator()(DialogFilterId dialog_filter_id) const {
|
||||
return Hash<int32>()(dialog_filter_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -13,9 +13,9 @@
|
||||
#include "td/telegram/UserId.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -78,8 +78,8 @@ class DialogId {
|
||||
};
|
||||
|
||||
struct DialogIdHash {
|
||||
std::size_t operator()(DialogId dialog_id) const {
|
||||
return std::hash<int64>()(dialog_id.get());
|
||||
uint32 operator()(DialogId dialog_id) const {
|
||||
return Hash<int64>()(dialog_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,9 +11,9 @@
|
||||
#include "td/telegram/td_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
@ -113,8 +113,8 @@ class DialogListId {
|
||||
};
|
||||
|
||||
struct DialogListIdHash {
|
||||
std::size_t operator()(DialogListId dialog_list_id) const {
|
||||
return std::hash<int64>()(dialog_list_id.get());
|
||||
uint32 operator()(DialogListId dialog_list_id) const {
|
||||
return Hash<int64>()(dialog_list_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -705,7 +705,7 @@ FileId DocumentsManager::dup_document(FileId new_id, FileId old_id) {
|
||||
CHECK(new_document == nullptr);
|
||||
new_document = make_unique<GeneralDocument>(*old_document);
|
||||
new_document->file_id = new_id;
|
||||
new_document->thumbnail.file_id = td_->file_manager_->dup_file_id(new_document->thumbnail.file_id);
|
||||
new_document->thumbnail.file_id = td_->file_manager_->dup_file_id(new_document->thumbnail.file_id, "dup_document");
|
||||
return new_id;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ void DownloadManagerCallback::delete_file(FileId file_id) {
|
||||
}
|
||||
|
||||
FileId DownloadManagerCallback::dup_file_id(FileId file_id) {
|
||||
return td_->file_manager_->dup_file_id(file_id);
|
||||
return td_->file_manager_->dup_file_id(file_id, "DownloadManagerCallback");
|
||||
}
|
||||
|
||||
void DownloadManagerCallback::get_file_search_text(FileId file_id, FileSourceId file_source_id,
|
||||
|
@ -37,7 +37,7 @@ FileReferenceManager::FileReferenceManager(ActorShared<> parent) : parent_(std::
|
||||
}
|
||||
|
||||
FileReferenceManager::~FileReferenceManager() {
|
||||
Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), file_sources_);
|
||||
Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), file_sources_, nodes_);
|
||||
}
|
||||
|
||||
void FileReferenceManager::tear_down() {
|
||||
@ -155,16 +155,26 @@ FileSourceId FileReferenceManager::create_attach_menu_bot_file_source(UserId use
|
||||
return add_file_source_id(source, PSLICE() << "attachment menu bot " << user_id);
|
||||
}
|
||||
|
||||
bool FileReferenceManager::add_file_source(NodeId node_id, FileSourceId file_source_id) {
|
||||
FileReferenceManager::Node &FileReferenceManager::add_node(NodeId node_id) {
|
||||
CHECK(node_id.is_valid());
|
||||
bool is_added = nodes_[node_id].file_source_ids.add(file_source_id);
|
||||
auto &node = nodes_[node_id];
|
||||
if (node == nullptr) {
|
||||
node = make_unique<Node>();
|
||||
}
|
||||
return *node;
|
||||
}
|
||||
|
||||
bool FileReferenceManager::add_file_source(NodeId node_id, FileSourceId file_source_id) {
|
||||
auto &node = add_node(node_id);
|
||||
bool is_added = node.file_source_ids.add(file_source_id);
|
||||
VLOG(file_references) << "Add " << (is_added ? "new" : "old") << ' ' << file_source_id << " for file " << node_id;
|
||||
return is_added;
|
||||
}
|
||||
|
||||
bool FileReferenceManager::remove_file_source(NodeId node_id, FileSourceId file_source_id) {
|
||||
CHECK(node_id.is_valid());
|
||||
bool is_removed = nodes_[node_id].file_source_ids.remove(file_source_id);
|
||||
auto *node = nodes_.get_pointer(node_id);
|
||||
bool is_removed = node != nullptr && node->file_source_ids.remove(file_source_id);
|
||||
if (is_removed) {
|
||||
VLOG(file_references) << "Remove " << file_source_id << " from file " << node_id;
|
||||
} else {
|
||||
@ -174,11 +184,11 @@ bool FileReferenceManager::remove_file_source(NodeId node_id, FileSourceId file_
|
||||
}
|
||||
|
||||
vector<FileSourceId> FileReferenceManager::get_some_file_sources(NodeId node_id) {
|
||||
auto it = nodes_.find(node_id);
|
||||
if (it == nodes_.end()) {
|
||||
auto *node = nodes_.get_pointer(node_id);
|
||||
if (node == nullptr) {
|
||||
return {};
|
||||
}
|
||||
return it->second.file_source_ids.get_some_elements();
|
||||
return node->file_source_ids.get_some_elements();
|
||||
}
|
||||
|
||||
vector<FullMessageId> FileReferenceManager::get_some_message_file_sources(NodeId node_id) {
|
||||
@ -197,14 +207,13 @@ vector<FullMessageId> FileReferenceManager::get_some_message_file_sources(NodeId
|
||||
}
|
||||
|
||||
void FileReferenceManager::merge(NodeId to_node_id, NodeId from_node_id) {
|
||||
auto from_it = nodes_.find(from_node_id);
|
||||
if (from_it == nodes_.end()) {
|
||||
auto *from_node_ptr = nodes_.get_pointer(from_node_id);
|
||||
if (from_node_ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto &from = *from_node_ptr;
|
||||
|
||||
CHECK(to_node_id.is_valid());
|
||||
auto &to = nodes_[to_node_id];
|
||||
auto &from = from_it->second;
|
||||
auto &to = add_node(to_node_id);
|
||||
VLOG(file_references) << "Merge " << to.file_source_ids.size() << " and " << from.file_source_ids.size()
|
||||
<< " sources of files " << to_node_id << " and " << from_node_id;
|
||||
CHECK(!to.query || to.query->proxy.is_empty());
|
||||
@ -227,7 +236,11 @@ void FileReferenceManager::merge(NodeId to_node_id, NodeId from_node_id) {
|
||||
|
||||
void FileReferenceManager::run_node(NodeId node_id) {
|
||||
CHECK(node_id.is_valid());
|
||||
Node &node = nodes_[node_id];
|
||||
auto *node_ptr = nodes_.get_pointer(node_id);
|
||||
if (node_ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
Node &node = *node_ptr;
|
||||
if (!node.query) {
|
||||
return;
|
||||
}
|
||||
@ -266,8 +279,7 @@ void FileReferenceManager::run_node(NodeId node_id) {
|
||||
void FileReferenceManager::send_query(Destination dest, FileSourceId file_source_id) {
|
||||
VLOG(file_references) << "Send file reference repair query for file " << dest.node_id << " with generation "
|
||||
<< dest.generation << " from " << file_source_id;
|
||||
CHECK(dest.node_id.is_valid());
|
||||
auto &node = nodes_[dest.node_id];
|
||||
auto &node = add_node(dest.node_id);
|
||||
node.query->active_queries++;
|
||||
|
||||
auto promise = PromiseCreator::lambda([dest, file_source_id, actor_id = actor_id(this),
|
||||
@ -361,8 +373,7 @@ FileReferenceManager::Destination FileReferenceManager::on_query_result(Destinat
|
||||
VLOG(file_references) << "Receive result of file reference repair query for file " << dest.node_id
|
||||
<< " with generation " << dest.generation << " from " << file_source_id << ": " << status << " "
|
||||
<< sub;
|
||||
CHECK(dest.node_id.is_valid());
|
||||
auto &node = nodes_[dest.node_id];
|
||||
auto &node = add_node(dest.node_id);
|
||||
|
||||
auto query = node.query.get();
|
||||
if (!query) {
|
||||
@ -399,8 +410,7 @@ void FileReferenceManager::repair_file_reference(NodeId node_id, Promise<> promi
|
||||
auto main_file_id = G()->td().get_actor_unsafe()->file_manager_->get_file_view(node_id).get_main_file_id();
|
||||
VLOG(file_references) << "Repair file reference for file " << node_id << "/" << main_file_id;
|
||||
node_id = main_file_id;
|
||||
CHECK(node_id.is_valid());
|
||||
auto &node = nodes_[node_id];
|
||||
auto &node = add_node(node_id);
|
||||
if (!node.query) {
|
||||
node.query = make_unique<Query>();
|
||||
node.query->generation = ++query_generation_;
|
||||
|
@ -20,12 +20,12 @@
|
||||
#include "td/actor/actor.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/Variant.h"
|
||||
#include "td/utils/WaitFreeHashMap.h"
|
||||
#include "td/utils/WaitFreeVector.h"
|
||||
|
||||
namespace td {
|
||||
@ -177,10 +177,12 @@ class FileReferenceManager final : public Actor {
|
||||
|
||||
int64 query_generation_{0};
|
||||
|
||||
FlatHashMap<NodeId, Node, FileIdHash> nodes_;
|
||||
WaitFreeHashMap<NodeId, unique_ptr<Node>, FileIdHash> nodes_;
|
||||
|
||||
ActorShared<> parent_;
|
||||
|
||||
Node &add_node(NodeId node_id);
|
||||
|
||||
void run_node(NodeId node);
|
||||
void send_query(Destination dest, FileSourceId file_source_id);
|
||||
Destination on_query_result(Destination dest, FileSourceId file_source_id, Status status, int32 sub = 0);
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -56,8 +56,8 @@ class FolderId {
|
||||
};
|
||||
|
||||
struct FolderIdHash {
|
||||
std::size_t operator()(FolderId folder_id) const {
|
||||
return std::hash<int32>()(folder_id.get());
|
||||
uint32 operator()(FolderId folder_id) const {
|
||||
return Hash<int32>()(folder_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -30,10 +30,6 @@ class ForumTopicEditedData {
|
||||
public:
|
||||
ForumTopicEditedData() = default;
|
||||
|
||||
bool is_empty() const {
|
||||
return title_.empty() && !edit_icon_custom_emoji_id_ && !edit_is_closed_;
|
||||
}
|
||||
|
||||
ForumTopicEditedData(string &&title, bool edit_icon_custom_emoji_id, int64 icon_custom_emoji_id, bool edit_is_closed,
|
||||
bool is_closed)
|
||||
: title_(std::move(title))
|
||||
@ -43,6 +39,14 @@ class ForumTopicEditedData {
|
||||
, is_closed_(is_closed) {
|
||||
}
|
||||
|
||||
bool is_empty() const {
|
||||
return title_.empty() && !edit_icon_custom_emoji_id_ && !edit_is_closed_;
|
||||
}
|
||||
|
||||
const string &get_title() const {
|
||||
return title_;
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::MessageContent> get_message_content_object() const;
|
||||
|
||||
template <class StorerT>
|
||||
|
@ -55,7 +55,7 @@ struct FullMessageId {
|
||||
};
|
||||
|
||||
struct FullMessageIdHash {
|
||||
std::size_t operator()(FullMessageId full_message_id) const {
|
||||
uint32 operator()(FullMessageId full_message_id) const {
|
||||
return DialogIdHash()(full_message_id.get_dialog_id()) * 2023654985u +
|
||||
MessageIdHash()(full_message_id.get_message_id());
|
||||
}
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -41,8 +41,8 @@ class GroupCallId {
|
||||
};
|
||||
|
||||
struct GroupCallIdHash {
|
||||
std::size_t operator()(GroupCallId group_call_id) const {
|
||||
return std::hash<int32>()(group_call_id.get());
|
||||
uint32 operator()(GroupCallId group_call_id) const {
|
||||
return Hash<int32>()(group_call_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -12,12 +12,11 @@
|
||||
|
||||
#include "td/db/SqliteKeyValueAsync.h"
|
||||
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
#include "td/utils/utf8.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace td {
|
||||
|
||||
HashtagHints::HashtagHints(string mode, ActorShared<> parent) : mode_(std::move(mode)), parent_(std::move(parent)) {
|
||||
@ -49,7 +48,7 @@ void HashtagHints::remove_hashtag(string hashtag, Promise<> promise) {
|
||||
if (hashtag[0] == '#') {
|
||||
hashtag = hashtag.substr(1);
|
||||
}
|
||||
auto key = std::hash<std::string>()(hashtag);
|
||||
auto key = Hash<string>()(hashtag);
|
||||
if (hints_.has_key(key)) {
|
||||
hints_.remove(key);
|
||||
G()->td_db()->get_sqlite_pmc()->set(get_key(), serialize(keys_to_strings(hints_.search_empty(101).second)),
|
||||
@ -80,8 +79,7 @@ void HashtagHints::hashtag_used_impl(const string &hashtag) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: may be it should be optimized a little
|
||||
auto key = std::hash<std::string>()(hashtag);
|
||||
auto key = Hash<string>()(hashtag);
|
||||
hints_.add(key, hashtag);
|
||||
hints_.set_rating(key, -++counter_);
|
||||
}
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/base64.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/HttpUrl.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
@ -58,7 +59,6 @@
|
||||
#include "td/utils/tl_parsers.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
namespace td {
|
||||
|
||||
@ -982,10 +982,10 @@ uint64 InlineQueriesManager::send_inline_query(UserId bot_user_id, DialogId dial
|
||||
}
|
||||
}();
|
||||
|
||||
uint64 query_hash = std::hash<std::string>()(trim(query));
|
||||
uint64 query_hash = Hash<string>()(trim(query));
|
||||
query_hash = query_hash * 2023654985u + bot_user_id.get();
|
||||
query_hash = query_hash * 2023654985u + static_cast<uint64>(peer_type);
|
||||
query_hash = query_hash * 2023654985u + std::hash<std::string>()(offset);
|
||||
query_hash = query_hash * 2023654985u + Hash<string>()(offset);
|
||||
if (r_bot_data.ok().need_location) {
|
||||
query_hash = query_hash * 2023654985u + static_cast<uint64>(user_location.get_latitude() * 1e4);
|
||||
query_hash = query_hash * 2023654985u + static_cast<uint64>(user_location.get_longitude() * 1e4);
|
||||
|
@ -9,10 +9,9 @@
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace td {
|
||||
|
||||
class InputGroupCallId {
|
||||
@ -43,8 +42,8 @@ class InputGroupCallId {
|
||||
return group_call_id != 0;
|
||||
}
|
||||
|
||||
std::size_t get_hash() const {
|
||||
return std::hash<int64>()(group_call_id);
|
||||
uint32 get_hash() const {
|
||||
return Hash<int64>()(group_call_id);
|
||||
}
|
||||
|
||||
tl_object_ptr<telegram_api::inputGroupCall> get_input_group_call() const;
|
||||
@ -65,7 +64,7 @@ class InputGroupCallId {
|
||||
};
|
||||
|
||||
struct InputGroupCallIdHash {
|
||||
std::size_t operator()(InputGroupCallId input_group_call_id) const {
|
||||
uint32 operator()(InputGroupCallId input_group_call_id) const {
|
||||
return input_group_call_id.get_hash();
|
||||
}
|
||||
};
|
||||
|
@ -1914,6 +1914,7 @@ void LanguagePackManager::hangup() {
|
||||
|
||||
int32 LanguagePackManager::manager_count_ = 0;
|
||||
std::mutex LanguagePackManager::language_database_mutex_;
|
||||
std::unordered_map<string, unique_ptr<LanguagePackManager::LanguageDatabase>> LanguagePackManager::language_databases_;
|
||||
std::unordered_map<string, unique_ptr<LanguagePackManager::LanguageDatabase>, Hash<string>>
|
||||
LanguagePackManager::language_databases_;
|
||||
|
||||
} // namespace td
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Container.h"
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
@ -105,7 +106,7 @@ class LanguagePackManager final : public NetQueryCallback {
|
||||
static int32 manager_count_;
|
||||
|
||||
static std::mutex language_database_mutex_;
|
||||
static std::unordered_map<string, unique_ptr<LanguageDatabase>> language_databases_;
|
||||
static std::unordered_map<string, unique_ptr<LanguageDatabase>, Hash<string>> language_databases_;
|
||||
|
||||
static LanguageDatabase *add_language_database(string path);
|
||||
|
||||
|
@ -4639,13 +4639,13 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
|
||||
auto fix_file_id = [dialog_id, to_secret, file_manager = td->file_manager_.get()](FileId file_id) {
|
||||
auto file_view = file_manager->get_file_view(file_id);
|
||||
if (to_secret && !file_view.is_encrypted_secret()) {
|
||||
auto download_file_id = file_manager->dup_file_id(file_id);
|
||||
auto download_file_id = file_manager->dup_file_id(file_id, "dup_message_content to secret");
|
||||
file_id = file_manager
|
||||
->register_generate(FileType::Encrypted, FileLocationSource::FromServer, file_view.suggested_path(),
|
||||
PSTRING() << "#file_id#" << download_file_id.get(), dialog_id, file_view.size())
|
||||
.ok();
|
||||
}
|
||||
return file_manager->dup_file_id(file_id);
|
||||
return file_manager->dup_file_id(file_id, "dup_message_content");
|
||||
};
|
||||
|
||||
FileId thumbnail_file_id;
|
||||
@ -4778,7 +4778,8 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
|
||||
|
||||
result->photo.photos.back().file_id = fix_file_id(result->photo.photos.back().file_id);
|
||||
if (has_thumbnail) {
|
||||
result->photo.photos[0].file_id = td->file_manager_->dup_file_id(result->photo.photos[0].file_id);
|
||||
result->photo.photos[0].file_id =
|
||||
td->file_manager_->dup_file_id(result->photo.photos[0].file_id, "dup_message_content photo");
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
@ -5788,6 +5789,14 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte
|
||||
const auto *poll = static_cast<const MessagePoll *>(content);
|
||||
return td->poll_manager_->get_poll_search_text(poll->poll_id);
|
||||
}
|
||||
case MessageContentType::TopicCreate: {
|
||||
const auto *topic_create = static_cast<const MessageTopicCreate *>(content);
|
||||
return topic_create->title;
|
||||
}
|
||||
case MessageContentType::TopicEdit: {
|
||||
const auto *topic_edit = static_cast<const MessageTopicEdit *>(content);
|
||||
return topic_edit->edited_data.get_title();
|
||||
}
|
||||
case MessageContentType::Contact:
|
||||
case MessageContentType::Game:
|
||||
case MessageContentType::LiveLocation:
|
||||
@ -5829,8 +5838,6 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte
|
||||
case MessageContentType::WebViewDataSent:
|
||||
case MessageContentType::WebViewDataReceived:
|
||||
case MessageContentType::GiftPremium:
|
||||
case MessageContentType::TopicCreate:
|
||||
case MessageContentType::TopicEdit:
|
||||
return string();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -7,10 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace td {
|
||||
|
||||
// increase MessageUnsupported::CURRENT_VERSION each time a new message content type is added
|
||||
@ -84,8 +83,8 @@ bool can_have_message_content_caption(MessageContentType content_type);
|
||||
uint64 get_message_content_chain_id(MessageContentType content_type);
|
||||
|
||||
struct MessageContentTypeHash {
|
||||
std::size_t operator()(MessageContentType content_type) const {
|
||||
return std::hash<int32>()(static_cast<int32>(content_type));
|
||||
uint32 operator()(MessageContentType content_type) const {
|
||||
return Hash<int32>()(static_cast<int32>(content_type));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/MessagesDb.h"
|
||||
#include "td/telegram/MessageDb.h"
|
||||
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/UserId.h"
|
||||
@ -38,11 +38,11 @@
|
||||
|
||||
namespace td {
|
||||
|
||||
static constexpr int32 MESSAGES_DB_INDEX_COUNT = 30;
|
||||
static constexpr int32 MESSAGES_DB_INDEX_COUNT_OLD = 9;
|
||||
static constexpr int32 MESSAGE_DB_INDEX_COUNT = 30;
|
||||
static constexpr int32 MESSAGE_DB_INDEX_COUNT_OLD = 9;
|
||||
|
||||
// NB: must happen inside a transaction
|
||||
Status init_messages_db(SqliteDb &db, int32 version) {
|
||||
Status init_message_db(SqliteDb &db, int32 version) {
|
||||
LOG(INFO) << "Init message database " << tag("version", version);
|
||||
|
||||
// Check if database exists
|
||||
@ -50,7 +50,7 @@ Status init_messages_db(SqliteDb &db, int32 version) {
|
||||
if (!has_table) {
|
||||
version = 0;
|
||||
} else if (version < static_cast<int32>(DbVersion::DialogDbCreated) || version > current_db_version()) {
|
||||
TRY_STATUS(drop_messages_db(db, version));
|
||||
TRY_STATUS(drop_message_db(db, version));
|
||||
version = 0;
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ Status init_messages_db(SqliteDb &db, int32 version) {
|
||||
db.exec("CREATE INDEX IF NOT EXISTS message_by_ttl ON messages "
|
||||
"(ttl_expires_at) WHERE ttl_expires_at IS NOT NULL"));
|
||||
|
||||
TRY_STATUS(add_media_indices(0, MESSAGES_DB_INDEX_COUNT));
|
||||
TRY_STATUS(add_media_indices(0, MESSAGE_DB_INDEX_COUNT));
|
||||
|
||||
TRY_STATUS(add_fts());
|
||||
|
||||
@ -142,14 +142,14 @@ Status init_messages_db(SqliteDb &db, int32 version) {
|
||||
|
||||
version = current_db_version();
|
||||
}
|
||||
if (version < static_cast<int32>(DbVersion::MessagesDbMediaIndex)) {
|
||||
if (version < static_cast<int32>(DbVersion::MessageDbMediaIndex)) {
|
||||
TRY_STATUS(db.exec("ALTER TABLE messages ADD COLUMN index_mask INT4"));
|
||||
TRY_STATUS(add_media_indices(0, MESSAGES_DB_INDEX_COUNT_OLD));
|
||||
TRY_STATUS(add_media_indices(0, MESSAGE_DB_INDEX_COUNT_OLD));
|
||||
}
|
||||
if (version < static_cast<int32>(DbVersion::MessagesDb30MediaIndex)) {
|
||||
TRY_STATUS(add_media_indices(MESSAGES_DB_INDEX_COUNT_OLD, MESSAGES_DB_INDEX_COUNT));
|
||||
if (version < static_cast<int32>(DbVersion::MessageDb30MediaIndex)) {
|
||||
TRY_STATUS(add_media_indices(MESSAGE_DB_INDEX_COUNT_OLD, MESSAGE_DB_INDEX_COUNT));
|
||||
}
|
||||
if (version < static_cast<int32>(DbVersion::MessagesDbFts)) {
|
||||
if (version < static_cast<int32>(DbVersion::MessageDbFts)) {
|
||||
TRY_STATUS(db.exec("ALTER TABLE messages ADD COLUMN search_id INT8"));
|
||||
TRY_STATUS(db.exec("ALTER TABLE messages ADD COLUMN text STRING"));
|
||||
TRY_STATUS(add_fts());
|
||||
@ -171,15 +171,15 @@ Status init_messages_db(SqliteDb &db, int32 version) {
|
||||
}
|
||||
|
||||
// NB: must happen inside a transaction
|
||||
Status drop_messages_db(SqliteDb &db, int32 version) {
|
||||
Status drop_message_db(SqliteDb &db, int32 version) {
|
||||
LOG(WARNING) << "Drop message database " << tag("version", version)
|
||||
<< tag("current_db_version", current_db_version());
|
||||
return db.exec("DROP TABLE IF EXISTS messages");
|
||||
}
|
||||
|
||||
class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
class MessageDbImpl final : public MessageDbSyncInterface {
|
||||
public:
|
||||
explicit MessagesDbImpl(SqliteDb db) : db_(std::move(db)) {
|
||||
explicit MessageDbImpl(SqliteDb db) : db_(std::move(db)) {
|
||||
init().ensure();
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
"IN (SELECT rowid FROM messages_fts WHERE messages_fts MATCH ?1 AND rowid < ?2 "
|
||||
"ORDER BY rowid DESC LIMIT ?3) ORDER BY search_id DESC"));
|
||||
|
||||
for (int32 i = 0; i < MESSAGES_DB_INDEX_COUNT; i++) {
|
||||
for (int32 i = 0; i < MESSAGE_DB_INDEX_COUNT; i++) {
|
||||
TRY_RESULT_ASSIGN(
|
||||
get_message_ids_stmts_[i],
|
||||
db_.get_statement(
|
||||
@ -341,7 +341,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
// add dialog_id to text
|
||||
text += PSTRING() << " \a" << dialog_id.get();
|
||||
if (index_mask != 0) {
|
||||
for (int i = 0; i < MESSAGES_DB_INDEX_COUNT; i++) {
|
||||
for (int i = 0; i < MESSAGE_DB_INDEX_COUNT; i++) {
|
||||
if ((index_mask & (1 << i))) {
|
||||
text += PSTRING() << " \a\a" << i;
|
||||
}
|
||||
@ -444,7 +444,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
delete_dialog_messages_by_sender_stmt_.step().ensure();
|
||||
}
|
||||
|
||||
Result<MessagesDbDialogMessage> get_message(FullMessageId full_message_id) final {
|
||||
Result<MessageDbDialogMessage> get_message(FullMessageId full_message_id) final {
|
||||
auto dialog_id = full_message_id.get_dialog_id();
|
||||
auto message_id = full_message_id.get_message_id();
|
||||
CHECK(dialog_id.is_valid());
|
||||
@ -477,10 +477,10 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
LOG_CHECK(received_message_id == message_id)
|
||||
<< received_message_id << ' ' << message_id << ' ' << get_message_info(received_message_id, data, true).first;
|
||||
}
|
||||
return MessagesDbDialogMessage{received_message_id, BufferSlice(data)};
|
||||
return MessageDbDialogMessage{received_message_id, BufferSlice(data)};
|
||||
}
|
||||
|
||||
Result<MessagesDbMessage> get_message_by_unique_message_id(ServerMessageId unique_message_id) final {
|
||||
Result<MessageDbMessage> get_message_by_unique_message_id(ServerMessageId unique_message_id) final {
|
||||
if (!unique_message_id.is_valid()) {
|
||||
return Status::Error("Invalid unique_message_id");
|
||||
}
|
||||
@ -494,10 +494,10 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
}
|
||||
DialogId dialog_id(get_message_by_unique_message_id_stmt_.view_int64(0));
|
||||
MessageId message_id(get_message_by_unique_message_id_stmt_.view_int64(1));
|
||||
return MessagesDbMessage{dialog_id, message_id, BufferSlice(get_message_by_unique_message_id_stmt_.view_blob(2))};
|
||||
return MessageDbMessage{dialog_id, message_id, BufferSlice(get_message_by_unique_message_id_stmt_.view_blob(2))};
|
||||
}
|
||||
|
||||
Result<MessagesDbDialogMessage> get_message_by_random_id(DialogId dialog_id, int64 random_id) final {
|
||||
Result<MessageDbDialogMessage> get_message_by_random_id(DialogId dialog_id, int64 random_id) final {
|
||||
SCOPE_EXIT {
|
||||
get_message_by_random_id_stmt_.reset();
|
||||
};
|
||||
@ -508,11 +508,11 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
return Status::Error("Not found");
|
||||
}
|
||||
MessageId message_id(get_message_by_random_id_stmt_.view_int64(0));
|
||||
return MessagesDbDialogMessage{message_id, BufferSlice(get_message_by_random_id_stmt_.view_blob(1))};
|
||||
return MessageDbDialogMessage{message_id, BufferSlice(get_message_by_random_id_stmt_.view_blob(1))};
|
||||
}
|
||||
|
||||
Result<MessagesDbDialogMessage> get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id,
|
||||
MessageId last_message_id, int32 date) final {
|
||||
Result<MessageDbDialogMessage> get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id,
|
||||
MessageId last_message_id, int32 date) final {
|
||||
int64 left_message_id = first_message_id.get();
|
||||
int64 right_message_id = last_message_id.get();
|
||||
LOG_CHECK(left_message_id <= right_message_id) << first_message_id << " " << last_message_id;
|
||||
@ -573,14 +573,14 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
return Status::Error("Not found");
|
||||
}
|
||||
|
||||
std::pair<vector<MessagesDbMessage>, int32> get_expiring_messages(int32 expires_from, int32 expires_till,
|
||||
int32 limit) final {
|
||||
std::pair<vector<MessageDbMessage>, int32> get_expiring_messages(int32 expires_from, int32 expires_till,
|
||||
int32 limit) final {
|
||||
SCOPE_EXIT {
|
||||
get_expiring_messages_stmt_.reset();
|
||||
get_expiring_messages_helper_stmt_.reset();
|
||||
};
|
||||
|
||||
vector<MessagesDbMessage> messages;
|
||||
vector<MessageDbMessage> messages;
|
||||
// load messages
|
||||
if (expires_from <= expires_till) {
|
||||
get_expiring_messages_stmt_.bind_int32(1, expires_from).ensure();
|
||||
@ -591,7 +591,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
DialogId dialog_id(get_expiring_messages_stmt_.view_int64(0));
|
||||
MessageId message_id(get_expiring_messages_stmt_.view_int64(1));
|
||||
BufferSlice data(get_expiring_messages_stmt_.view_blob(2));
|
||||
messages.push_back(MessagesDbMessage{dialog_id, message_id, std::move(data)});
|
||||
messages.push_back(MessageDbMessage{dialog_id, message_id, std::move(data)});
|
||||
get_expiring_messages_stmt_.step().ensure();
|
||||
}
|
||||
}
|
||||
@ -609,7 +609,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
return std::make_pair(std::move(messages), next_expires_till);
|
||||
}
|
||||
|
||||
MessagesDbCalendar get_dialog_message_calendar(MessagesDbDialogCalendarQuery query) final {
|
||||
MessageDbCalendar get_dialog_message_calendar(MessageDbDialogCalendarQuery query) final {
|
||||
auto &stmt = get_messages_from_index_stmts_[message_search_filter_index(query.filter)].desc_stmt_;
|
||||
SCOPE_EXIT {
|
||||
stmt.reset();
|
||||
@ -619,7 +619,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
stmt.bind_int64(2, query.from_message_id.get()).ensure();
|
||||
stmt.bind_int32(3, limit).ensure();
|
||||
|
||||
vector<MessagesDbDialogMessage> messages;
|
||||
vector<MessageDbDialogMessage> messages;
|
||||
vector<int32> total_counts;
|
||||
stmt.step().ensure();
|
||||
int32 current_day = std::numeric_limits<int32>::max();
|
||||
@ -633,16 +633,16 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
total_counts.back()++;
|
||||
} else {
|
||||
current_day = day;
|
||||
messages.push_back(MessagesDbDialogMessage{message_id, BufferSlice(data_slice)});
|
||||
messages.push_back(MessageDbDialogMessage{message_id, BufferSlice(data_slice)});
|
||||
total_counts.push_back(1);
|
||||
}
|
||||
stmt.step().ensure();
|
||||
}
|
||||
return MessagesDbCalendar{std::move(messages), std::move(total_counts)};
|
||||
return MessageDbCalendar{std::move(messages), std::move(total_counts)};
|
||||
}
|
||||
|
||||
Result<MessagesDbMessagePositions> get_dialog_sparse_message_positions(
|
||||
MessagesDbGetDialogSparseMessagePositionsQuery query) final {
|
||||
Result<MessageDbMessagePositions> get_dialog_sparse_message_positions(
|
||||
MessageDbGetDialogSparseMessagePositionsQuery query) final {
|
||||
auto &stmt = get_message_ids_stmts_[message_search_filter_index(query.filter)];
|
||||
SCOPE_EXIT {
|
||||
stmt.reset();
|
||||
@ -657,7 +657,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
stmt.step().ensure();
|
||||
}
|
||||
|
||||
MessagesDbMessagePositions positions;
|
||||
MessageDbMessagePositions positions;
|
||||
int32 limit = min(query.limit, static_cast<int32>(message_ids.size()));
|
||||
if (limit > 0) {
|
||||
double delta = static_cast<double>(message_ids.size()) / limit;
|
||||
@ -668,26 +668,26 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
auto message_id = message_ids[position];
|
||||
TRY_RESULT(message, get_message({query.dialog_id, message_id}));
|
||||
auto date = get_message_info(message).second;
|
||||
positions.positions.push_back(MessagesDbMessagePosition{position, date, message_id});
|
||||
positions.positions.push_back(MessageDbMessagePosition{position, date, message_id});
|
||||
}
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
vector<MessagesDbDialogMessage> get_messages(MessagesDbMessagesQuery query) final {
|
||||
vector<MessageDbDialogMessage> get_messages(MessageDbMessagesQuery query) final {
|
||||
if (query.filter != MessageSearchFilter::Empty) {
|
||||
return get_messages_from_index(query.dialog_id, query.from_message_id, query.filter, query.offset, query.limit);
|
||||
}
|
||||
return get_messages_impl(get_messages_stmt_, query.dialog_id, query.from_message_id, query.offset, query.limit);
|
||||
}
|
||||
|
||||
vector<MessagesDbDialogMessage> get_scheduled_messages(DialogId dialog_id, int32 limit) final {
|
||||
vector<MessageDbDialogMessage> get_scheduled_messages(DialogId dialog_id, int32 limit) final {
|
||||
return get_messages_inner(get_scheduled_messages_stmt_, dialog_id, std::numeric_limits<int64>::max(), limit);
|
||||
}
|
||||
|
||||
vector<MessagesDbDialogMessage> get_messages_from_notification_id(DialogId dialog_id,
|
||||
NotificationId from_notification_id,
|
||||
int32 limit) final {
|
||||
vector<MessageDbDialogMessage> get_messages_from_notification_id(DialogId dialog_id,
|
||||
NotificationId from_notification_id,
|
||||
int32 limit) final {
|
||||
auto &stmt = get_messages_from_notification_id_stmt_;
|
||||
SCOPE_EXIT {
|
||||
stmt.reset();
|
||||
@ -696,12 +696,12 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
stmt.bind_int32(2, from_notification_id.get()).ensure();
|
||||
stmt.bind_int32(3, limit).ensure();
|
||||
|
||||
vector<MessagesDbDialogMessage> result;
|
||||
vector<MessageDbDialogMessage> result;
|
||||
stmt.step().ensure();
|
||||
while (stmt.has_row()) {
|
||||
auto data_slice = stmt.view_blob(0);
|
||||
MessageId message_id(stmt.view_int64(1));
|
||||
result.push_back(MessagesDbDialogMessage{message_id, BufferSlice(data_slice)});
|
||||
result.push_back(MessageDbDialogMessage{message_id, BufferSlice(data_slice)});
|
||||
LOG(INFO) << "Load " << message_id << " in " << dialog_id << " from database";
|
||||
stmt.step().ensure();
|
||||
}
|
||||
@ -755,7 +755,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
return sb.as_cslice().str();
|
||||
}
|
||||
|
||||
MessagesDbFtsResult get_messages_fts(MessagesDbFtsQuery query) final {
|
||||
MessageDbFtsResult get_messages_fts(MessageDbFtsQuery query) final {
|
||||
SCOPE_EXIT {
|
||||
get_messages_fts_stmt_.reset();
|
||||
};
|
||||
@ -782,7 +782,7 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
}
|
||||
stmt.bind_int64(2, query.from_search_id).ensure();
|
||||
stmt.bind_int32(3, query.limit).ensure();
|
||||
MessagesDbFtsResult result;
|
||||
MessageDbFtsResult result;
|
||||
auto status = stmt.step();
|
||||
if (status.is_error()) {
|
||||
LOG(ERROR) << status;
|
||||
@ -794,19 +794,19 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
auto data_slice = stmt.view_blob(2);
|
||||
auto search_id = stmt.view_int64(3);
|
||||
result.next_search_id = search_id;
|
||||
result.messages.push_back(MessagesDbMessage{dialog_id, message_id, BufferSlice(data_slice)});
|
||||
result.messages.push_back(MessageDbMessage{dialog_id, message_id, BufferSlice(data_slice)});
|
||||
stmt.step().ensure();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<MessagesDbDialogMessage> get_messages_from_index(DialogId dialog_id, MessageId from_message_id,
|
||||
MessageSearchFilter filter, int32 offset, int32 limit) {
|
||||
vector<MessageDbDialogMessage> get_messages_from_index(DialogId dialog_id, MessageId from_message_id,
|
||||
MessageSearchFilter filter, int32 offset, int32 limit) {
|
||||
auto &stmt = get_messages_from_index_stmts_[message_search_filter_index(filter)];
|
||||
return get_messages_impl(stmt, dialog_id, from_message_id, offset, limit);
|
||||
}
|
||||
|
||||
MessagesDbCallsResult get_calls(MessagesDbCallsQuery query) final {
|
||||
MessageDbCallsResult get_calls(MessageDbCallsQuery query) final {
|
||||
int32 pos;
|
||||
if (query.filter == MessageSearchFilter::Call) {
|
||||
pos = 0;
|
||||
@ -824,13 +824,13 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
stmt.bind_int32(1, query.from_unique_message_id).ensure();
|
||||
stmt.bind_int32(2, query.limit).ensure();
|
||||
|
||||
MessagesDbCallsResult result;
|
||||
MessageDbCallsResult result;
|
||||
stmt.step().ensure();
|
||||
while (stmt.has_row()) {
|
||||
DialogId dialog_id(stmt.view_int64(0));
|
||||
MessageId message_id(stmt.view_int64(1));
|
||||
auto data_slice = stmt.view_blob(2);
|
||||
result.messages.push_back(MessagesDbMessage{dialog_id, message_id, BufferSlice(data_slice)});
|
||||
result.messages.push_back(MessageDbMessage{dialog_id, message_id, BufferSlice(data_slice)});
|
||||
stmt.step().ensure();
|
||||
}
|
||||
return result;
|
||||
@ -866,8 +866,8 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
SqliteStatement get_scheduled_messages_stmt_;
|
||||
SqliteStatement get_messages_from_notification_id_stmt_;
|
||||
|
||||
std::array<SqliteStatement, MESSAGES_DB_INDEX_COUNT> get_message_ids_stmts_;
|
||||
std::array<GetMessagesStmt, MESSAGES_DB_INDEX_COUNT> get_messages_from_index_stmts_;
|
||||
std::array<SqliteStatement, MESSAGE_DB_INDEX_COUNT> get_message_ids_stmts_;
|
||||
std::array<GetMessagesStmt, MESSAGE_DB_INDEX_COUNT> get_messages_from_index_stmts_;
|
||||
std::array<SqliteStatement, 2> get_calls_stmts_;
|
||||
|
||||
SqliteStatement get_messages_fts_stmt_;
|
||||
@ -878,8 +878,8 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
SqliteStatement delete_scheduled_message_stmt_;
|
||||
SqliteStatement delete_scheduled_server_message_stmt_;
|
||||
|
||||
static vector<MessagesDbDialogMessage> get_messages_impl(GetMessagesStmt &stmt, DialogId dialog_id,
|
||||
MessageId from_message_id, int32 offset, int32 limit) {
|
||||
static vector<MessageDbDialogMessage> get_messages_impl(GetMessagesStmt &stmt, DialogId dialog_id,
|
||||
MessageId from_message_id, int32 offset, int32 limit) {
|
||||
LOG_CHECK(dialog_id.is_valid()) << dialog_id;
|
||||
CHECK(from_message_id.is_valid());
|
||||
|
||||
@ -898,8 +898,8 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
auto right_message_id = message_id - 1;
|
||||
auto right_cnt = -offset;
|
||||
|
||||
vector<MessagesDbDialogMessage> left;
|
||||
vector<MessagesDbDialogMessage> right;
|
||||
vector<MessageDbDialogMessage> left;
|
||||
vector<MessageDbDialogMessage> right;
|
||||
|
||||
if (left_cnt != 0) {
|
||||
if (right_cnt == 1 && false) {
|
||||
@ -930,8 +930,8 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
return right;
|
||||
}
|
||||
|
||||
static vector<MessagesDbDialogMessage> get_messages_inner(SqliteStatement &stmt, DialogId dialog_id,
|
||||
int64 from_message_id, int32 limit) {
|
||||
static vector<MessageDbDialogMessage> get_messages_inner(SqliteStatement &stmt, DialogId dialog_id,
|
||||
int64 from_message_id, int32 limit) {
|
||||
SCOPE_EXIT {
|
||||
stmt.reset();
|
||||
};
|
||||
@ -941,19 +941,19 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
|
||||
LOG(INFO) << "Begin to load " << limit << " messages in " << dialog_id << " from " << MessageId(from_message_id)
|
||||
<< " from database";
|
||||
vector<MessagesDbDialogMessage> result;
|
||||
vector<MessageDbDialogMessage> result;
|
||||
stmt.step().ensure();
|
||||
while (stmt.has_row()) {
|
||||
auto data_slice = stmt.view_blob(0);
|
||||
MessageId message_id(stmt.view_int64(1));
|
||||
result.push_back(MessagesDbDialogMessage{message_id, BufferSlice(data_slice)});
|
||||
result.push_back(MessageDbDialogMessage{message_id, BufferSlice(data_slice)});
|
||||
LOG(INFO) << "Loaded " << message_id << " in " << dialog_id << " from database";
|
||||
stmt.step().ensure();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::pair<MessageId, int32> get_message_info(const MessagesDbDialogMessage &message, bool from_data = false) {
|
||||
static std::pair<MessageId, int32> get_message_info(const MessageDbDialogMessage &message, bool from_data = false) {
|
||||
return get_message_info(message.message_id, message.data.as_slice(), from_data);
|
||||
}
|
||||
|
||||
@ -984,29 +984,29 @@ class MessagesDbImpl final : public MessagesDbSyncInterface {
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<MessagesDbSyncSafeInterface> create_messages_db_sync(
|
||||
std::shared_ptr<MessageDbSyncSafeInterface> create_message_db_sync(
|
||||
std::shared_ptr<SqliteConnectionSafe> sqlite_connection) {
|
||||
class MessagesDbSyncSafe final : public MessagesDbSyncSafeInterface {
|
||||
class MessageDbSyncSafe final : public MessageDbSyncSafeInterface {
|
||||
public:
|
||||
explicit MessagesDbSyncSafe(std::shared_ptr<SqliteConnectionSafe> sqlite_connection)
|
||||
explicit MessageDbSyncSafe(std::shared_ptr<SqliteConnectionSafe> sqlite_connection)
|
||||
: lsls_db_([safe_connection = std::move(sqlite_connection)] {
|
||||
return make_unique<MessagesDbImpl>(safe_connection->get().clone());
|
||||
return make_unique<MessageDbImpl>(safe_connection->get().clone());
|
||||
}) {
|
||||
}
|
||||
MessagesDbSyncInterface &get() final {
|
||||
MessageDbSyncInterface &get() final {
|
||||
return *lsls_db_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
LazySchedulerLocalStorage<unique_ptr<MessagesDbSyncInterface>> lsls_db_;
|
||||
LazySchedulerLocalStorage<unique_ptr<MessageDbSyncInterface>> lsls_db_;
|
||||
};
|
||||
return std::make_shared<MessagesDbSyncSafe>(std::move(sqlite_connection));
|
||||
return std::make_shared<MessageDbSyncSafe>(std::move(sqlite_connection));
|
||||
}
|
||||
|
||||
class MessagesDbAsync final : public MessagesDbAsyncInterface {
|
||||
class MessageDbAsync final : public MessageDbAsyncInterface {
|
||||
public:
|
||||
MessagesDbAsync(std::shared_ptr<MessagesDbSyncSafeInterface> sync_db, int32 scheduler_id) {
|
||||
impl_ = create_actor_on_scheduler<Impl>("MessagesDbActor", scheduler_id, std::move(sync_db));
|
||||
MessageDbAsync(std::shared_ptr<MessageDbSyncSafeInterface> sync_db, int32 scheduler_id) {
|
||||
impl_ = create_actor_on_scheduler<Impl>("MessageDbActor", scheduler_id, std::move(sync_db));
|
||||
}
|
||||
|
||||
void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, DialogId sender_dialog_id,
|
||||
@ -1031,49 +1031,49 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
|
||||
send_closure_later(impl_, &Impl::delete_dialog_messages_by_sender, dialog_id, sender_dialog_id, std::move(promise));
|
||||
}
|
||||
|
||||
void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) final {
|
||||
void get_message(FullMessageId full_message_id, Promise<MessageDbDialogMessage> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_message, full_message_id, std::move(promise));
|
||||
}
|
||||
void get_message_by_unique_message_id(ServerMessageId unique_message_id, Promise<MessagesDbMessage> promise) final {
|
||||
void get_message_by_unique_message_id(ServerMessageId unique_message_id, Promise<MessageDbMessage> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_message_by_unique_message_id, unique_message_id, std::move(promise));
|
||||
}
|
||||
void get_message_by_random_id(DialogId dialog_id, int64 random_id, Promise<MessagesDbDialogMessage> promise) final {
|
||||
void get_message_by_random_id(DialogId dialog_id, int64 random_id, Promise<MessageDbDialogMessage> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_message_by_random_id, dialog_id, random_id, std::move(promise));
|
||||
}
|
||||
void get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id, MessageId last_message_id, int32 date,
|
||||
Promise<MessagesDbDialogMessage> promise) final {
|
||||
Promise<MessageDbDialogMessage> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_dialog_message_by_date, dialog_id, first_message_id, last_message_id, date,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void get_dialog_message_calendar(MessagesDbDialogCalendarQuery query, Promise<MessagesDbCalendar> promise) final {
|
||||
void get_dialog_message_calendar(MessageDbDialogCalendarQuery query, Promise<MessageDbCalendar> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_dialog_message_calendar, std::move(query), std::move(promise));
|
||||
}
|
||||
|
||||
void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
|
||||
Promise<MessagesDbMessagePositions> promise) final {
|
||||
void get_dialog_sparse_message_positions(MessageDbGetDialogSparseMessagePositionsQuery query,
|
||||
Promise<MessageDbMessagePositions> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_dialog_sparse_message_positions, std::move(query), std::move(promise));
|
||||
}
|
||||
|
||||
void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) final {
|
||||
void get_messages(MessageDbMessagesQuery query, Promise<vector<MessageDbDialogMessage>> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_messages, std::move(query), std::move(promise));
|
||||
}
|
||||
void get_scheduled_messages(DialogId dialog_id, int32 limit, Promise<vector<MessagesDbDialogMessage>> promise) final {
|
||||
void get_scheduled_messages(DialogId dialog_id, int32 limit, Promise<vector<MessageDbDialogMessage>> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_scheduled_messages, dialog_id, limit, std::move(promise));
|
||||
}
|
||||
void get_messages_from_notification_id(DialogId dialog_id, NotificationId from_notification_id, int32 limit,
|
||||
Promise<vector<MessagesDbDialogMessage>> promise) final {
|
||||
Promise<vector<MessageDbDialogMessage>> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_messages_from_notification_id, dialog_id, from_notification_id, limit,
|
||||
std::move(promise));
|
||||
}
|
||||
void get_calls(MessagesDbCallsQuery query, Promise<MessagesDbCallsResult> promise) final {
|
||||
void get_calls(MessageDbCallsQuery query, Promise<MessageDbCallsResult> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_calls, std::move(query), std::move(promise));
|
||||
}
|
||||
void get_messages_fts(MessagesDbFtsQuery query, Promise<MessagesDbFtsResult> promise) final {
|
||||
void get_messages_fts(MessageDbFtsQuery query, Promise<MessageDbFtsResult> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_messages_fts, std::move(query), std::move(promise));
|
||||
}
|
||||
void get_expiring_messages(int32 expires_from, int32 expires_till, int32 limit,
|
||||
Promise<std::pair<vector<MessagesDbMessage>, int32>> promise) final {
|
||||
Promise<std::pair<vector<MessageDbMessage>, int32>> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_expiring_messages, expires_from, expires_till, limit, std::move(promise));
|
||||
}
|
||||
|
||||
@ -1088,7 +1088,7 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
|
||||
private:
|
||||
class Impl final : public Actor {
|
||||
public:
|
||||
explicit Impl(std::shared_ptr<MessagesDbSyncSafeInterface> sync_db_safe) : sync_db_safe_(std::move(sync_db_safe)) {
|
||||
explicit Impl(std::shared_ptr<MessageDbSyncSafeInterface> sync_db_safe) : sync_db_safe_(std::move(sync_db_safe)) {
|
||||
}
|
||||
void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, DialogId sender_dialog_id,
|
||||
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
|
||||
@ -1134,58 +1134,58 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) {
|
||||
void get_message(FullMessageId full_message_id, Promise<MessageDbDialogMessage> promise) {
|
||||
add_read_query();
|
||||
promise.set_result(sync_db_->get_message(full_message_id));
|
||||
}
|
||||
void get_message_by_unique_message_id(ServerMessageId unique_message_id, Promise<MessagesDbMessage> promise) {
|
||||
void get_message_by_unique_message_id(ServerMessageId unique_message_id, Promise<MessageDbMessage> promise) {
|
||||
add_read_query();
|
||||
promise.set_result(sync_db_->get_message_by_unique_message_id(unique_message_id));
|
||||
}
|
||||
void get_message_by_random_id(DialogId dialog_id, int64 random_id, Promise<MessagesDbDialogMessage> promise) {
|
||||
void get_message_by_random_id(DialogId dialog_id, int64 random_id, Promise<MessageDbDialogMessage> promise) {
|
||||
add_read_query();
|
||||
promise.set_result(sync_db_->get_message_by_random_id(dialog_id, random_id));
|
||||
}
|
||||
void get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id, MessageId last_message_id,
|
||||
int32 date, Promise<MessagesDbDialogMessage> promise) {
|
||||
int32 date, Promise<MessageDbDialogMessage> promise) {
|
||||
add_read_query();
|
||||
promise.set_result(sync_db_->get_dialog_message_by_date(dialog_id, first_message_id, last_message_id, date));
|
||||
}
|
||||
|
||||
void get_dialog_message_calendar(MessagesDbDialogCalendarQuery query, Promise<MessagesDbCalendar> promise) {
|
||||
void get_dialog_message_calendar(MessageDbDialogCalendarQuery query, Promise<MessageDbCalendar> promise) {
|
||||
add_read_query();
|
||||
promise.set_value(sync_db_->get_dialog_message_calendar(std::move(query)));
|
||||
}
|
||||
|
||||
void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
|
||||
Promise<MessagesDbMessagePositions> promise) {
|
||||
void get_dialog_sparse_message_positions(MessageDbGetDialogSparseMessagePositionsQuery query,
|
||||
Promise<MessageDbMessagePositions> promise) {
|
||||
add_read_query();
|
||||
promise.set_result(sync_db_->get_dialog_sparse_message_positions(std::move(query)));
|
||||
}
|
||||
|
||||
void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) {
|
||||
void get_messages(MessageDbMessagesQuery query, Promise<vector<MessageDbDialogMessage>> promise) {
|
||||
add_read_query();
|
||||
promise.set_value(sync_db_->get_messages(std::move(query)));
|
||||
}
|
||||
void get_scheduled_messages(DialogId dialog_id, int32 limit, Promise<vector<MessagesDbDialogMessage>> promise) {
|
||||
void get_scheduled_messages(DialogId dialog_id, int32 limit, Promise<vector<MessageDbDialogMessage>> promise) {
|
||||
add_read_query();
|
||||
promise.set_value(sync_db_->get_scheduled_messages(dialog_id, limit));
|
||||
}
|
||||
void get_messages_from_notification_id(DialogId dialog_id, NotificationId from_notification_id, int32 limit,
|
||||
Promise<vector<MessagesDbDialogMessage>> promise) {
|
||||
Promise<vector<MessageDbDialogMessage>> promise) {
|
||||
add_read_query();
|
||||
promise.set_value(sync_db_->get_messages_from_notification_id(dialog_id, from_notification_id, limit));
|
||||
}
|
||||
void get_calls(MessagesDbCallsQuery query, Promise<MessagesDbCallsResult> promise) {
|
||||
void get_calls(MessageDbCallsQuery query, Promise<MessageDbCallsResult> promise) {
|
||||
add_read_query();
|
||||
promise.set_value(sync_db_->get_calls(std::move(query)));
|
||||
}
|
||||
void get_messages_fts(MessagesDbFtsQuery query, Promise<MessagesDbFtsResult> promise) {
|
||||
void get_messages_fts(MessageDbFtsQuery query, Promise<MessageDbFtsResult> promise) {
|
||||
add_read_query();
|
||||
promise.set_value(sync_db_->get_messages_fts(std::move(query)));
|
||||
}
|
||||
void get_expiring_messages(int32 expires_from, int32 expires_till, int32 limit,
|
||||
Promise<std::pair<vector<MessagesDbMessage>, int32>> promise) {
|
||||
Promise<std::pair<vector<MessageDbMessage>, int32>> promise) {
|
||||
add_read_query();
|
||||
promise.set_value(sync_db_->get_expiring_messages(expires_from, expires_till, limit));
|
||||
}
|
||||
@ -1199,13 +1199,13 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
|
||||
}
|
||||
|
||||
void force_flush() {
|
||||
LOG(INFO) << "MessagesDb flushed";
|
||||
do_flush();
|
||||
LOG(INFO) << "MessageDb flushed";
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<MessagesDbSyncSafeInterface> sync_db_safe_;
|
||||
MessagesDbSyncInterface *sync_db_ = nullptr;
|
||||
std::shared_ptr<MessageDbSyncSafeInterface> sync_db_safe_;
|
||||
MessageDbSyncInterface *sync_db_ = nullptr;
|
||||
|
||||
static constexpr size_t MAX_PENDING_QUERIES_COUNT{50};
|
||||
static constexpr double MAX_PENDING_QUERIES_DELAY{0.01};
|
||||
@ -1236,15 +1236,9 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
|
||||
return;
|
||||
}
|
||||
sync_db_->begin_write_transaction().ensure();
|
||||
for (auto &query : pending_writes_) {
|
||||
query.set_value(Unit());
|
||||
}
|
||||
set_promises(pending_writes_);
|
||||
sync_db_->commit_transaction().ensure();
|
||||
pending_writes_.clear();
|
||||
for (auto &promise : finished_writes_) {
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
finished_writes_.clear();
|
||||
set_promises(finished_writes_);
|
||||
cancel_timeout();
|
||||
}
|
||||
void timeout_expired() final {
|
||||
@ -1258,9 +1252,9 @@ class MessagesDbAsync final : public MessagesDbAsyncInterface {
|
||||
ActorOwn<Impl> impl_;
|
||||
};
|
||||
|
||||
std::shared_ptr<MessagesDbAsyncInterface> create_messages_db_async(std::shared_ptr<MessagesDbSyncSafeInterface> sync_db,
|
||||
int32 scheduler_id) {
|
||||
return std::make_shared<MessagesDbAsync>(std::move(sync_db), scheduler_id);
|
||||
std::shared_ptr<MessageDbAsyncInterface> create_message_db_async(std::shared_ptr<MessageDbSyncSafeInterface> sync_db,
|
||||
int32 scheduler_id) {
|
||||
return std::make_shared<MessageDbAsync>(std::move(sync_db), scheduler_id);
|
||||
}
|
||||
|
||||
} // namespace td
|
@ -26,7 +26,7 @@ namespace td {
|
||||
class SqliteConnectionSafe;
|
||||
class SqliteDb;
|
||||
|
||||
struct MessagesDbMessagesQuery {
|
||||
struct MessageDbMessagesQuery {
|
||||
DialogId dialog_id;
|
||||
MessageSearchFilter filter{MessageSearchFilter::Empty};
|
||||
MessageId from_message_id;
|
||||
@ -34,75 +34,75 @@ struct MessagesDbMessagesQuery {
|
||||
int32 limit{100};
|
||||
};
|
||||
|
||||
struct MessagesDbDialogMessage {
|
||||
struct MessageDbDialogMessage {
|
||||
MessageId message_id;
|
||||
BufferSlice data;
|
||||
};
|
||||
|
||||
struct MessagesDbMessage {
|
||||
struct MessageDbMessage {
|
||||
DialogId dialog_id;
|
||||
MessageId message_id;
|
||||
BufferSlice data;
|
||||
};
|
||||
|
||||
struct MessagesDbDialogCalendarQuery {
|
||||
struct MessageDbDialogCalendarQuery {
|
||||
DialogId dialog_id;
|
||||
MessageSearchFilter filter{MessageSearchFilter::Empty};
|
||||
MessageId from_message_id;
|
||||
int32 tz_offset{0};
|
||||
};
|
||||
|
||||
struct MessagesDbCalendar {
|
||||
vector<MessagesDbDialogMessage> messages;
|
||||
struct MessageDbCalendar {
|
||||
vector<MessageDbDialogMessage> messages;
|
||||
vector<int32> total_counts;
|
||||
};
|
||||
|
||||
struct MessagesDbGetDialogSparseMessagePositionsQuery {
|
||||
struct MessageDbGetDialogSparseMessagePositionsQuery {
|
||||
DialogId dialog_id;
|
||||
MessageSearchFilter filter{MessageSearchFilter::Empty};
|
||||
MessageId from_message_id;
|
||||
int32 limit{0};
|
||||
};
|
||||
|
||||
struct MessagesDbMessagePosition {
|
||||
struct MessageDbMessagePosition {
|
||||
int32 position;
|
||||
int32 date;
|
||||
MessageId message_id;
|
||||
};
|
||||
|
||||
struct MessagesDbMessagePositions {
|
||||
struct MessageDbMessagePositions {
|
||||
int32 total_count{0};
|
||||
vector<MessagesDbMessagePosition> positions;
|
||||
vector<MessageDbMessagePosition> positions;
|
||||
};
|
||||
|
||||
struct MessagesDbFtsQuery {
|
||||
struct MessageDbFtsQuery {
|
||||
string query;
|
||||
DialogId dialog_id;
|
||||
MessageSearchFilter filter{MessageSearchFilter::Empty};
|
||||
int64 from_search_id{0};
|
||||
int32 limit{100};
|
||||
};
|
||||
struct MessagesDbFtsResult {
|
||||
vector<MessagesDbMessage> messages;
|
||||
struct MessageDbFtsResult {
|
||||
vector<MessageDbMessage> messages;
|
||||
int64 next_search_id{1};
|
||||
};
|
||||
|
||||
struct MessagesDbCallsQuery {
|
||||
struct MessageDbCallsQuery {
|
||||
MessageSearchFilter filter{MessageSearchFilter::Empty};
|
||||
int32 from_unique_message_id{0};
|
||||
int32 limit{100};
|
||||
};
|
||||
|
||||
struct MessagesDbCallsResult {
|
||||
vector<MessagesDbMessage> messages;
|
||||
struct MessageDbCallsResult {
|
||||
vector<MessageDbMessage> messages;
|
||||
};
|
||||
|
||||
class MessagesDbSyncInterface {
|
||||
class MessageDbSyncInterface {
|
||||
public:
|
||||
MessagesDbSyncInterface() = default;
|
||||
MessagesDbSyncInterface(const MessagesDbSyncInterface &) = delete;
|
||||
MessagesDbSyncInterface &operator=(const MessagesDbSyncInterface &) = delete;
|
||||
virtual ~MessagesDbSyncInterface() = default;
|
||||
MessageDbSyncInterface() = default;
|
||||
MessageDbSyncInterface(const MessageDbSyncInterface &) = delete;
|
||||
MessageDbSyncInterface &operator=(const MessageDbSyncInterface &) = delete;
|
||||
virtual ~MessageDbSyncInterface() = default;
|
||||
|
||||
virtual void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, DialogId sender_dialog_id,
|
||||
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
|
||||
@ -113,48 +113,48 @@ class MessagesDbSyncInterface {
|
||||
virtual void delete_all_dialog_messages(DialogId dialog_id, MessageId from_message_id) = 0;
|
||||
virtual void delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id) = 0;
|
||||
|
||||
virtual Result<MessagesDbDialogMessage> get_message(FullMessageId full_message_id) = 0;
|
||||
virtual Result<MessagesDbMessage> get_message_by_unique_message_id(ServerMessageId unique_message_id) = 0;
|
||||
virtual Result<MessagesDbDialogMessage> get_message_by_random_id(DialogId dialog_id, int64 random_id) = 0;
|
||||
virtual Result<MessagesDbDialogMessage> get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id,
|
||||
MessageId last_message_id, int32 date) = 0;
|
||||
virtual Result<MessageDbDialogMessage> get_message(FullMessageId full_message_id) = 0;
|
||||
virtual Result<MessageDbMessage> get_message_by_unique_message_id(ServerMessageId unique_message_id) = 0;
|
||||
virtual Result<MessageDbDialogMessage> get_message_by_random_id(DialogId dialog_id, int64 random_id) = 0;
|
||||
virtual Result<MessageDbDialogMessage> get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id,
|
||||
MessageId last_message_id, int32 date) = 0;
|
||||
|
||||
virtual MessagesDbCalendar get_dialog_message_calendar(MessagesDbDialogCalendarQuery query) = 0;
|
||||
virtual MessageDbCalendar get_dialog_message_calendar(MessageDbDialogCalendarQuery query) = 0;
|
||||
|
||||
virtual Result<MessagesDbMessagePositions> get_dialog_sparse_message_positions(
|
||||
MessagesDbGetDialogSparseMessagePositionsQuery query) = 0;
|
||||
virtual Result<MessageDbMessagePositions> get_dialog_sparse_message_positions(
|
||||
MessageDbGetDialogSparseMessagePositionsQuery query) = 0;
|
||||
|
||||
virtual vector<MessagesDbDialogMessage> get_messages(MessagesDbMessagesQuery query) = 0;
|
||||
virtual vector<MessagesDbDialogMessage> get_scheduled_messages(DialogId dialog_id, int32 limit) = 0;
|
||||
virtual vector<MessagesDbDialogMessage> get_messages_from_notification_id(DialogId dialog_id,
|
||||
NotificationId from_notification_id,
|
||||
int32 limit) = 0;
|
||||
virtual vector<MessageDbDialogMessage> get_messages(MessageDbMessagesQuery query) = 0;
|
||||
virtual vector<MessageDbDialogMessage> get_scheduled_messages(DialogId dialog_id, int32 limit) = 0;
|
||||
virtual vector<MessageDbDialogMessage> get_messages_from_notification_id(DialogId dialog_id,
|
||||
NotificationId from_notification_id,
|
||||
int32 limit) = 0;
|
||||
|
||||
virtual std::pair<vector<MessagesDbMessage>, int32> get_expiring_messages(int32 expires_from, int32 expires_till,
|
||||
int32 limit) = 0;
|
||||
virtual MessagesDbCallsResult get_calls(MessagesDbCallsQuery query) = 0;
|
||||
virtual MessagesDbFtsResult get_messages_fts(MessagesDbFtsQuery query) = 0;
|
||||
virtual std::pair<vector<MessageDbMessage>, int32> get_expiring_messages(int32 expires_from, int32 expires_till,
|
||||
int32 limit) = 0;
|
||||
virtual MessageDbCallsResult get_calls(MessageDbCallsQuery query) = 0;
|
||||
virtual MessageDbFtsResult get_messages_fts(MessageDbFtsQuery query) = 0;
|
||||
|
||||
virtual Status begin_write_transaction() = 0;
|
||||
virtual Status commit_transaction() = 0;
|
||||
};
|
||||
|
||||
class MessagesDbSyncSafeInterface {
|
||||
class MessageDbSyncSafeInterface {
|
||||
public:
|
||||
MessagesDbSyncSafeInterface() = default;
|
||||
MessagesDbSyncSafeInterface(const MessagesDbSyncSafeInterface &) = delete;
|
||||
MessagesDbSyncSafeInterface &operator=(const MessagesDbSyncSafeInterface &) = delete;
|
||||
virtual ~MessagesDbSyncSafeInterface() = default;
|
||||
MessageDbSyncSafeInterface() = default;
|
||||
MessageDbSyncSafeInterface(const MessageDbSyncSafeInterface &) = delete;
|
||||
MessageDbSyncSafeInterface &operator=(const MessageDbSyncSafeInterface &) = delete;
|
||||
virtual ~MessageDbSyncSafeInterface() = default;
|
||||
|
||||
virtual MessagesDbSyncInterface &get() = 0;
|
||||
virtual MessageDbSyncInterface &get() = 0;
|
||||
};
|
||||
|
||||
class MessagesDbAsyncInterface {
|
||||
class MessageDbAsyncInterface {
|
||||
public:
|
||||
MessagesDbAsyncInterface() = default;
|
||||
MessagesDbAsyncInterface(const MessagesDbAsyncInterface &) = delete;
|
||||
MessagesDbAsyncInterface &operator=(const MessagesDbAsyncInterface &) = delete;
|
||||
virtual ~MessagesDbAsyncInterface() = default;
|
||||
MessageDbAsyncInterface() = default;
|
||||
MessageDbAsyncInterface(const MessageDbAsyncInterface &) = delete;
|
||||
MessageDbAsyncInterface &operator=(const MessageDbAsyncInterface &) = delete;
|
||||
virtual ~MessageDbAsyncInterface() = default;
|
||||
|
||||
virtual void add_message(FullMessageId full_message_id, ServerMessageId unique_message_id, DialogId sender_dialog_id,
|
||||
int64 random_id, int32 ttl_expires_at, int32 index_mask, int64 search_id, string text,
|
||||
@ -166,43 +166,42 @@ class MessagesDbAsyncInterface {
|
||||
virtual void delete_all_dialog_messages(DialogId dialog_id, MessageId from_message_id, Promise<> promise) = 0;
|
||||
virtual void delete_dialog_messages_by_sender(DialogId dialog_id, DialogId sender_dialog_id, Promise<> promise) = 0;
|
||||
|
||||
virtual void get_message(FullMessageId full_message_id, Promise<MessagesDbDialogMessage> promise) = 0;
|
||||
virtual void get_message(FullMessageId full_message_id, Promise<MessageDbDialogMessage> promise) = 0;
|
||||
virtual void get_message_by_unique_message_id(ServerMessageId unique_message_id,
|
||||
Promise<MessagesDbMessage> promise) = 0;
|
||||
Promise<MessageDbMessage> promise) = 0;
|
||||
virtual void get_message_by_random_id(DialogId dialog_id, int64 random_id,
|
||||
Promise<MessagesDbDialogMessage> promise) = 0;
|
||||
Promise<MessageDbDialogMessage> promise) = 0;
|
||||
virtual void get_dialog_message_by_date(DialogId dialog_id, MessageId first_message_id, MessageId last_message_id,
|
||||
int32 date, Promise<MessagesDbDialogMessage> promise) = 0;
|
||||
int32 date, Promise<MessageDbDialogMessage> promise) = 0;
|
||||
|
||||
virtual void get_dialog_message_calendar(MessagesDbDialogCalendarQuery query,
|
||||
Promise<MessagesDbCalendar> promise) = 0;
|
||||
virtual void get_dialog_message_calendar(MessageDbDialogCalendarQuery query, Promise<MessageDbCalendar> promise) = 0;
|
||||
|
||||
virtual void get_dialog_sparse_message_positions(MessagesDbGetDialogSparseMessagePositionsQuery query,
|
||||
Promise<MessagesDbMessagePositions> promise) = 0;
|
||||
virtual void get_dialog_sparse_message_positions(MessageDbGetDialogSparseMessagePositionsQuery query,
|
||||
Promise<MessageDbMessagePositions> promise) = 0;
|
||||
|
||||
virtual void get_messages(MessagesDbMessagesQuery query, Promise<vector<MessagesDbDialogMessage>> promise) = 0;
|
||||
virtual void get_messages(MessageDbMessagesQuery query, Promise<vector<MessageDbDialogMessage>> promise) = 0;
|
||||
virtual void get_scheduled_messages(DialogId dialog_id, int32 limit,
|
||||
Promise<vector<MessagesDbDialogMessage>> promise) = 0;
|
||||
Promise<vector<MessageDbDialogMessage>> promise) = 0;
|
||||
virtual void get_messages_from_notification_id(DialogId dialog_id, NotificationId from_notification_id, int32 limit,
|
||||
Promise<vector<MessagesDbDialogMessage>> promise) = 0;
|
||||
Promise<vector<MessageDbDialogMessage>> promise) = 0;
|
||||
|
||||
virtual void get_calls(MessagesDbCallsQuery, Promise<MessagesDbCallsResult> promise) = 0;
|
||||
virtual void get_messages_fts(MessagesDbFtsQuery query, Promise<MessagesDbFtsResult> promise) = 0;
|
||||
virtual void get_calls(MessageDbCallsQuery, Promise<MessageDbCallsResult> promise) = 0;
|
||||
virtual void get_messages_fts(MessageDbFtsQuery query, Promise<MessageDbFtsResult> promise) = 0;
|
||||
|
||||
virtual void get_expiring_messages(int32 expires_from, int32 expires_till, int32 limit,
|
||||
Promise<std::pair<vector<MessagesDbMessage>, int32>> promise) = 0;
|
||||
Promise<std::pair<vector<MessageDbMessage>, int32>> promise) = 0;
|
||||
|
||||
virtual void close(Promise<> promise) = 0;
|
||||
virtual void force_flush() = 0;
|
||||
};
|
||||
|
||||
Status init_messages_db(SqliteDb &db, int version) TD_WARN_UNUSED_RESULT;
|
||||
Status drop_messages_db(SqliteDb &db, int version) TD_WARN_UNUSED_RESULT;
|
||||
Status init_message_db(SqliteDb &db, int version) TD_WARN_UNUSED_RESULT;
|
||||
Status drop_message_db(SqliteDb &db, int version) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
std::shared_ptr<MessagesDbSyncSafeInterface> create_messages_db_sync(
|
||||
std::shared_ptr<MessageDbSyncSafeInterface> create_message_db_sync(
|
||||
std::shared_ptr<SqliteConnectionSafe> sqlite_connection);
|
||||
|
||||
std::shared_ptr<MessagesDbAsyncInterface> create_messages_db_async(std::shared_ptr<MessagesDbSyncSafeInterface> sync_db,
|
||||
int32 scheduler_id = -1);
|
||||
std::shared_ptr<MessageDbAsyncInterface> create_message_db_async(std::shared_ptr<MessageDbSyncSafeInterface> sync_db,
|
||||
int32 scheduler_id = -1);
|
||||
|
||||
} // namespace td
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/Promise.h"
|
||||
@ -2455,7 +2456,7 @@ static FormattedText parse_text_url_entities_v3(Slice text, const vector<Message
|
||||
}
|
||||
|
||||
static vector<MessageEntity> find_splittable_entities_v3(Slice text, const vector<MessageEntity> &entities) {
|
||||
std::unordered_set<size_t> unallowed_boundaries;
|
||||
std::unordered_set<int32, Hash<int32>> unallowed_boundaries;
|
||||
for (auto &entity : entities) {
|
||||
unallowed_boundaries.insert(entity.offset);
|
||||
unallowed_boundaries.insert(entity.offset + entity.length);
|
||||
@ -2489,7 +2490,8 @@ static vector<MessageEntity> find_splittable_entities_v3(Slice text, const vecto
|
||||
if ((c == '_' || c == '*' || c == '~' || c == '|') && text[i] == text[i + 1] &&
|
||||
unallowed_boundaries.count(utf16_offset) == 0) {
|
||||
auto j = i + 2;
|
||||
while (j != text.size() && text[j] == text[i] && unallowed_boundaries.count(utf16_offset + j - i - 1) == 0) {
|
||||
while (j != text.size() && text[j] == text[i] &&
|
||||
unallowed_boundaries.count(utf16_offset + static_cast<int32>(j - i - 1)) == 0) {
|
||||
j++;
|
||||
}
|
||||
if (j == i + 2) {
|
||||
|
@ -10,9 +10,9 @@
|
||||
#include "td/telegram/ServerMessageId.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
@ -182,8 +182,8 @@ class MessageId {
|
||||
};
|
||||
|
||||
struct MessageIdHash {
|
||||
std::size_t operator()(MessageId message_id) const {
|
||||
return std::hash<int64>()(message_id.get());
|
||||
uint32 operator()(MessageId message_id) const {
|
||||
return Hash<int64>()(message_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -27,31 +27,31 @@ MessageReplyInfo::MessageReplyInfo(Td *td, tl_object_ptr<telegram_api::messageRe
|
||||
return;
|
||||
}
|
||||
if (is_bot || reply_info->channel_id_ == 777) {
|
||||
is_dropped = true;
|
||||
is_dropped_ = true;
|
||||
return;
|
||||
}
|
||||
reply_count = reply_info->replies_;
|
||||
pts = reply_info->replies_pts_;
|
||||
reply_count_ = reply_info->replies_;
|
||||
pts_ = reply_info->replies_pts_;
|
||||
|
||||
is_comment = reply_info->comments_;
|
||||
is_comment_ = reply_info->comments_;
|
||||
|
||||
if (is_comment) {
|
||||
channel_id = ChannelId(reply_info->channel_id_);
|
||||
if (!channel_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << channel_id;
|
||||
channel_id = ChannelId();
|
||||
is_comment = false;
|
||||
if (is_comment_) {
|
||||
channel_id_ = ChannelId(reply_info->channel_id_);
|
||||
if (!channel_id_.is_valid()) {
|
||||
LOG(ERROR) << "Receive invalid " << channel_id_;
|
||||
channel_id_ = ChannelId();
|
||||
is_comment_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_comment) {
|
||||
if (is_comment_) {
|
||||
for (const auto &peer : reply_info->recent_repliers_) {
|
||||
DialogId dialog_id(peer);
|
||||
if (!dialog_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive " << dialog_id << " as a recent replier";
|
||||
continue;
|
||||
}
|
||||
if (td::contains(recent_replier_dialog_ids, dialog_id)) {
|
||||
if (td::contains(recent_replier_dialog_ids_, dialog_id)) {
|
||||
LOG(ERROR) << "Receive duplicate " << dialog_id << " as a recent replier";
|
||||
continue;
|
||||
}
|
||||
@ -70,28 +70,28 @@ MessageReplyInfo::MessageReplyInfo(Td *td, tl_object_ptr<telegram_api::messageRe
|
||||
LOG(ERROR) << "Receive unknown replied " << replier_channel_id;
|
||||
continue;
|
||||
}
|
||||
replier_min_channels.emplace_back(replier_channel_id, *min_channel);
|
||||
replier_min_channels_.emplace_back(replier_channel_id, *min_channel);
|
||||
} else {
|
||||
LOG(ERROR) << "Receive unknown replied " << dialog_id;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
recent_replier_dialog_ids.push_back(dialog_id);
|
||||
if (recent_replier_dialog_ids.size() == MAX_RECENT_REPLIERS) {
|
||||
recent_replier_dialog_ids_.push_back(dialog_id);
|
||||
if (recent_replier_dialog_ids_.size() == MAX_RECENT_REPLIERS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((reply_info->flags_ & telegram_api::messageReplies::MAX_ID_MASK) != 0 &&
|
||||
ServerMessageId(reply_info->max_id_).is_valid()) {
|
||||
max_message_id = MessageId(ServerMessageId(reply_info->max_id_));
|
||||
max_message_id_ = MessageId(ServerMessageId(reply_info->max_id_));
|
||||
}
|
||||
if ((reply_info->flags_ & telegram_api::messageReplies::READ_MAX_ID_MASK) != 0 &&
|
||||
ServerMessageId(reply_info->read_max_id_).is_valid()) {
|
||||
last_read_inbox_message_id = MessageId(ServerMessageId(reply_info->read_max_id_));
|
||||
last_read_inbox_message_id_ = MessageId(ServerMessageId(reply_info->read_max_id_));
|
||||
}
|
||||
if (last_read_inbox_message_id > max_message_id) { // possible if last thread message was deleted after it was read
|
||||
max_message_id = last_read_inbox_message_id;
|
||||
if (last_read_inbox_message_id_ > max_message_id_) { // possible if last thread message was deleted after it was read
|
||||
max_message_id_ = last_read_inbox_message_id_;
|
||||
}
|
||||
LOG(DEBUG) << "Parsed " << oneline(to_string(reply_info)) << " to " << *this;
|
||||
}
|
||||
@ -101,42 +101,43 @@ bool MessageReplyInfo::need_update_to(const MessageReplyInfo &other) const {
|
||||
// ignore updates to empty reply info, because we will hide the info ourselves
|
||||
// return true;
|
||||
}
|
||||
if (other.pts < pts) {
|
||||
if (other.pts_ < pts_ && !other.was_dropped()) {
|
||||
return false;
|
||||
}
|
||||
return reply_count != other.reply_count || recent_replier_dialog_ids != other.recent_replier_dialog_ids ||
|
||||
replier_min_channels.size() != other.replier_min_channels.size() || is_comment != other.is_comment ||
|
||||
channel_id != other.channel_id;
|
||||
return reply_count_ != other.reply_count_ || recent_replier_dialog_ids_ != other.recent_replier_dialog_ids_ ||
|
||||
replier_min_channels_.size() != other.replier_min_channels_.size() || is_comment_ != other.is_comment_ ||
|
||||
channel_id_ != other.channel_id_;
|
||||
}
|
||||
|
||||
bool MessageReplyInfo::update_max_message_ids(const MessageReplyInfo &other) {
|
||||
return update_max_message_ids(other.max_message_id, other.last_read_inbox_message_id,
|
||||
other.last_read_outbox_message_id);
|
||||
return update_max_message_ids(other.max_message_id_, other.last_read_inbox_message_id_,
|
||||
other.last_read_outbox_message_id_);
|
||||
}
|
||||
|
||||
bool MessageReplyInfo::update_max_message_ids(MessageId other_max_message_id,
|
||||
MessageId other_last_read_inbox_message_id,
|
||||
MessageId other_last_read_outbox_message_id) {
|
||||
bool result = false;
|
||||
if (other_max_message_id > max_message_id) {
|
||||
max_message_id = other_max_message_id;
|
||||
if (other_last_read_inbox_message_id > last_read_inbox_message_id_) {
|
||||
last_read_inbox_message_id_ = other_last_read_inbox_message_id;
|
||||
result = true;
|
||||
}
|
||||
if (other_last_read_inbox_message_id > last_read_inbox_message_id) {
|
||||
last_read_inbox_message_id = other_last_read_inbox_message_id;
|
||||
if (other_last_read_outbox_message_id > last_read_outbox_message_id_) {
|
||||
last_read_outbox_message_id_ = other_last_read_outbox_message_id;
|
||||
result = true;
|
||||
}
|
||||
if (other_last_read_outbox_message_id > last_read_outbox_message_id) {
|
||||
last_read_outbox_message_id = other_last_read_outbox_message_id;
|
||||
result = true;
|
||||
}
|
||||
if (last_read_inbox_message_id > max_message_id) {
|
||||
max_message_id = last_read_inbox_message_id;
|
||||
result = true;
|
||||
}
|
||||
if (last_read_outbox_message_id > max_message_id) {
|
||||
max_message_id = last_read_outbox_message_id;
|
||||
result = true;
|
||||
if (other_max_message_id.is_valid() ||
|
||||
(!other_last_read_inbox_message_id.is_valid() && !other_last_read_outbox_message_id.is_valid())) {
|
||||
if (other_max_message_id < last_read_inbox_message_id_) {
|
||||
other_max_message_id = last_read_inbox_message_id_;
|
||||
}
|
||||
if (other_max_message_id < last_read_outbox_message_id_) {
|
||||
other_max_message_id = last_read_outbox_message_id_;
|
||||
}
|
||||
if (other_max_message_id != max_message_id_) {
|
||||
max_message_id_ = other_max_message_id;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -145,44 +146,44 @@ bool MessageReplyInfo::add_reply(DialogId replier_dialog_id, MessageId reply_mes
|
||||
CHECK(!is_empty());
|
||||
CHECK(diff == +1 || diff == -1);
|
||||
|
||||
if (diff == -1 && reply_count == 0) {
|
||||
if (diff == -1 && reply_count_ == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
reply_count += diff;
|
||||
if (is_comment && replier_dialog_id.is_valid()) {
|
||||
reply_count_ += diff;
|
||||
if (is_comment_ && replier_dialog_id.is_valid()) {
|
||||
if (replier_dialog_id.get_type() == DialogType::Channel) {
|
||||
// the replier_dialog_id is never min, because it is the sender of a message
|
||||
for (auto it = replier_min_channels.begin(); it != replier_min_channels.end(); ++it) {
|
||||
for (auto it = replier_min_channels_.begin(); it != replier_min_channels_.end(); ++it) {
|
||||
if (it->first == replier_dialog_id.get_channel_id()) {
|
||||
replier_min_channels.erase(it);
|
||||
replier_min_channels_.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td::remove(recent_replier_dialog_ids, replier_dialog_id);
|
||||
td::remove(recent_replier_dialog_ids_, replier_dialog_id);
|
||||
if (diff > 0) {
|
||||
recent_replier_dialog_ids.insert(recent_replier_dialog_ids.begin(), replier_dialog_id);
|
||||
if (recent_replier_dialog_ids.size() > MAX_RECENT_REPLIERS) {
|
||||
recent_replier_dialog_ids.pop_back();
|
||||
recent_replier_dialog_ids_.insert(recent_replier_dialog_ids_.begin(), replier_dialog_id);
|
||||
if (recent_replier_dialog_ids_.size() > MAX_RECENT_REPLIERS) {
|
||||
recent_replier_dialog_ids_.pop_back();
|
||||
}
|
||||
} else {
|
||||
auto max_repliers = static_cast<size_t>(reply_count);
|
||||
if (recent_replier_dialog_ids.size() > max_repliers) {
|
||||
recent_replier_dialog_ids.resize(max_repliers);
|
||||
auto max_repliers = static_cast<size_t>(reply_count_);
|
||||
if (recent_replier_dialog_ids_.size() > max_repliers) {
|
||||
recent_replier_dialog_ids_.resize(max_repliers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (diff > 0 && reply_message_id > max_message_id) {
|
||||
max_message_id = reply_message_id;
|
||||
if (diff > 0 && reply_message_id > max_message_id_) {
|
||||
max_message_id_ = reply_message_id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessageReplyInfo::need_reget(const Td *td) const {
|
||||
for (auto &dialog_id : recent_replier_dialog_ids) {
|
||||
for (auto &dialog_id : recent_replier_dialog_ids_) {
|
||||
if (dialog_id.get_type() != DialogType::User && !td->messages_manager_->have_dialog_info(dialog_id)) {
|
||||
if (dialog_id.get_type() == DialogType::Channel &&
|
||||
td->contacts_manager_->have_min_channel(dialog_id.get_channel_id())) {
|
||||
@ -195,31 +196,36 @@ bool MessageReplyInfo::need_reget(const Td *td) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
td_api::object_ptr<td_api::messageReplyInfo> MessageReplyInfo::get_message_reply_info_object(Td *td) const {
|
||||
td_api::object_ptr<td_api::messageReplyInfo> MessageReplyInfo::get_message_reply_info_object(
|
||||
Td *td, MessageId dialog_last_read_inbox_message_id) const {
|
||||
if (is_empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vector<td_api::object_ptr<td_api::MessageSender>> recent_repliers;
|
||||
for (auto dialog_id : recent_replier_dialog_ids) {
|
||||
for (auto dialog_id : recent_replier_dialog_ids_) {
|
||||
auto recent_replier = get_min_message_sender_object(td, dialog_id, "get_message_reply_info_object");
|
||||
if (recent_replier != nullptr) {
|
||||
recent_repliers.push_back(std::move(recent_replier));
|
||||
}
|
||||
}
|
||||
return td_api::make_object<td_api::messageReplyInfo>(reply_count, std::move(recent_repliers),
|
||||
auto last_read_inbox_message_id = last_read_inbox_message_id_;
|
||||
if (last_read_inbox_message_id.is_valid() && last_read_inbox_message_id < dialog_last_read_inbox_message_id) {
|
||||
last_read_inbox_message_id = min(dialog_last_read_inbox_message_id, max_message_id_);
|
||||
}
|
||||
return td_api::make_object<td_api::messageReplyInfo>(reply_count_, std::move(recent_repliers),
|
||||
last_read_inbox_message_id.get(),
|
||||
last_read_outbox_message_id.get(), max_message_id.get());
|
||||
last_read_outbox_message_id_.get(), max_message_id_.get());
|
||||
}
|
||||
|
||||
StringBuilder &operator<<(StringBuilder &string_builder, const MessageReplyInfo &reply_info) {
|
||||
if (reply_info.is_comment) {
|
||||
return string_builder << reply_info.reply_count << " comments in " << reply_info.channel_id << " by "
|
||||
<< reply_info.recent_replier_dialog_ids << " read up to "
|
||||
<< reply_info.last_read_inbox_message_id << "/" << reply_info.last_read_outbox_message_id;
|
||||
if (reply_info.is_comment_) {
|
||||
return string_builder << reply_info.reply_count_ << " comments in " << reply_info.channel_id_ << " by "
|
||||
<< reply_info.recent_replier_dialog_ids_ << " read up to "
|
||||
<< reply_info.last_read_inbox_message_id_ << "/" << reply_info.last_read_outbox_message_id_;
|
||||
} else {
|
||||
return string_builder << reply_info.reply_count << " replies read up to " << reply_info.last_read_inbox_message_id
|
||||
<< "/" << reply_info.last_read_outbox_message_id;
|
||||
return string_builder << reply_info.reply_count_ << " replies read up to " << reply_info.last_read_inbox_message_id_
|
||||
<< "/" << reply_info.last_read_outbox_message_id_;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,16 +23,16 @@ namespace td {
|
||||
class Td;
|
||||
|
||||
struct MessageReplyInfo {
|
||||
int32 reply_count = -1;
|
||||
int32 pts = -1;
|
||||
vector<DialogId> recent_replier_dialog_ids; // comments only
|
||||
vector<std::pair<ChannelId, MinChannel>> replier_min_channels; // comments only
|
||||
ChannelId channel_id; // comments only
|
||||
MessageId max_message_id;
|
||||
MessageId last_read_inbox_message_id;
|
||||
MessageId last_read_outbox_message_id;
|
||||
bool is_comment = false;
|
||||
bool is_dropped = false;
|
||||
int32 reply_count_ = -1;
|
||||
int32 pts_ = -1;
|
||||
vector<DialogId> recent_replier_dialog_ids_; // comments only
|
||||
vector<std::pair<ChannelId, MinChannel>> replier_min_channels_; // comments only
|
||||
ChannelId channel_id_; // comments only
|
||||
MessageId max_message_id_;
|
||||
MessageId last_read_inbox_message_id_;
|
||||
MessageId last_read_outbox_message_id_;
|
||||
bool is_comment_ = false;
|
||||
bool is_dropped_ = false;
|
||||
|
||||
static constexpr size_t MAX_RECENT_REPLIERS = 3;
|
||||
|
||||
@ -41,11 +41,11 @@ struct MessageReplyInfo {
|
||||
MessageReplyInfo(Td *td, tl_object_ptr<telegram_api::messageReplies> &&reply_info, bool is_bot);
|
||||
|
||||
bool is_empty() const {
|
||||
return reply_count < 0;
|
||||
return reply_count_ < 0;
|
||||
}
|
||||
|
||||
bool was_dropped() const {
|
||||
return is_dropped;
|
||||
return is_dropped_;
|
||||
}
|
||||
|
||||
bool need_update_to(const MessageReplyInfo &other) const;
|
||||
@ -59,7 +59,8 @@ struct MessageReplyInfo {
|
||||
|
||||
bool need_reget(const Td *td) const;
|
||||
|
||||
td_api::object_ptr<td_api::messageReplyInfo> get_message_reply_info_object(Td *td) const;
|
||||
td_api::object_ptr<td_api::messageReplyInfo> get_message_reply_info_object(
|
||||
Td *td, MessageId dialog_last_read_inbox_message_id) const;
|
||||
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const;
|
||||
|
@ -17,14 +17,14 @@ namespace td {
|
||||
template <class StorerT>
|
||||
void MessageReplyInfo::store(StorerT &storer) const {
|
||||
CHECK(!is_empty());
|
||||
bool has_recent_replier_dialog_ids = !recent_replier_dialog_ids.empty();
|
||||
bool has_channel_id = channel_id.is_valid();
|
||||
bool has_max_message_id = max_message_id.is_valid();
|
||||
bool has_last_read_inbox_message_id = last_read_inbox_message_id.is_valid();
|
||||
bool has_last_read_outbox_message_id = last_read_outbox_message_id.is_valid();
|
||||
bool has_replier_min_channels = !replier_min_channels.empty();
|
||||
bool has_recent_replier_dialog_ids = !recent_replier_dialog_ids_.empty();
|
||||
bool has_channel_id = channel_id_.is_valid();
|
||||
bool has_max_message_id = max_message_id_.is_valid();
|
||||
bool has_last_read_inbox_message_id = last_read_inbox_message_id_.is_valid();
|
||||
bool has_last_read_outbox_message_id = last_read_outbox_message_id_.is_valid();
|
||||
bool has_replier_min_channels = !replier_min_channels_.empty();
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(is_comment);
|
||||
STORE_FLAG(is_comment_);
|
||||
STORE_FLAG(has_recent_replier_dialog_ids);
|
||||
STORE_FLAG(has_channel_id);
|
||||
STORE_FLAG(has_max_message_id);
|
||||
@ -32,25 +32,25 @@ void MessageReplyInfo::store(StorerT &storer) const {
|
||||
STORE_FLAG(has_last_read_outbox_message_id);
|
||||
STORE_FLAG(has_replier_min_channels);
|
||||
END_STORE_FLAGS();
|
||||
td::store(reply_count, storer);
|
||||
td::store(pts, storer);
|
||||
td::store(reply_count_, storer);
|
||||
td::store(pts_, storer);
|
||||
if (has_recent_replier_dialog_ids) {
|
||||
td::store(recent_replier_dialog_ids, storer);
|
||||
td::store(recent_replier_dialog_ids_, storer);
|
||||
}
|
||||
if (has_channel_id) {
|
||||
td::store(channel_id, storer);
|
||||
td::store(channel_id_, storer);
|
||||
}
|
||||
if (has_max_message_id) {
|
||||
td::store(max_message_id, storer);
|
||||
td::store(max_message_id_, storer);
|
||||
}
|
||||
if (has_last_read_inbox_message_id) {
|
||||
td::store(last_read_inbox_message_id, storer);
|
||||
td::store(last_read_inbox_message_id_, storer);
|
||||
}
|
||||
if (has_last_read_outbox_message_id) {
|
||||
td::store(last_read_outbox_message_id, storer);
|
||||
td::store(last_read_outbox_message_id_, storer);
|
||||
}
|
||||
if (has_replier_min_channels) {
|
||||
td::store(replier_min_channels, storer);
|
||||
td::store(replier_min_channels_, storer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ void MessageReplyInfo::parse(ParserT &parser) {
|
||||
bool has_last_read_outbox_message_id;
|
||||
bool has_replier_min_channels;
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(is_comment);
|
||||
PARSE_FLAG(is_comment_);
|
||||
PARSE_FLAG(has_recent_replier_dialog_ids);
|
||||
PARSE_FLAG(has_channel_id);
|
||||
PARSE_FLAG(has_max_message_id);
|
||||
@ -71,32 +71,33 @@ void MessageReplyInfo::parse(ParserT &parser) {
|
||||
PARSE_FLAG(has_last_read_outbox_message_id);
|
||||
PARSE_FLAG(has_replier_min_channels);
|
||||
END_PARSE_FLAGS();
|
||||
td::parse(reply_count, parser);
|
||||
td::parse(pts, parser);
|
||||
td::parse(reply_count_, parser);
|
||||
td::parse(pts_, parser);
|
||||
if (has_recent_replier_dialog_ids) {
|
||||
td::parse(recent_replier_dialog_ids, parser);
|
||||
td::parse(recent_replier_dialog_ids_, parser);
|
||||
}
|
||||
if (has_channel_id) {
|
||||
td::parse(channel_id, parser);
|
||||
td::parse(channel_id_, parser);
|
||||
}
|
||||
if (has_max_message_id) {
|
||||
td::parse(max_message_id, parser);
|
||||
td::parse(max_message_id_, parser);
|
||||
}
|
||||
if (has_last_read_inbox_message_id) {
|
||||
td::parse(last_read_inbox_message_id, parser);
|
||||
td::parse(last_read_inbox_message_id_, parser);
|
||||
}
|
||||
if (has_last_read_outbox_message_id) {
|
||||
td::parse(last_read_outbox_message_id, parser);
|
||||
td::parse(last_read_outbox_message_id_, parser);
|
||||
}
|
||||
if (has_replier_min_channels) {
|
||||
td::parse(replier_min_channels, parser);
|
||||
td::parse(replier_min_channels_, parser);
|
||||
}
|
||||
|
||||
if (channel_id.get() == 777) {
|
||||
if (channel_id_.get() == 777) {
|
||||
*this = MessageReplyInfo();
|
||||
is_dropped_ = true;
|
||||
}
|
||||
if (recent_replier_dialog_ids.size() > MAX_RECENT_REPLIERS) {
|
||||
recent_replier_dialog_ids.resize(MAX_RECENT_REPLIERS);
|
||||
if (recent_replier_dialog_ids_.size() > MAX_RECENT_REPLIERS) {
|
||||
recent_replier_dialog_ids_.resize(MAX_RECENT_REPLIERS);
|
||||
}
|
||||
}
|
||||
|
||||
|
343
td/telegram/MessageThreadDb.cpp
Normal file
343
td/telegram/MessageThreadDb.cpp
Normal file
@ -0,0 +1,343 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/telegram/MessageThreadDb.h"
|
||||
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/db/SqliteConnectionSafe.h"
|
||||
#include "td/db/SqliteDb.h"
|
||||
#include "td/db/SqliteStatement.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/SchedulerLocalStorage.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/ScopeGuard.h"
|
||||
#include "td/utils/Time.h"
|
||||
|
||||
namespace td {
|
||||
// NB: must happen inside a transaction
|
||||
Status init_message_thread_db(SqliteDb &db, int32 version) {
|
||||
LOG(INFO) << "Init message thread database " << tag("version", version);
|
||||
|
||||
// Check if database exists
|
||||
TRY_RESULT(has_table, db.has_table("threads"));
|
||||
if (!has_table) {
|
||||
version = 0;
|
||||
}
|
||||
|
||||
if (version > current_db_version()) {
|
||||
TRY_STATUS(drop_message_thread_db(db, version));
|
||||
version = 0;
|
||||
}
|
||||
|
||||
if (version == 0) {
|
||||
LOG(INFO) << "Create new message thread database";
|
||||
TRY_STATUS(
|
||||
db.exec("CREATE TABLE IF NOT EXISTS threads (dialog_id INT8, thread_id INT8, thread_order INT8, data BLOB, "
|
||||
"PRIMARY KEY (dialog_id, thread_id))"));
|
||||
TRY_STATUS(
|
||||
db.exec("CREATE INDEX IF NOT EXISTS dialog_threads_by_thread_order ON threads (dialog_id, thread_order)"));
|
||||
version = current_db_version();
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
// NB: must happen inside a transaction
|
||||
Status drop_message_thread_db(SqliteDb &db, int version) {
|
||||
if (version > current_db_version()) {
|
||||
LOG(WARNING) << "Drop message_thread_db " << tag("version", version)
|
||||
<< tag("current_db_version", current_db_version());
|
||||
}
|
||||
return db.exec("DROP TABLE IF EXISTS threads");
|
||||
}
|
||||
|
||||
class MessageThreadDbImpl final : public MessageThreadDbSyncInterface {
|
||||
public:
|
||||
explicit MessageThreadDbImpl(SqliteDb db) : db_(std::move(db)) {
|
||||
init().ensure();
|
||||
}
|
||||
|
||||
Status init() {
|
||||
TRY_RESULT_ASSIGN(add_thread_stmt_, db_.get_statement("INSERT OR REPLACE INTO threads VALUES(?1, ?2, ?3, ?4)"));
|
||||
TRY_RESULT_ASSIGN(delete_thread_stmt_,
|
||||
db_.get_statement("DELETE FROM threads WHERE dialog_id = ?1 AND thread_id = ?2"));
|
||||
TRY_RESULT_ASSIGN(delete_all_dialog_threads_stmt_, db_.get_statement("DELETE FROM threads WHERE dialog_id = ?1"));
|
||||
TRY_RESULT_ASSIGN(get_thread_stmt_,
|
||||
db_.get_statement("SELECT data FROM threads WHERE dialog_id = ?1 AND thread_id = ?2"));
|
||||
TRY_RESULT_ASSIGN(get_threads_stmt_,
|
||||
db_.get_statement("SELECT data, dialog_id, thread_id, thread_order FROM threads WHERE dialog_id "
|
||||
"= ?1 AND thread_order < ?2 ORDER BY thread_order DESC LIMIT ?3"));
|
||||
|
||||
// LOG(ERROR) << delete_thread_stmt_.explain().ok();
|
||||
// LOG(ERROR) << delete_all_dialog_threads_stmt_.explain().ok();
|
||||
// LOG(ERROR) << get_thread_stmt_.explain().ok();
|
||||
// LOG(ERROR) << get_threads_stmt_.explain().ok();
|
||||
// LOG(FATAL) << "EXPLAINED";
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void add_message_thread(DialogId dialog_id, MessageId top_thread_message_id, int64 order, BufferSlice data) final {
|
||||
SCOPE_EXIT {
|
||||
add_thread_stmt_.reset();
|
||||
};
|
||||
add_thread_stmt_.bind_int64(1, dialog_id.get()).ensure();
|
||||
add_thread_stmt_.bind_int64(2, top_thread_message_id.get()).ensure();
|
||||
add_thread_stmt_.bind_int64(3, order).ensure();
|
||||
add_thread_stmt_.bind_blob(4, data.as_slice()).ensure();
|
||||
add_thread_stmt_.step().ensure();
|
||||
}
|
||||
|
||||
void delete_message_thread(DialogId dialog_id, MessageId top_thread_message_id) final {
|
||||
SCOPE_EXIT {
|
||||
delete_thread_stmt_.reset();
|
||||
};
|
||||
delete_thread_stmt_.bind_int64(1, dialog_id.get()).ensure();
|
||||
delete_thread_stmt_.bind_int64(2, top_thread_message_id.get()).ensure();
|
||||
delete_thread_stmt_.step().ensure();
|
||||
}
|
||||
|
||||
void delete_all_dialog_message_threads(DialogId dialog_id) final {
|
||||
SCOPE_EXIT {
|
||||
delete_all_dialog_threads_stmt_.reset();
|
||||
};
|
||||
delete_all_dialog_threads_stmt_.bind_int64(1, dialog_id.get()).ensure();
|
||||
delete_all_dialog_threads_stmt_.step().ensure();
|
||||
}
|
||||
|
||||
BufferSlice get_message_thread(DialogId dialog_id, MessageId top_thread_message_id) final {
|
||||
SCOPE_EXIT {
|
||||
get_thread_stmt_.reset();
|
||||
};
|
||||
|
||||
get_thread_stmt_.bind_int64(1, dialog_id.get()).ensure();
|
||||
get_thread_stmt_.bind_int64(2, top_thread_message_id.get()).ensure();
|
||||
get_thread_stmt_.step().ensure();
|
||||
if (!get_thread_stmt_.has_row()) {
|
||||
return BufferSlice();
|
||||
}
|
||||
return BufferSlice(get_thread_stmt_.view_blob(0));
|
||||
}
|
||||
|
||||
MessageThreadDbMessageThreads get_message_threads(DialogId dialog_id, int64 offset_order, int32 limit) final {
|
||||
SCOPE_EXIT {
|
||||
get_threads_stmt_.reset();
|
||||
};
|
||||
|
||||
get_threads_stmt_.bind_int64(1, dialog_id.get()).ensure();
|
||||
get_threads_stmt_.bind_int64(2, offset_order).ensure();
|
||||
get_threads_stmt_.bind_int32(3, limit).ensure();
|
||||
|
||||
MessageThreadDbMessageThreads result;
|
||||
result.next_order = offset_order;
|
||||
get_threads_stmt_.step().ensure();
|
||||
while (get_threads_stmt_.has_row()) {
|
||||
BufferSlice data(get_threads_stmt_.view_blob(0));
|
||||
result.next_order = get_threads_stmt_.view_int64(3);
|
||||
LOG(INFO) << "Load thread of " << MessageId(get_threads_stmt_.view_int64(2)) << " in "
|
||||
<< DialogId(get_threads_stmt_.view_int64(1)) << " with order " << result.next_order;
|
||||
result.message_threads.emplace_back(std::move(data));
|
||||
get_threads_stmt_.step().ensure();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Status begin_write_transaction() final {
|
||||
return db_.begin_write_transaction();
|
||||
}
|
||||
|
||||
Status commit_transaction() final {
|
||||
return db_.commit_transaction();
|
||||
}
|
||||
|
||||
private:
|
||||
SqliteDb db_;
|
||||
|
||||
SqliteStatement add_thread_stmt_;
|
||||
SqliteStatement delete_thread_stmt_;
|
||||
SqliteStatement delete_all_dialog_threads_stmt_;
|
||||
SqliteStatement get_thread_stmt_;
|
||||
SqliteStatement get_threads_stmt_;
|
||||
};
|
||||
|
||||
std::shared_ptr<MessageThreadDbSyncSafeInterface> create_message_thread_db_sync(
|
||||
std::shared_ptr<SqliteConnectionSafe> sqlite_connection) {
|
||||
class MessageThreadDbSyncSafe final : public MessageThreadDbSyncSafeInterface {
|
||||
public:
|
||||
explicit MessageThreadDbSyncSafe(std::shared_ptr<SqliteConnectionSafe> sqlite_connection)
|
||||
: lsls_db_([safe_connection = std::move(sqlite_connection)] {
|
||||
return make_unique<MessageThreadDbImpl>(safe_connection->get().clone());
|
||||
}) {
|
||||
}
|
||||
MessageThreadDbSyncInterface &get() final {
|
||||
return *lsls_db_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
LazySchedulerLocalStorage<unique_ptr<MessageThreadDbSyncInterface>> lsls_db_;
|
||||
};
|
||||
return std::make_shared<MessageThreadDbSyncSafe>(std::move(sqlite_connection));
|
||||
}
|
||||
|
||||
class MessageThreadDbAsync final : public MessageThreadDbAsyncInterface {
|
||||
public:
|
||||
MessageThreadDbAsync(std::shared_ptr<MessageThreadDbSyncSafeInterface> sync_db, int32 scheduler_id) {
|
||||
impl_ = create_actor_on_scheduler<Impl>("MessageThreadDbActor", scheduler_id, std::move(sync_db));
|
||||
}
|
||||
|
||||
void add_message_thread(DialogId dialog_id, MessageId top_thread_message_id, int64 order, BufferSlice data,
|
||||
Promise<Unit> promise) final {
|
||||
send_closure(impl_, &Impl::add_message_thread, dialog_id, top_thread_message_id, order, std::move(data),
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void delete_message_thread(DialogId dialog_id, MessageId top_thread_message_id, Promise<Unit> promise) final {
|
||||
send_closure(impl_, &Impl::delete_message_thread, dialog_id, top_thread_message_id, std::move(promise));
|
||||
}
|
||||
|
||||
void delete_all_dialog_message_threads(DialogId dialog_id, Promise<Unit> promise) final {
|
||||
send_closure(impl_, &Impl::delete_all_dialog_message_threads, dialog_id, std::move(promise));
|
||||
}
|
||||
|
||||
void get_message_thread(DialogId dialog_id, MessageId top_thread_message_id, Promise<BufferSlice> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_message_thread, dialog_id, top_thread_message_id, std::move(promise));
|
||||
}
|
||||
|
||||
void get_message_threads(DialogId dialog_id, int64 offset_order, int32 limit,
|
||||
Promise<MessageThreadDbMessageThreads> promise) final {
|
||||
send_closure_later(impl_, &Impl::get_message_threads, dialog_id, offset_order, limit, std::move(promise));
|
||||
}
|
||||
|
||||
void close(Promise<Unit> promise) final {
|
||||
send_closure_later(impl_, &Impl::close, std::move(promise));
|
||||
}
|
||||
|
||||
void force_flush() final {
|
||||
send_closure_later(impl_, &Impl::force_flush);
|
||||
}
|
||||
|
||||
private:
|
||||
class Impl final : public Actor {
|
||||
public:
|
||||
explicit Impl(std::shared_ptr<MessageThreadDbSyncSafeInterface> sync_db_safe)
|
||||
: sync_db_safe_(std::move(sync_db_safe)) {
|
||||
}
|
||||
|
||||
void add_message_thread(DialogId dialog_id, MessageId top_thread_message_id, int64 order, BufferSlice data,
|
||||
Promise<Unit> promise) {
|
||||
add_write_query([this, dialog_id, top_thread_message_id, order, data = std::move(data),
|
||||
promise = std::move(promise)](Unit) mutable {
|
||||
sync_db_->add_message_thread(dialog_id, top_thread_message_id, order, std::move(data));
|
||||
on_write_result(std::move(promise));
|
||||
});
|
||||
}
|
||||
|
||||
void delete_message_thread(DialogId dialog_id, MessageId top_thread_message_id, Promise<Unit> promise) {
|
||||
add_write_query([this, dialog_id, top_thread_message_id, promise = std::move(promise)](Unit) mutable {
|
||||
sync_db_->delete_message_thread(dialog_id, top_thread_message_id);
|
||||
on_write_result(std::move(promise));
|
||||
});
|
||||
}
|
||||
|
||||
void delete_all_dialog_message_threads(DialogId dialog_id, Promise<Unit> promise) {
|
||||
add_write_query([this, dialog_id, promise = std::move(promise)](Unit) mutable {
|
||||
sync_db_->delete_all_dialog_message_threads(dialog_id);
|
||||
on_write_result(std::move(promise));
|
||||
});
|
||||
}
|
||||
|
||||
void on_write_result(Promise<Unit> &&promise) {
|
||||
// We are inside a transaction and don't know how to handle errors
|
||||
finished_writes_.push_back(std::move(promise));
|
||||
}
|
||||
|
||||
void get_message_thread(DialogId dialog_id, MessageId top_thread_message_id, Promise<BufferSlice> promise) {
|
||||
add_read_query();
|
||||
promise.set_result(sync_db_->get_message_thread(dialog_id, top_thread_message_id));
|
||||
}
|
||||
|
||||
void get_message_threads(DialogId dialog_id, int64 offset_order, int32 limit,
|
||||
Promise<MessageThreadDbMessageThreads> promise) {
|
||||
add_read_query();
|
||||
promise.set_result(sync_db_->get_message_threads(dialog_id, offset_order, limit));
|
||||
}
|
||||
|
||||
void close(Promise<> promise) {
|
||||
do_flush();
|
||||
sync_db_safe_.reset();
|
||||
sync_db_ = nullptr;
|
||||
promise.set_value(Unit());
|
||||
stop();
|
||||
}
|
||||
|
||||
void force_flush() {
|
||||
do_flush();
|
||||
LOG(INFO) << "MessageThreadDb flushed";
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<MessageThreadDbSyncSafeInterface> sync_db_safe_;
|
||||
MessageThreadDbSyncInterface *sync_db_ = nullptr;
|
||||
|
||||
static constexpr size_t MAX_PENDING_QUERIES_COUNT{50};
|
||||
static constexpr double MAX_PENDING_QUERIES_DELAY{0.01};
|
||||
|
||||
//NB: order is important, destructor of pending_writes_ will change finished_writes_
|
||||
vector<Promise<Unit>> finished_writes_;
|
||||
vector<Promise<Unit>> pending_writes_; // TODO use Action
|
||||
double wakeup_at_ = 0;
|
||||
|
||||
template <class F>
|
||||
void add_write_query(F &&f) {
|
||||
pending_writes_.push_back(PromiseCreator::lambda(std::forward<F>(f)));
|
||||
if (pending_writes_.size() > MAX_PENDING_QUERIES_COUNT) {
|
||||
do_flush();
|
||||
wakeup_at_ = 0;
|
||||
} else if (wakeup_at_ == 0) {
|
||||
wakeup_at_ = Time::now_cached() + MAX_PENDING_QUERIES_DELAY;
|
||||
}
|
||||
if (wakeup_at_ != 0) {
|
||||
set_timeout_at(wakeup_at_);
|
||||
}
|
||||
}
|
||||
|
||||
void add_read_query() {
|
||||
do_flush();
|
||||
}
|
||||
|
||||
void do_flush() {
|
||||
if (pending_writes_.empty()) {
|
||||
return;
|
||||
}
|
||||
sync_db_->begin_write_transaction().ensure();
|
||||
set_promises(pending_writes_);
|
||||
sync_db_->commit_transaction().ensure();
|
||||
set_promises(finished_writes_);
|
||||
cancel_timeout();
|
||||
}
|
||||
|
||||
void timeout_expired() final {
|
||||
do_flush();
|
||||
}
|
||||
|
||||
void start_up() final {
|
||||
sync_db_ = &sync_db_safe_->get();
|
||||
}
|
||||
};
|
||||
ActorOwn<Impl> impl_;
|
||||
};
|
||||
|
||||
std::shared_ptr<MessageThreadDbAsyncInterface> create_message_thread_db_async(
|
||||
std::shared_ptr<MessageThreadDbSyncSafeInterface> sync_db, int32 scheduler_id) {
|
||||
return std::make_shared<MessageThreadDbAsync>(std::move(sync_db), scheduler_id);
|
||||
}
|
||||
|
||||
} // namespace td
|
98
td/telegram/MessageThreadDb.h
Normal file
98
td/telegram/MessageThreadDb.h
Normal file
@ -0,0 +1,98 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/DialogId.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace td {
|
||||
|
||||
class SqliteConnectionSafe;
|
||||
class SqliteDb;
|
||||
|
||||
struct MessageThreadDbMessageThreads {
|
||||
vector<BufferSlice> message_threads;
|
||||
int64 next_order = 0;
|
||||
};
|
||||
|
||||
class MessageThreadDbSyncInterface {
|
||||
public:
|
||||
MessageThreadDbSyncInterface() = default;
|
||||
MessageThreadDbSyncInterface(const MessageThreadDbSyncInterface &) = delete;
|
||||
MessageThreadDbSyncInterface &operator=(const MessageThreadDbSyncInterface &) = delete;
|
||||
virtual ~MessageThreadDbSyncInterface() = default;
|
||||
|
||||
virtual void add_message_thread(DialogId dialog_id, MessageId top_thread_message_id, int64 order,
|
||||
BufferSlice data) = 0;
|
||||
|
||||
virtual void delete_message_thread(DialogId dialog_id, MessageId top_thread_message_id) = 0;
|
||||
|
||||
virtual void delete_all_dialog_message_threads(DialogId dialog_id) = 0;
|
||||
|
||||
virtual BufferSlice get_message_thread(DialogId dialog_id, MessageId top_thread_message_id) = 0;
|
||||
|
||||
virtual MessageThreadDbMessageThreads get_message_threads(DialogId dialog_id, int64 offset_order, int32 limit) = 0;
|
||||
|
||||
virtual Status begin_write_transaction() = 0;
|
||||
|
||||
virtual Status commit_transaction() = 0;
|
||||
};
|
||||
|
||||
class MessageThreadDbSyncSafeInterface {
|
||||
public:
|
||||
MessageThreadDbSyncSafeInterface() = default;
|
||||
MessageThreadDbSyncSafeInterface(const MessageThreadDbSyncSafeInterface &) = delete;
|
||||
MessageThreadDbSyncSafeInterface &operator=(const MessageThreadDbSyncSafeInterface &) = delete;
|
||||
virtual ~MessageThreadDbSyncSafeInterface() = default;
|
||||
|
||||
virtual MessageThreadDbSyncInterface &get() = 0;
|
||||
};
|
||||
|
||||
class MessageThreadDbAsyncInterface {
|
||||
public:
|
||||
MessageThreadDbAsyncInterface() = default;
|
||||
MessageThreadDbAsyncInterface(const MessageThreadDbAsyncInterface &) = delete;
|
||||
MessageThreadDbAsyncInterface &operator=(const MessageThreadDbAsyncInterface &) = delete;
|
||||
virtual ~MessageThreadDbAsyncInterface() = default;
|
||||
|
||||
virtual void add_message_thread(DialogId dialog_id, MessageId top_thread_message_id, int64 order, BufferSlice data,
|
||||
Promise<Unit> promise) = 0;
|
||||
|
||||
virtual void delete_message_thread(DialogId dialog_id, MessageId top_thread_message_id, Promise<Unit> promise) = 0;
|
||||
|
||||
virtual void delete_all_dialog_message_threads(DialogId dialog_id, Promise<Unit> promise) = 0;
|
||||
|
||||
virtual void get_message_thread(DialogId dialog_id, MessageId top_thread_message_id,
|
||||
Promise<BufferSlice> promise) = 0;
|
||||
|
||||
virtual void get_message_threads(DialogId dialog_id, int64 offset_order, int32 limit,
|
||||
Promise<MessageThreadDbMessageThreads> promise) = 0;
|
||||
|
||||
virtual void close(Promise<Unit> promise) = 0;
|
||||
|
||||
virtual void force_flush() = 0;
|
||||
};
|
||||
|
||||
Status init_message_thread_db(SqliteDb &db, int version) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
Status drop_message_thread_db(SqliteDb &db, int version) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
std::shared_ptr<MessageThreadDbSyncSafeInterface> create_message_thread_db_sync(
|
||||
std::shared_ptr<SqliteConnectionSafe> sqlite_connection);
|
||||
|
||||
std::shared_ptr<MessageThreadDbAsyncInterface> create_message_thread_db_async(
|
||||
std::shared_ptr<MessageThreadDbSyncSafeInterface> sync_db, int32 scheduler_id = -1);
|
||||
|
||||
} // namespace td
|
File diff suppressed because it is too large
Load Diff
@ -31,11 +31,11 @@
|
||||
#include "td/telegram/logevent/LogEventHelper.h"
|
||||
#include "td/telegram/MessageContentType.h"
|
||||
#include "td/telegram/MessageCopyOptions.h"
|
||||
#include "td/telegram/MessageDb.h"
|
||||
#include "td/telegram/MessageId.h"
|
||||
#include "td/telegram/MessageLinkInfo.h"
|
||||
#include "td/telegram/MessageReplyHeader.h"
|
||||
#include "td/telegram/MessageReplyInfo.h"
|
||||
#include "td/telegram/MessagesDb.h"
|
||||
#include "td/telegram/MessageSearchFilter.h"
|
||||
#include "td/telegram/MessageThreadInfo.h"
|
||||
#include "td/telegram/MessageTtl.h"
|
||||
@ -73,6 +73,7 @@
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/FlatHashSet.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/Heap.h"
|
||||
#include "td/utils/Hints.h"
|
||||
#include "td/utils/logging.h"
|
||||
@ -911,7 +912,7 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void after_get_difference();
|
||||
|
||||
bool on_get_dialog_error(DialogId dialog_id, const Status &status, const string &source);
|
||||
bool on_get_dialog_error(DialogId dialog_id, const Status &status, const char *source);
|
||||
|
||||
void on_send_message_get_quick_ack(int64 random_id);
|
||||
|
||||
@ -1208,6 +1209,7 @@ class MessagesManager final : public Actor {
|
||||
unique_ptr<DraftMessage> thread_draft_message;
|
||||
uint32 available_reactions_generation = 0;
|
||||
int32 interaction_info_update_date = 0;
|
||||
uint32 history_generation = 0;
|
||||
|
||||
int32 legacy_layer = 0;
|
||||
|
||||
@ -1301,7 +1303,7 @@ class MessagesManager final : public Actor {
|
||||
unique_ptr<DialogActionBar> action_bar;
|
||||
LogEventIdWithGeneration save_draft_message_log_event_id;
|
||||
LogEventIdWithGeneration save_notification_settings_log_event_id;
|
||||
std::unordered_map<int64, LogEventIdWithGeneration> read_history_log_event_ids;
|
||||
std::unordered_map<int64, LogEventIdWithGeneration, Hash<int64>> read_history_log_event_ids;
|
||||
std::unordered_set<MessageId, MessageIdHash> updated_read_history_message_ids;
|
||||
LogEventIdWithGeneration set_folder_id_log_event_id;
|
||||
InputGroupCallId active_group_call_id;
|
||||
@ -1314,6 +1316,7 @@ class MessagesManager final : public Actor {
|
||||
int32 have_full_history_source = 0;
|
||||
int32 unload_dialog_delay_seed = 0;
|
||||
int64 last_media_album_id = 0;
|
||||
uint32 history_generation = 0;
|
||||
|
||||
FolderId folder_id;
|
||||
vector<DialogListId> dialog_list_ids; // TODO replace with mask
|
||||
@ -1399,11 +1402,12 @@ class MessagesManager final : public Actor {
|
||||
bool suffix_load_done_ = false;
|
||||
bool suffix_load_has_query_ = false;
|
||||
|
||||
int32 pts = 0; // for channels only
|
||||
int32 pending_read_channel_inbox_pts = 0; // for channels only
|
||||
int32 pending_read_channel_inbox_server_unread_count = 0; // for channels only
|
||||
MessageId pending_read_channel_inbox_max_message_id; // for channels only
|
||||
std::unordered_map<int64, MessageId> random_id_to_message_id; // for secret chats and yet unsent messages only
|
||||
int32 pts = 0; // for channels only
|
||||
int32 pending_read_channel_inbox_pts = 0; // for channels only
|
||||
int32 pending_read_channel_inbox_server_unread_count = 0; // for channels only
|
||||
MessageId pending_read_channel_inbox_max_message_id; // for channels only
|
||||
std::unordered_map<int64, MessageId, Hash<int64>>
|
||||
random_id_to_message_id; // for secret chats and yet unsent messages only
|
||||
|
||||
MessageId last_assigned_message_id; // identifier of the last local or yet unsent message, assigned after
|
||||
// application start, used to guarantee that all assigned message identifiers
|
||||
@ -1812,7 +1816,8 @@ class MessagesManager final : public Actor {
|
||||
static constexpr size_t MAX_DIALOG_FILTER_TITLE_LENGTH = 12; // server side limit for dialog filter title
|
||||
static constexpr int32 MAX_PRIVATE_MESSAGE_TTL = 60; // server side limit
|
||||
static constexpr int32 DIALOG_FILTERS_CACHE_TIME = 86400;
|
||||
static constexpr size_t MIN_DELETED_ASYNCHRONOUSLY_MESSAGES = 10u;
|
||||
static constexpr size_t MIN_DELETED_ASYNCHRONOUSLY_MESSAGES = 10;
|
||||
static constexpr size_t MAX_UNLOADED_MESSAGES = 5000;
|
||||
|
||||
static constexpr int64 SPONSORED_DIALOG_ORDER = static_cast<int64>(2147483647) << 32;
|
||||
static constexpr int32 MIN_PINNED_DIALOG_DATE = 2147000000; // some big date
|
||||
@ -2304,7 +2309,7 @@ class MessagesManager final : public Actor {
|
||||
|
||||
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<MessagesDbDialogMessage> &&messages,
|
||||
bool from_the_end, bool only_local, vector<MessageDbDialogMessage> &&messages,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void get_history_from_the_end(DialogId dialog_id, bool from_database, bool only_local, Promise<Unit> &&promise);
|
||||
@ -2326,7 +2331,7 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void load_dialog_scheduled_messages(DialogId dialog_id, bool from_database, int64 hash, Promise<Unit> &&promise);
|
||||
|
||||
void on_get_scheduled_messages_from_database(DialogId dialog_id, vector<MessagesDbDialogMessage> &&messages);
|
||||
void on_get_scheduled_messages_from_database(DialogId dialog_id, vector<MessageDbDialogMessage> &&messages);
|
||||
|
||||
static int32 get_random_y(MessageId message_id);
|
||||
|
||||
@ -2477,7 +2482,7 @@ class MessagesManager final : public Actor {
|
||||
|
||||
vector<Notification> get_message_notifications_from_database_force(Dialog *d, bool from_mentions, int32 limit);
|
||||
|
||||
static vector<MessagesDbDialogMessage> do_get_message_notifications_from_database_force(
|
||||
static vector<MessageDbDialogMessage> do_get_message_notifications_from_database_force(
|
||||
Dialog *d, bool from_mentions, NotificationId from_notification_id, MessageId from_message_id, int32 limit);
|
||||
|
||||
void do_get_message_notifications_from_database(Dialog *d, bool from_mentions,
|
||||
@ -2487,11 +2492,11 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void on_get_message_notifications_from_database(DialogId dialog_id, bool from_mentions,
|
||||
NotificationId initial_from_notification_id, int32 limit,
|
||||
Result<vector<MessagesDbDialogMessage>> result,
|
||||
Result<vector<MessageDbDialogMessage>> result,
|
||||
Promise<vector<Notification>> promise);
|
||||
|
||||
void do_remove_message_notification(DialogId dialog_id, bool from_mentions, NotificationId notification_id,
|
||||
vector<MessagesDbDialogMessage> result);
|
||||
vector<MessageDbDialogMessage> result);
|
||||
|
||||
int32 get_dialog_pending_notification_count(const Dialog *d, bool from_mentions) const;
|
||||
|
||||
@ -2942,9 +2947,9 @@ class MessagesManager final : public Actor {
|
||||
void get_message_force_from_server(Dialog *d, MessageId message_id, Promise<Unit> &&promise,
|
||||
tl_object_ptr<telegram_api::InputMessage> input_message = nullptr);
|
||||
|
||||
Message *on_get_message_from_database(const MessagesDbMessage &message, bool is_scheduled, const char *source);
|
||||
Message *on_get_message_from_database(const MessageDbMessage &message, bool is_scheduled, const char *source);
|
||||
|
||||
Message *on_get_message_from_database(Dialog *d, const MessagesDbDialogMessage &message, bool is_scheduled,
|
||||
Message *on_get_message_from_database(Dialog *d, const MessageDbDialogMessage &message, bool is_scheduled,
|
||||
const char *source);
|
||||
|
||||
Message *on_get_message_from_database(Dialog *d, MessageId message_id, const BufferSlice &value, bool is_scheduled,
|
||||
@ -2954,7 +2959,7 @@ class MessagesManager final : public Actor {
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void on_get_dialog_message_by_date_from_database(DialogId dialog_id, int32 date, int64 random_id,
|
||||
Result<MessagesDbDialogMessage> result, Promise<Unit> promise);
|
||||
Result<MessageDbDialogMessage> result, Promise<Unit> promise);
|
||||
|
||||
std::pair<bool, int32> get_dialog_mute_until(DialogId dialog_id, const Dialog *d) const;
|
||||
|
||||
@ -2968,7 +2973,7 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void cancel_upload_message_content_files(const MessageContent *content);
|
||||
|
||||
static void cancel_upload_file(FileId file_id);
|
||||
static void cancel_upload_file(FileId file_id, const char *source);
|
||||
|
||||
void cancel_send_message_query(DialogId dialog_id, Message *m);
|
||||
|
||||
@ -3025,7 +3030,7 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void ttl_db_loop_start(double server_now);
|
||||
void ttl_db_loop(double server_now);
|
||||
void ttl_db_on_result(Result<std::pair<std::vector<MessagesDbMessage>, int32>> r_result, bool dummy);
|
||||
void ttl_db_on_result(Result<std::pair<std::vector<MessageDbMessage>, int32>> r_result, bool dummy);
|
||||
|
||||
void on_restore_missing_message_after_get_difference(FullMessageId full_message_id, MessageId old_message_id,
|
||||
Result<Unit> result);
|
||||
@ -3051,18 +3056,18 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void on_get_message_calendar_from_database(int64 random_id, DialogId dialog_id, MessageId from_message_id,
|
||||
MessageId first_db_message_id, MessageSearchFilter filter,
|
||||
Result<MessagesDbCalendar> r_calendar, Promise<Unit> promise);
|
||||
Result<MessageDbCalendar> r_calendar, Promise<Unit> promise);
|
||||
|
||||
void on_search_dialog_messages_db_result(int64 random_id, DialogId dialog_id, MessageId from_message_id,
|
||||
MessageId first_db_message_id, MessageSearchFilter filter, int32 offset,
|
||||
int32 limit, Result<vector<MessagesDbDialogMessage>> r_messages,
|
||||
Promise<Unit> promise);
|
||||
void on_search_dialog_message_db_result(int64 random_id, DialogId dialog_id, MessageId from_message_id,
|
||||
MessageId first_db_message_id, MessageSearchFilter filter, int32 offset,
|
||||
int32 limit, Result<vector<MessageDbDialogMessage>> r_messages,
|
||||
Promise<Unit> promise);
|
||||
|
||||
void on_messages_db_fts_result(Result<MessagesDbFtsResult> result, string offset, int32 limit, int64 random_id,
|
||||
Promise<Unit> &&promise);
|
||||
void on_message_db_fts_result(Result<MessageDbFtsResult> result, string offset, int32 limit, int64 random_id,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void on_messages_db_calls_result(Result<MessagesDbCallsResult> result, int64 random_id, MessageId first_db_message_id,
|
||||
MessageSearchFilter filter, Promise<Unit> &&promise);
|
||||
void on_message_db_calls_result(Result<MessageDbCallsResult> result, int64 random_id, MessageId first_db_message_id,
|
||||
MessageSearchFilter filter, Promise<Unit> &&promise);
|
||||
|
||||
void on_load_active_live_location_full_message_ids_from_database(string value);
|
||||
|
||||
@ -3178,10 +3183,11 @@ class MessagesManager final : public Actor {
|
||||
|
||||
void on_channel_get_difference_timeout(DialogId dialog_id);
|
||||
|
||||
void get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source);
|
||||
void get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source, bool is_old = false);
|
||||
|
||||
void do_get_channel_difference(DialogId dialog_id, int32 pts, bool force,
|
||||
tl_object_ptr<telegram_api::InputChannel> &&input_channel, const char *source);
|
||||
tl_object_ptr<telegram_api::InputChannel> &&input_channel, bool is_old,
|
||||
const char *source);
|
||||
|
||||
void process_get_channel_difference_updates(DialogId dialog_id, int32 new_pts,
|
||||
vector<tl_object_ptr<telegram_api::Message>> &&new_messages,
|
||||
@ -3437,8 +3443,8 @@ class MessagesManager final : public Actor {
|
||||
}
|
||||
};
|
||||
struct TtlNodeHash {
|
||||
std::size_t operator()(const TtlNode &ttl_node) const {
|
||||
return FullMessageIdHash()(ttl_node.full_message_id_) * 2 + static_cast<size_t>(ttl_node.by_ttl_period_);
|
||||
uint32 operator()(const TtlNode &ttl_node) const {
|
||||
return FullMessageIdHash()(ttl_node.full_message_id_) * 2 + static_cast<uint32>(ttl_node.by_ttl_period_);
|
||||
}
|
||||
};
|
||||
std::unordered_set<TtlNode, TtlNodeHash> ttl_nodes_;
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -55,8 +55,8 @@ class NotificationGroupId {
|
||||
};
|
||||
|
||||
struct NotificationGroupIdHash {
|
||||
std::size_t operator()(NotificationGroupId group_id) const {
|
||||
return std::hash<int32>()(group_id.get());
|
||||
uint32 operator()(NotificationGroupId group_id) const {
|
||||
return Hash<int32>()(group_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
@ -60,8 +60,8 @@ class NotificationId {
|
||||
};
|
||||
|
||||
struct NotificationIdHash {
|
||||
std::size_t operator()(NotificationId notification_id) const {
|
||||
return std::hash<int32>()(notification_id.get());
|
||||
uint32 operator()(NotificationId notification_id) const {
|
||||
return Hash<int32>()(notification_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -934,7 +934,7 @@ void NotificationSettingsManager::add_saved_ringtone(td_api::object_ptr<td_api::
|
||||
return;
|
||||
}
|
||||
|
||||
auto download_file_id = td_->file_manager_->dup_file_id(file_id);
|
||||
auto download_file_id = td_->file_manager_->dup_file_id(file_id, "add_saved_ringtone");
|
||||
file_id = td_->file_manager_
|
||||
->register_generate(FileType::Ringtone, FileLocationSource::FromServer, file_view.suggested_path(),
|
||||
PSTRING() << "#file_id#" << download_file_id.get(), DialogId(), file_view.size())
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -43,8 +43,8 @@ class PollId {
|
||||
};
|
||||
|
||||
struct PollIdHash {
|
||||
std::size_t operator()(PollId poll_id) const {
|
||||
return std::hash<int64>()(poll_id.get());
|
||||
uint32 operator()(PollId poll_id) const {
|
||||
return Hash<int64>()(poll_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -303,32 +303,23 @@ bool PollManager::is_local_poll_id(PollId poll_id) {
|
||||
}
|
||||
|
||||
const PollManager::Poll *PollManager::get_poll(PollId poll_id) const {
|
||||
auto p = polls_.find(poll_id);
|
||||
if (p == polls_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return p->second.get();
|
||||
}
|
||||
return polls_.get_pointer(poll_id);
|
||||
}
|
||||
|
||||
const PollManager::Poll *PollManager::get_poll(PollId poll_id) {
|
||||
auto p = polls_.find(poll_id);
|
||||
if (p == polls_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
auto p = polls_.get_pointer(poll_id);
|
||||
if (p != nullptr) {
|
||||
schedule_poll_unload(poll_id);
|
||||
return p->second.get();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
PollManager::Poll *PollManager::get_poll_editable(PollId poll_id) {
|
||||
auto p = polls_.find(poll_id);
|
||||
if (p == polls_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
auto p = polls_.get_pointer(poll_id);
|
||||
if (p != nullptr) {
|
||||
schedule_poll_unload(poll_id);
|
||||
return p->second.get();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
bool PollManager::have_poll(PollId poll_id) const {
|
||||
@ -336,18 +327,20 @@ bool PollManager::have_poll(PollId poll_id) const {
|
||||
}
|
||||
|
||||
void PollManager::notify_on_poll_update(PollId poll_id) {
|
||||
auto server_it = server_poll_messages_.find(poll_id);
|
||||
if (server_it != server_poll_messages_.end()) {
|
||||
for (const auto &full_message_id : server_it->second) {
|
||||
td_->messages_manager_->on_external_update_message_content(full_message_id);
|
||||
}
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto other_it = other_poll_messages_.find(poll_id);
|
||||
if (other_it != other_poll_messages_.end()) {
|
||||
for (const auto &full_message_id : other_it->second) {
|
||||
if (server_poll_messages_.count(poll_id) > 0) {
|
||||
server_poll_messages_[poll_id].foreach([&](const FullMessageId &full_message_id) {
|
||||
td_->messages_manager_->on_external_update_message_content(full_message_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (other_poll_messages_.count(poll_id) > 0) {
|
||||
other_poll_messages_[poll_id].foreach([&](const FullMessageId &full_message_id) {
|
||||
td_->messages_manager_->on_external_update_message_content(full_message_id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -647,22 +640,19 @@ PollId PollManager::create_poll(string &&question, vector<string> &&options, boo
|
||||
|
||||
PollId poll_id(--current_local_poll_id_);
|
||||
CHECK(is_local_poll_id(poll_id));
|
||||
bool is_inserted = polls_.emplace(poll_id, std::move(poll)).second;
|
||||
CHECK(is_inserted);
|
||||
polls_.set(poll_id, std::move(poll));
|
||||
return poll_id;
|
||||
}
|
||||
|
||||
void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id, const char *source) {
|
||||
CHECK(have_poll(poll_id));
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
|
||||
bool is_inserted = other_poll_messages_[poll_id].insert(full_message_id).second;
|
||||
LOG_CHECK(is_inserted) << source << ' ' << poll_id << ' ' << full_message_id;
|
||||
other_poll_messages_[poll_id].insert(full_message_id);
|
||||
unload_poll_timeout_.cancel_timeout(poll_id.get());
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Register " << poll_id << " from " << full_message_id << " from " << source;
|
||||
bool is_inserted = server_poll_messages_[poll_id].insert(full_message_id).second;
|
||||
LOG_CHECK(is_inserted) << source << ' ' << poll_id << ' ' << full_message_id;
|
||||
server_poll_messages_[poll_id].insert(full_message_id);
|
||||
auto poll = get_poll(poll_id);
|
||||
CHECK(poll != nullptr);
|
||||
if (!td_->auth_manager_->is_bot() && !is_local_poll_id(poll_id) &&
|
||||
@ -777,7 +767,7 @@ void PollManager::set_poll_answer(PollId poll_id, FullMessageId full_message_id,
|
||||
return promise.set_error(Status::Error(400, "Can't revote in a quiz"));
|
||||
}
|
||||
|
||||
FlatHashMap<size_t, int> affected_option_ids;
|
||||
FlatHashMap<uint64, int> affected_option_ids;
|
||||
vector<string> options;
|
||||
for (auto &option_id : option_ids) {
|
||||
auto index = static_cast<size_t>(option_id);
|
||||
@ -798,7 +788,7 @@ void PollManager::set_poll_answer(PollId poll_id, FullMessageId full_message_id,
|
||||
}
|
||||
for (const auto &it : affected_option_ids) {
|
||||
if (it.second == 1) {
|
||||
invalidate_poll_option_voters(poll, poll_id, it.first - 1);
|
||||
invalidate_poll_option_voters(poll, poll_id, static_cast<size_t>(it.first - 1));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1216,23 +1206,27 @@ void PollManager::do_stop_poll(PollId poll_id, FullMessageId full_message_id, un
|
||||
|
||||
bool is_inserted = being_closed_polls_.insert(poll_id).second;
|
||||
CHECK(is_inserted);
|
||||
auto new_promise = PromiseCreator::lambda(
|
||||
[actor_id = actor_id(this), poll_id, log_event_id, promise = std::move(promise)](Result<Unit> result) mutable {
|
||||
send_closure(actor_id, &PollManager::on_stop_poll_finished, poll_id, log_event_id, std::move(result),
|
||||
std::move(promise));
|
||||
});
|
||||
auto new_promise = PromiseCreator::lambda([actor_id = actor_id(this), poll_id, full_message_id, log_event_id,
|
||||
promise = std::move(promise)](Result<Unit> result) mutable {
|
||||
send_closure(actor_id, &PollManager::on_stop_poll_finished, poll_id, full_message_id, log_event_id,
|
||||
std::move(result), std::move(promise));
|
||||
});
|
||||
|
||||
td_->create_handler<StopPollQuery>(std::move(new_promise))->send(full_message_id, std::move(reply_markup), poll_id);
|
||||
}
|
||||
|
||||
void PollManager::on_stop_poll_finished(PollId poll_id, uint64 log_event_id, Result<Unit> &&result,
|
||||
Promise<Unit> &&promise) {
|
||||
void PollManager::on_stop_poll_finished(PollId poll_id, FullMessageId full_message_id, uint64 log_event_id,
|
||||
Result<Unit> &&result, Promise<Unit> &&promise) {
|
||||
being_closed_polls_.erase(poll_id);
|
||||
|
||||
if (log_event_id != 0 && !G()->close_flag()) {
|
||||
binlog_erase(G()->td_db()->get_binlog(), log_event_id);
|
||||
}
|
||||
|
||||
if (td_->auth_manager_->is_bot()) {
|
||||
td_->messages_manager_->on_external_update_message_content(full_message_id);
|
||||
}
|
||||
|
||||
promise.set_result(std::move(result));
|
||||
}
|
||||
|
||||
@ -1269,12 +1263,11 @@ void PollManager::on_update_poll_timeout(PollId poll_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = server_poll_messages_.find(poll_id);
|
||||
if (it == server_poll_messages_.end()) {
|
||||
if (server_poll_messages_.count(poll_id) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto full_message_id = *it->second.begin();
|
||||
auto full_message_id = server_poll_messages_[poll_id].get_random();
|
||||
LOG(INFO) << "Fetching results of " << poll_id << " from " << full_message_id;
|
||||
auto query_promise = PromiseCreator::lambda([poll_id, generation = current_generation_, actor_id = actor_id(this)](
|
||||
Result<tl_object_ptr<telegram_api::Updates>> &&result) {
|
||||
@ -1383,14 +1376,13 @@ void PollManager::on_online() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &it : server_poll_messages_) {
|
||||
auto poll_id = it.first;
|
||||
server_poll_messages_.foreach([&](const PollId &poll_id, WaitFreeHashSet<FullMessageId, FullMessageIdHash> &) {
|
||||
if (update_poll_timeout_.has_timeout(poll_id.get())) {
|
||||
auto timeout = Random::fast(3, 30);
|
||||
LOG(INFO) << "Schedule updating of " << poll_id << " in " << timeout;
|
||||
update_poll_timeout_.set_timeout_in(poll_id.get(), timeout);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
PollId PollManager::dup_poll(PollId poll_id) {
|
||||
@ -1517,8 +1509,7 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
|
||||
|
||||
auto p = make_unique<Poll>();
|
||||
poll = p.get();
|
||||
bool is_inserted = polls_.emplace(poll_id, std::move(p)).second;
|
||||
CHECK(is_inserted);
|
||||
polls_.set(poll_id, std::move(p));
|
||||
}
|
||||
CHECK(poll != nullptr);
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "td/utils/FlatHashSet.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/WaitFreeHashMap.h"
|
||||
#include "td/utils/WaitFreeHashSet.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
@ -215,7 +217,8 @@ class PollManager final : public Actor {
|
||||
void do_stop_poll(PollId poll_id, FullMessageId full_message_id, unique_ptr<ReplyMarkup> &&reply_markup,
|
||||
uint64 log_event_id, Promise<Unit> &&promise);
|
||||
|
||||
void on_stop_poll_finished(PollId poll_id, uint64 log_event_id, Result<Unit> &&result, Promise<Unit> &&promise);
|
||||
void on_stop_poll_finished(PollId poll_id, FullMessageId full_message_id, uint64 log_event_id, Result<Unit> &&result,
|
||||
Promise<Unit> &&promise);
|
||||
|
||||
void forget_local_poll(PollId poll_id);
|
||||
|
||||
@ -225,10 +228,10 @@ class PollManager final : public Actor {
|
||||
|
||||
Td *td_;
|
||||
ActorShared<> parent_;
|
||||
FlatHashMap<PollId, unique_ptr<Poll>, PollIdHash> polls_;
|
||||
WaitFreeHashMap<PollId, unique_ptr<Poll>, PollIdHash> polls_;
|
||||
|
||||
FlatHashMap<PollId, FlatHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> server_poll_messages_;
|
||||
FlatHashMap<PollId, FlatHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> other_poll_messages_;
|
||||
WaitFreeHashMap<PollId, WaitFreeHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> server_poll_messages_;
|
||||
WaitFreeHashMap<PollId, WaitFreeHashSet<FullMessageId, FullMessageIdHash>, PollIdHash> other_poll_messages_;
|
||||
|
||||
struct PendingPollAnswer {
|
||||
vector<string> options_;
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -53,8 +53,8 @@ class ScheduledServerMessageId {
|
||||
};
|
||||
|
||||
struct ScheduledServerMessageIdHash {
|
||||
std::size_t operator()(ScheduledServerMessageId message_id) const {
|
||||
return std::hash<int32>()(message_id.get());
|
||||
uint32 operator()(ScheduledServerMessageId message_id) const {
|
||||
return Hash<int32>()(message_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -6,9 +6,10 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -54,8 +55,8 @@ class SecretChatId {
|
||||
};
|
||||
|
||||
struct SecretChatIdHash {
|
||||
std::size_t operator()(SecretChatId secret_chat_id) const {
|
||||
return std::hash<int32>()(secret_chat_id.get());
|
||||
uint32 operator()(SecretChatId secret_chat_id) const {
|
||||
return Hash<int32>()(secret_chat_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -546,7 +546,7 @@ void SetSecureValue::start_upload(FileManager *file_manager, FileId &file_id, Se
|
||||
bool force = false;
|
||||
if (info.file_id.empty()) {
|
||||
if (!file_view.is_encrypted_secure()) {
|
||||
auto download_file_id = file_manager->dup_file_id(file_id);
|
||||
auto download_file_id = file_manager->dup_file_id(file_id, "SetSecureValue");
|
||||
file_id =
|
||||
file_manager
|
||||
->register_generate(FileType::SecureEncrypted, FileLocationSource::FromServer, file_view.suggested_path(),
|
||||
@ -554,7 +554,7 @@ void SetSecureValue::start_upload(FileManager *file_manager, FileId &file_id, Se
|
||||
.ok();
|
||||
}
|
||||
|
||||
info.file_id = file_manager->dup_file_id(file_id);
|
||||
info.file_id = file_manager->dup_file_id(file_id, "SetSecureValue");
|
||||
} else {
|
||||
force = true;
|
||||
}
|
||||
@ -650,8 +650,7 @@ void SetSecureValue::merge(FileManager *file_manager, FileId file_id, EncryptedS
|
||||
LOG(ERROR) << "Hash mismatch";
|
||||
return;
|
||||
}
|
||||
auto r_file_id = file_manager->merge(encrypted_file.file.file_id, file_id);
|
||||
LOG_IF(ERROR, r_file_id.is_error()) << r_file_id.error();
|
||||
LOG_STATUS(file_manager->merge(encrypted_file.file.file_id, file_id));
|
||||
}
|
||||
|
||||
class DeleteSecureValue final : public NetQueryCallback {
|
||||
|
@ -9,8 +9,7 @@
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
|
||||
#include <functional>
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
@ -59,8 +58,8 @@ inline bool operator!=(const SpecialStickerSetType &lhs, const SpecialStickerSet
|
||||
}
|
||||
|
||||
struct SpecialStickerSetTypeHash {
|
||||
std::size_t operator()(SpecialStickerSetType type) const {
|
||||
return std::hash<string>()(type.type_);
|
||||
uint32 operator()(SpecialStickerSetType type) const {
|
||||
return Hash<string>()(type.type_);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -43,8 +43,8 @@ class StickerSetId {
|
||||
};
|
||||
|
||||
struct StickerSetIdHash {
|
||||
std::size_t operator()(StickerSetId sticker_set_id) const {
|
||||
return std::hash<int64>()(sticker_set_id.get());
|
||||
uint32 operator()(StickerSetId sticker_set_id) const {
|
||||
return Hash<int64>()(sticker_set_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3045,7 +3045,7 @@ FileId StickersManager::dup_sticker(FileId new_id, FileId old_id) {
|
||||
auto new_sticker = make_unique<Sticker>(*old_sticker);
|
||||
new_sticker->file_id_ = new_id;
|
||||
// there is no reason to dup m_thumbnail and premium_animation_file_id
|
||||
new_sticker->s_thumbnail_.file_id = td_->file_manager_->dup_file_id(new_sticker->s_thumbnail_.file_id);
|
||||
new_sticker->s_thumbnail_.file_id = td_->file_manager_->dup_file_id(new_sticker->s_thumbnail_.file_id, "dup_sticker");
|
||||
stickers_.set(new_id, std::move(new_sticker));
|
||||
return new_id;
|
||||
}
|
||||
@ -6520,7 +6520,7 @@ void StickersManager::schedule_update_animated_emoji_clicked(const StickerSet *s
|
||||
}
|
||||
|
||||
auto all_sticker_ids = get_animated_emoji_click_stickers(sticker_set, emoji);
|
||||
FlatHashMap<int, FileId> sticker_ids;
|
||||
FlatHashMap<int32, FileId> sticker_ids;
|
||||
for (auto sticker_id : all_sticker_ids) {
|
||||
auto it = sticker_set->sticker_emojis_map_.find(sticker_id);
|
||||
if (it != sticker_set->sticker_emojis_map_.end()) {
|
||||
@ -7643,10 +7643,11 @@ void StickersManager::upload_sticker_file(UserId user_id, FileId file_id, Promis
|
||||
FileId upload_file_id;
|
||||
if (td_->file_manager_->get_file_view(file_id).get_type() == FileType::Sticker) {
|
||||
CHECK(get_input_media(file_id, nullptr, nullptr, string()) == nullptr);
|
||||
upload_file_id = dup_sticker(td_->file_manager_->dup_file_id(file_id), file_id);
|
||||
upload_file_id = dup_sticker(td_->file_manager_->dup_file_id(file_id, "upload_sticker_file"), file_id);
|
||||
} else {
|
||||
CHECK(td_->documents_manager_->get_input_media(file_id, nullptr, nullptr) == nullptr);
|
||||
upload_file_id = td_->documents_manager_->dup_document(td_->file_manager_->dup_file_id(file_id), file_id);
|
||||
upload_file_id =
|
||||
td_->documents_manager_->dup_document(td_->file_manager_->dup_file_id(file_id, "upload_sticker_file"), file_id);
|
||||
}
|
||||
|
||||
CHECK(upload_file_id.is_valid());
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/FlatHashSet.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/Hints.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Slice.h"
|
||||
@ -1020,8 +1021,8 @@ class StickersManager final : public Actor {
|
||||
FlatHashMap<string, FoundStickers> found_stickers_;
|
||||
FlatHashMap<string, vector<std::pair<int32, Promise<td_api::object_ptr<td_api::stickers>>>>> search_stickers_queries_;
|
||||
|
||||
std::unordered_map<string, vector<StickerSetId>> found_sticker_sets_;
|
||||
std::unordered_map<string, vector<Promise<Unit>>> search_sticker_sets_queries_;
|
||||
std::unordered_map<string, vector<StickerSetId>, Hash<string>> found_sticker_sets_;
|
||||
std::unordered_map<string, vector<Promise<Unit>>, Hash<string>> search_sticker_sets_queries_;
|
||||
|
||||
FlatHashSet<StickerSetId, StickerSetIdHash> pending_viewed_featured_sticker_set_ids_;
|
||||
Timeout pending_featured_sticker_set_views_timeout_;
|
||||
|
@ -2551,33 +2551,6 @@ class SearchBackgroundRequest final : public RequestActor<> {
|
||||
}
|
||||
};
|
||||
|
||||
class SetBackgroundRequest final : public RequestActor<> {
|
||||
td_api::object_ptr<td_api::InputBackground> input_background_;
|
||||
td_api::object_ptr<td_api::BackgroundType> background_type_;
|
||||
bool for_dark_theme_ = false;
|
||||
|
||||
BackgroundId background_id_;
|
||||
|
||||
void do_run(Promise<Unit> &&promise) final {
|
||||
background_id_ = td_->background_manager_->set_background(input_background_.get(), background_type_.get(),
|
||||
for_dark_theme_, std::move(promise));
|
||||
}
|
||||
|
||||
void do_send_result() final {
|
||||
send_result(td_->background_manager_->get_background_object(background_id_, for_dark_theme_, nullptr));
|
||||
}
|
||||
|
||||
public:
|
||||
SetBackgroundRequest(ActorShared<Td> td, uint64 request_id,
|
||||
td_api::object_ptr<td_api::InputBackground> &&input_background,
|
||||
td_api::object_ptr<td_api::BackgroundType> background_type, bool for_dark_theme)
|
||||
: RequestActor(std::move(td), request_id)
|
||||
, input_background_(std::move(input_background))
|
||||
, background_type_(std::move(background_type))
|
||||
, for_dark_theme_(for_dark_theme) {
|
||||
}
|
||||
};
|
||||
|
||||
Td::Td(unique_ptr<TdCallback> callback, Options options)
|
||||
: callback_(std::move(callback)), td_options_(std::move(options)) {
|
||||
CHECK(callback_ != nullptr);
|
||||
@ -6612,7 +6585,7 @@ void Td::on_request(uint64 id, td_api::preliminaryUploadFile &request) {
|
||||
return send_error_raw(id, 400, r_file_id.error().message());
|
||||
}
|
||||
auto file_id = r_file_id.ok();
|
||||
auto upload_file_id = file_manager_->dup_file_id(file_id);
|
||||
auto upload_file_id = file_manager_->dup_file_id(file_id, "preliminaryUploadFile");
|
||||
|
||||
file_manager_->upload(upload_file_id, upload_file_callback_, priority, 0);
|
||||
|
||||
@ -7935,8 +7908,9 @@ void Td::on_request(uint64 id, td_api::searchBackground &request) {
|
||||
|
||||
void Td::on_request(uint64 id, td_api::setBackground &request) {
|
||||
CHECK_IS_USER();
|
||||
CREATE_REQUEST(SetBackgroundRequest, std::move(request.background_), std::move(request.type_),
|
||||
request.for_dark_theme_);
|
||||
CREATE_REQUEST_PROMISE();
|
||||
background_manager_->set_background(request.background_.get(), request.type_.get(), request.for_dark_theme_,
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::removeBackground &request) {
|
||||
|
@ -10,7 +10,8 @@
|
||||
#include "td/telegram/files/FileDb.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/MessagesDb.h"
|
||||
#include "td/telegram/MessageDb.h"
|
||||
#include "td/telegram/MessageThreadDb.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/TdParameters.h"
|
||||
#include "td/telegram/Version.h"
|
||||
@ -184,15 +185,26 @@ SqliteKeyValueAsyncInterface *TdDb::get_sqlite_pmc() {
|
||||
return common_kv_async_.get();
|
||||
}
|
||||
|
||||
MessagesDbSyncInterface *TdDb::get_messages_db_sync() {
|
||||
return &messages_db_sync_safe_->get();
|
||||
MessageDbSyncInterface *TdDb::get_message_db_sync() {
|
||||
return &message_db_sync_safe_->get();
|
||||
}
|
||||
MessagesDbAsyncInterface *TdDb::get_messages_db_async() {
|
||||
return messages_db_async_.get();
|
||||
|
||||
MessageDbAsyncInterface *TdDb::get_message_db_async() {
|
||||
return message_db_async_.get();
|
||||
}
|
||||
|
||||
MessageThreadDbSyncInterface *TdDb::get_message_thread_db_sync() {
|
||||
return &message_thread_db_sync_safe_->get();
|
||||
}
|
||||
|
||||
MessageThreadDbAsyncInterface *TdDb::get_message_thread_db_async() {
|
||||
return message_thread_db_async_.get();
|
||||
}
|
||||
|
||||
DialogDbSyncInterface *TdDb::get_dialog_db_sync() {
|
||||
return &dialog_db_sync_safe_->get();
|
||||
}
|
||||
|
||||
DialogDbAsyncInterface *TdDb::get_dialog_db_async() {
|
||||
return dialog_db_async_.get();
|
||||
}
|
||||
@ -206,8 +218,14 @@ CSlice TdDb::sqlite_path() const {
|
||||
|
||||
void TdDb::flush_all() {
|
||||
LOG(INFO) << "Flush all databases";
|
||||
if (messages_db_async_) {
|
||||
messages_db_async_->force_flush();
|
||||
if (message_db_async_) {
|
||||
message_db_async_->force_flush();
|
||||
}
|
||||
if (message_thread_db_async_) {
|
||||
message_thread_db_async_->force_flush();
|
||||
}
|
||||
if (dialog_db_async_) {
|
||||
dialog_db_async_->force_flush();
|
||||
}
|
||||
binlog_->force_flush();
|
||||
}
|
||||
@ -249,9 +267,14 @@ void TdDb::do_close(Promise<> on_finished, bool destroy_flag) {
|
||||
common_kv_async_->close(mpas.get_promise());
|
||||
}
|
||||
|
||||
messages_db_sync_safe_.reset();
|
||||
if (messages_db_async_) {
|
||||
messages_db_async_->close(mpas.get_promise());
|
||||
message_db_sync_safe_.reset();
|
||||
if (message_db_async_) {
|
||||
message_db_async_->close(mpas.get_promise());
|
||||
}
|
||||
|
||||
message_thread_db_sync_safe_.reset();
|
||||
if (message_thread_db_async_) {
|
||||
message_thread_db_async_->close(mpas.get_promise());
|
||||
}
|
||||
|
||||
dialog_db_sync_safe_.reset();
|
||||
@ -287,6 +310,7 @@ Status TdDb::init_sqlite(const TdParameters ¶meters, const DbKey &key, const
|
||||
bool use_sqlite = parameters.use_file_db;
|
||||
bool use_file_db = parameters.use_file_db;
|
||||
bool use_dialog_db = parameters.use_message_db;
|
||||
bool use_message_thread_db = parameters.use_message_db && false;
|
||||
bool use_message_db = parameters.use_message_db;
|
||||
if (!use_sqlite) {
|
||||
SqliteDb::destroy(sql_database_path).ignore();
|
||||
@ -328,11 +352,18 @@ Status TdDb::init_sqlite(const TdParameters ¶meters, const DbKey &key, const
|
||||
TRY_STATUS(drop_dialog_db(db, user_version));
|
||||
}
|
||||
|
||||
// init MessagesDb
|
||||
if (use_message_db) {
|
||||
TRY_STATUS(init_messages_db(db, user_version));
|
||||
// init MessageThreadDb
|
||||
if (use_message_thread_db) {
|
||||
TRY_STATUS(init_message_thread_db(db, user_version));
|
||||
} else {
|
||||
TRY_STATUS(drop_messages_db(db, user_version));
|
||||
TRY_STATUS(drop_message_thread_db(db, user_version));
|
||||
}
|
||||
|
||||
// init MessageDb
|
||||
if (use_message_db) {
|
||||
TRY_STATUS(init_message_db(db, user_version));
|
||||
} else {
|
||||
TRY_STATUS(drop_message_db(db, user_version));
|
||||
}
|
||||
|
||||
// init filesDb
|
||||
@ -379,9 +410,14 @@ Status TdDb::init_sqlite(const TdParameters ¶meters, const DbKey &key, const
|
||||
dialog_db_async_ = create_dialog_db_async(dialog_db_sync_safe_);
|
||||
}
|
||||
|
||||
if (use_message_thread_db) {
|
||||
message_thread_db_sync_safe_ = create_message_thread_db_sync(sql_connection_);
|
||||
message_thread_db_async_ = create_message_thread_db_async(message_thread_db_sync_safe_);
|
||||
}
|
||||
|
||||
if (use_message_db) {
|
||||
messages_db_sync_safe_ = create_messages_db_sync(sql_connection_);
|
||||
messages_db_async_ = create_messages_db_async(messages_db_sync_safe_);
|
||||
message_db_sync_safe_ = create_message_db_sync(sql_connection_);
|
||||
message_db_async_ = create_message_db_async(message_db_sync_safe_);
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
|
@ -30,9 +30,12 @@ class DialogDbSyncInterface;
|
||||
class DialogDbSyncSafeInterface;
|
||||
class DialogDbAsyncInterface;
|
||||
class FileDbInterface;
|
||||
class MessagesDbSyncInterface;
|
||||
class MessagesDbSyncSafeInterface;
|
||||
class MessagesDbAsyncInterface;
|
||||
class MessageDbSyncInterface;
|
||||
class MessageDbSyncSafeInterface;
|
||||
class MessageDbAsyncInterface;
|
||||
class MessageThreadDbSyncInterface;
|
||||
class MessageThreadDbSyncSafeInterface;
|
||||
class MessageThreadDbAsyncInterface;
|
||||
class SqliteConnectionSafe;
|
||||
class SqliteKeyValueSafe;
|
||||
class SqliteKeyValueAsyncInterface;
|
||||
@ -92,8 +95,11 @@ class TdDb {
|
||||
void close_all(Promise<> on_finished);
|
||||
void close_and_destroy_all(Promise<> on_finished);
|
||||
|
||||
MessagesDbSyncInterface *get_messages_db_sync();
|
||||
MessagesDbAsyncInterface *get_messages_db_async();
|
||||
MessageDbSyncInterface *get_message_db_sync();
|
||||
MessageDbAsyncInterface *get_message_db_async();
|
||||
|
||||
MessageThreadDbSyncInterface *get_message_thread_db_sync();
|
||||
MessageThreadDbAsyncInterface *get_message_thread_db_async();
|
||||
|
||||
DialogDbSyncInterface *get_dialog_db_sync();
|
||||
DialogDbAsyncInterface *get_dialog_db_async();
|
||||
@ -113,8 +119,11 @@ class TdDb {
|
||||
std::shared_ptr<SqliteKeyValueSafe> common_kv_safe_;
|
||||
unique_ptr<SqliteKeyValueAsyncInterface> common_kv_async_;
|
||||
|
||||
std::shared_ptr<MessagesDbSyncSafeInterface> messages_db_sync_safe_;
|
||||
std::shared_ptr<MessagesDbAsyncInterface> messages_db_async_;
|
||||
std::shared_ptr<MessageDbSyncSafeInterface> message_db_sync_safe_;
|
||||
std::shared_ptr<MessageDbAsyncInterface> message_db_async_;
|
||||
|
||||
std::shared_ptr<MessageThreadDbSyncSafeInterface> message_thread_db_sync_safe_;
|
||||
std::shared_ptr<MessageThreadDbAsyncInterface> message_thread_db_async_;
|
||||
|
||||
std::shared_ptr<DialogDbSyncSafeInterface> dialog_db_sync_safe_;
|
||||
std::shared_ptr<DialogDbAsyncInterface> dialog_db_async_;
|
||||
|
@ -177,9 +177,6 @@ class GetDifferenceQuery final : public Td::ResultHandler {
|
||||
}
|
||||
};
|
||||
|
||||
const double UpdatesManager::MAX_UNFILLED_GAP_TIME = 0.7;
|
||||
const double UpdatesManager::MAX_PTS_SAVE_DELAY = 0.05;
|
||||
|
||||
UpdatesManager::UpdatesManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
||||
last_pts_save_time_ = last_qts_save_time_ = Time::now() - 2 * MAX_PTS_SAVE_DELAY;
|
||||
|
||||
@ -482,7 +479,7 @@ Promise<> UpdatesManager::set_pts(int32 pts, const char *source) {
|
||||
Promise<> result;
|
||||
if (pts > get_pts() || (0 < pts && pts < get_pts() - 399999)) { // pts can only go up or drop cardinally
|
||||
if (pts < get_pts() - 399999) {
|
||||
LOG(WARNING) << "Pts decreases from " << get_pts() << " to " << pts << " from " << source;
|
||||
LOG(WARNING) << "PTS decreases from " << get_pts() << " to " << pts << " from " << source;
|
||||
} else {
|
||||
LOG(INFO) << "Update pts from " << get_pts() << " to " << pts << " from " << source;
|
||||
}
|
||||
@ -1691,7 +1688,7 @@ void UpdatesManager::after_get_difference() {
|
||||
}
|
||||
VLOG(get_difference) << "Finished to apply " << total_update_count << " postponed updates";
|
||||
auto passed_time = Time::now() - begin_time;
|
||||
if (passed_time >= 1.0) {
|
||||
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
|
||||
LOG(WARNING) << "Applied " << total_update_count << " postponed for "
|
||||
<< (Time::now() - get_difference_start_time_) << " updates in " << chunk_count << " chunks in "
|
||||
<< passed_time;
|
||||
@ -1716,7 +1713,7 @@ void UpdatesManager::after_get_difference() {
|
||||
<< ", max_pts = " << accumulated_pts_ << " and " << pending_pts_updates_.size() << " + "
|
||||
<< postponed_pts_updates_.size() << " pending pts updates";
|
||||
auto passed_time = Time::now() - begin_time;
|
||||
if (passed_time >= 1.0) {
|
||||
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
|
||||
LOG(WARNING) << "Applied " << update_count << " postponed for " << (Time::now() - get_difference_start_time_)
|
||||
<< " pts updates in " << passed_time;
|
||||
}
|
||||
@ -2328,7 +2325,8 @@ void UpdatesManager::add_pending_pts_update(tl_object_ptr<telegram_api::Update>
|
||||
if (new_pts < old_pts - 99 && source != AFTER_GET_DIFFERENCE_SOURCE) {
|
||||
bool need_restore_pts = new_pts < old_pts - 19999;
|
||||
auto now = Time::now();
|
||||
if (now > last_pts_jump_warning_time_ + 1 && (need_restore_pts || now < last_pts_jump_warning_time_ + 5)) {
|
||||
if (now > last_pts_jump_warning_time_ + 1 && (need_restore_pts || now < last_pts_jump_warning_time_ + 5) &&
|
||||
!(old_pts == std::numeric_limits<int32>::max() && running_get_difference_)) {
|
||||
LOG(ERROR) << "Restore pts after delete_first_messages from " << old_pts << " to " << new_pts
|
||||
<< " is disabled, pts_count = " << pts_count << ", update is from " << source << ": "
|
||||
<< oneline(to_string(update));
|
||||
@ -2608,14 +2606,14 @@ void UpdatesManager::process_postponed_pts_updates() {
|
||||
}
|
||||
CHECK(!running_get_difference_);
|
||||
if (skipped_update_count + applied_update_count > 0) {
|
||||
VLOG(get_difference) << "Pts has changed from " << initial_pts << " to " << old_pts << " after skipping "
|
||||
VLOG(get_difference) << "PTS has changed from " << initial_pts << " to " << old_pts << " after skipping "
|
||||
<< skipped_update_count << ", applying " << applied_update_count << " and keeping "
|
||||
<< postponed_pts_updates_.size() << " postponed updates";
|
||||
}
|
||||
|
||||
auto passed_time = Time::now() - begin_time;
|
||||
if (passed_time >= 1.0) {
|
||||
LOG(WARNING) << "Pts has changed from " << initial_pts << " to " << old_pts << " after skipping "
|
||||
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
|
||||
LOG(WARNING) << "PTS has changed from " << initial_pts << " to " << old_pts << " after skipping "
|
||||
<< skipped_update_count << ", applying " << applied_update_count << " and keeping "
|
||||
<< postponed_pts_updates_.size() << " postponed for " << (Time::now() - get_difference_start_time_)
|
||||
<< " updates in " << passed_time;
|
||||
@ -2627,7 +2625,9 @@ void UpdatesManager::process_pending_pts_updates() {
|
||||
return;
|
||||
}
|
||||
|
||||
bool processed_pending_update = false;
|
||||
auto begin_time = Time::now();
|
||||
auto initial_pts = get_pts();
|
||||
int32 applied_update_count = 0;
|
||||
while (!pending_pts_updates_.empty()) {
|
||||
auto update_it = pending_pts_updates_.begin();
|
||||
auto &update = update_it->second;
|
||||
@ -2636,7 +2636,7 @@ void UpdatesManager::process_pending_pts_updates() {
|
||||
break;
|
||||
}
|
||||
|
||||
processed_pending_update = true;
|
||||
applied_update_count++;
|
||||
if (update.pts_count > 0) {
|
||||
td_->messages_manager_->process_pts_update(std::move(update.update));
|
||||
set_pts(update.pts, "process_pending_pts_updates")
|
||||
@ -2651,7 +2651,7 @@ void UpdatesManager::process_pending_pts_updates() {
|
||||
update.promise.set_value(Unit());
|
||||
pending_pts_updates_.erase(update_it);
|
||||
}
|
||||
if (processed_pending_update) {
|
||||
if (applied_update_count > 0) {
|
||||
pts_gap_timeout_.cancel_timeout();
|
||||
}
|
||||
if (!pending_pts_updates_.empty()) {
|
||||
@ -2666,6 +2666,13 @@ void UpdatesManager::process_pending_pts_updates() {
|
||||
}
|
||||
set_pts_gap_timeout(receive_time + MAX_UNFILLED_GAP_TIME - Time::now());
|
||||
}
|
||||
|
||||
auto passed_time = Time::now() - begin_time;
|
||||
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
|
||||
LOG(WARNING) << "PTS has changed from " << initial_pts << " to " << get_pts() << " after applying "
|
||||
<< applied_update_count << " and keeping " << pending_pts_updates_.size() << " pending updates in "
|
||||
<< passed_time;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatesManager::process_pending_seq_updates() {
|
||||
@ -2674,7 +2681,9 @@ void UpdatesManager::process_pending_seq_updates() {
|
||||
// must not return, because in case of seq overflow there are no pending seq updates
|
||||
}
|
||||
|
||||
bool processed_pending_update = false;
|
||||
auto begin_time = Time::now();
|
||||
int32 initial_seq = seq_;
|
||||
int32 applied_update_count = 0;
|
||||
while (!pending_seq_updates_.empty() && !running_get_difference_) {
|
||||
auto update_it = pending_seq_updates_.begin();
|
||||
auto &update = update_it->second;
|
||||
@ -2684,7 +2693,7 @@ void UpdatesManager::process_pending_seq_updates() {
|
||||
break;
|
||||
}
|
||||
|
||||
processed_pending_update = true;
|
||||
applied_update_count++;
|
||||
auto seq_end = update.seq_end;
|
||||
if (seq_begin - 1 == seq_) {
|
||||
process_seq_updates(seq_end, update.date, std::move(update.updates), std::move(update.promise));
|
||||
@ -2699,7 +2708,7 @@ void UpdatesManager::process_pending_seq_updates() {
|
||||
}
|
||||
pending_seq_updates_.erase(update_it);
|
||||
}
|
||||
if (pending_seq_updates_.empty() || processed_pending_update) {
|
||||
if (pending_seq_updates_.empty() || applied_update_count > 0) {
|
||||
seq_gap_timeout_.cancel_timeout();
|
||||
}
|
||||
if (!pending_seq_updates_.empty()) {
|
||||
@ -2714,6 +2723,13 @@ void UpdatesManager::process_pending_seq_updates() {
|
||||
}
|
||||
set_seq_gap_timeout(receive_time + MAX_UNFILLED_GAP_TIME - Time::now());
|
||||
}
|
||||
|
||||
auto passed_time = Time::now() - begin_time;
|
||||
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
|
||||
LOG(WARNING) << "Seq has changed from " << initial_seq << " to " << seq_ << " after applying "
|
||||
<< applied_update_count << " and keeping " << pending_seq_updates_.size() << " pending updates in "
|
||||
<< passed_time;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatesManager::process_pending_qts_updates() {
|
||||
@ -2722,7 +2738,9 @@ void UpdatesManager::process_pending_qts_updates() {
|
||||
}
|
||||
|
||||
LOG(DEBUG) << "Process " << pending_qts_updates_.size() << " pending qts updates";
|
||||
bool processed_pending_update = false;
|
||||
auto begin_time = Time::now();
|
||||
auto initial_qts = get_qts();
|
||||
int32 applied_update_count = 0;
|
||||
while (!pending_qts_updates_.empty()) {
|
||||
CHECK(!running_get_difference_);
|
||||
auto update_it = pending_qts_updates_.begin();
|
||||
@ -2734,7 +2752,7 @@ void UpdatesManager::process_pending_qts_updates() {
|
||||
}
|
||||
auto promise = PromiseCreator::lambda(
|
||||
[promises = std::move(update_it->second.promises)](Unit) mutable { set_promises(promises); });
|
||||
processed_pending_update = true;
|
||||
applied_update_count++;
|
||||
if (qts == old_qts + 1) {
|
||||
process_qts_update(std::move(update_it->second.update), qts, std::move(promise));
|
||||
} else {
|
||||
@ -2743,7 +2761,7 @@ void UpdatesManager::process_pending_qts_updates() {
|
||||
pending_qts_updates_.erase(update_it);
|
||||
}
|
||||
|
||||
if (processed_pending_update) {
|
||||
if (applied_update_count > 0) {
|
||||
qts_gap_timeout_.cancel_timeout();
|
||||
}
|
||||
if (!pending_qts_updates_.empty()) {
|
||||
@ -2759,6 +2777,13 @@ void UpdatesManager::process_pending_qts_updates() {
|
||||
set_qts_gap_timeout(receive_time + MAX_UNFILLED_GAP_TIME - Time::now());
|
||||
}
|
||||
CHECK(!running_get_difference_);
|
||||
|
||||
auto passed_time = Time::now() - begin_time;
|
||||
if (passed_time >= UPDATE_APPLY_WARNING_TIME) {
|
||||
LOG(WARNING) << "QTS has changed from " << initial_qts << " to " << get_qts() << " after applying "
|
||||
<< applied_update_count << " and keeping " << pending_qts_updates_.size() << " pending updates in "
|
||||
<< passed_time;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatesManager::set_pts_gap_timeout(double timeout) {
|
||||
@ -2884,7 +2909,7 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelTooLong>
|
||||
}
|
||||
|
||||
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannel> update, Promise<Unit> &&promise) {
|
||||
td_->contacts_manager_->invalidate_channel_full(ChannelId(update->channel_id_), false);
|
||||
td_->contacts_manager_->invalidate_channel_full(ChannelId(update->channel_id_), false, "updateChannel");
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
@ -2939,22 +2964,32 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChannelAvailabl
|
||||
|
||||
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateReadChannelDiscussionInbox> update,
|
||||
Promise<Unit> &&promise) {
|
||||
td_->messages_manager_->on_update_read_message_comments(
|
||||
DialogId(ChannelId(update->channel_id_)), MessageId(ServerMessageId(update->top_msg_id_)), MessageId(),
|
||||
MessageId(ServerMessageId(update->read_max_id_)), MessageId());
|
||||
auto last_read_inbox_message_id = MessageId(ServerMessageId(update->read_max_id_));
|
||||
if (!last_read_inbox_message_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive " << to_string(update);
|
||||
return;
|
||||
}
|
||||
td_->messages_manager_->on_update_read_message_comments(DialogId(ChannelId(update->channel_id_)),
|
||||
MessageId(ServerMessageId(update->top_msg_id_)), MessageId(),
|
||||
last_read_inbox_message_id, MessageId());
|
||||
if ((update->flags_ & telegram_api::updateReadChannelDiscussionInbox::BROADCAST_ID_MASK) != 0) {
|
||||
td_->messages_manager_->on_update_read_message_comments(
|
||||
DialogId(ChannelId(update->broadcast_id_)), MessageId(ServerMessageId(update->broadcast_post_)), MessageId(),
|
||||
MessageId(ServerMessageId(update->read_max_id_)), MessageId());
|
||||
td_->messages_manager_->on_update_read_message_comments(DialogId(ChannelId(update->broadcast_id_)),
|
||||
MessageId(ServerMessageId(update->broadcast_post_)),
|
||||
MessageId(), last_read_inbox_message_id, MessageId());
|
||||
}
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateReadChannelDiscussionOutbox> update,
|
||||
Promise<Unit> &&promise) {
|
||||
td_->messages_manager_->on_update_read_message_comments(
|
||||
DialogId(ChannelId(update->channel_id_)), MessageId(ServerMessageId(update->top_msg_id_)), MessageId(),
|
||||
MessageId(), MessageId(ServerMessageId(update->read_max_id_)));
|
||||
auto last_read_outbox_message_id = MessageId(ServerMessageId(update->read_max_id_));
|
||||
if (!last_read_outbox_message_id.is_valid()) {
|
||||
LOG(ERROR) << "Receive " << to_string(update);
|
||||
return;
|
||||
}
|
||||
td_->messages_manager_->on_update_read_message_comments(DialogId(ChannelId(update->channel_id_)),
|
||||
MessageId(ServerMessageId(update->top_msg_id_)), MessageId(),
|
||||
MessageId(), last_read_outbox_message_id);
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
|
||||
|
@ -139,8 +139,9 @@ class UpdatesManager final : public Actor {
|
||||
private:
|
||||
static constexpr int32 FORCED_GET_DIFFERENCE_PTS_DIFF = 100000;
|
||||
static constexpr int32 GAP_TIMEOUT_UPDATE_COUNT = 20;
|
||||
static const double MAX_UNFILLED_GAP_TIME;
|
||||
static const double MAX_PTS_SAVE_DELAY;
|
||||
static constexpr double MAX_UNFILLED_GAP_TIME = 0.7;
|
||||
static constexpr double MAX_PTS_SAVE_DELAY = 0.05;
|
||||
static constexpr double UPDATE_APPLY_WARNING_TIME = 0.25;
|
||||
static constexpr bool DROP_PTS_UPDATES = false;
|
||||
static constexpr const char *AFTER_GET_DIFFERENCE_SOURCE = "after get difference";
|
||||
static constexpr int32 AUDIO_TRANSCRIPTION_TIMEOUT = 60;
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include "td/telegram/Version.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -79,8 +79,8 @@ class UserId {
|
||||
};
|
||||
|
||||
struct UserIdHash {
|
||||
std::size_t operator()(UserId user_id) const {
|
||||
return std::hash<int64>()(user_id.get());
|
||||
uint32 operator()(UserId user_id) const {
|
||||
return Hash<int64>()(user_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -62,9 +62,9 @@ enum class Version : int32 {
|
||||
|
||||
enum class DbVersion : int32 {
|
||||
DialogDbCreated = 3,
|
||||
MessagesDbMediaIndex,
|
||||
MessagesDb30MediaIndex,
|
||||
MessagesDbFts,
|
||||
MessageDbMediaIndex,
|
||||
MessageDb30MediaIndex,
|
||||
MessageDbFts,
|
||||
MessagesCallIndex,
|
||||
FixFileRemoteLocationKeyBug,
|
||||
AddNotificationsSupport,
|
||||
@ -72,6 +72,7 @@ enum class DbVersion : int32 {
|
||||
AddScheduledMessages,
|
||||
StorePinnedDialogsInBinlog,
|
||||
AddMessageThreadSupport,
|
||||
AddMessageThreadDatabase,
|
||||
Next
|
||||
};
|
||||
|
||||
|
@ -129,7 +129,8 @@ FileId VideoNotesManager::dup_video_note(FileId new_id, FileId old_id) {
|
||||
new_video_note->waveform = old_video_note->waveform;
|
||||
new_video_note->minithumbnail = old_video_note->minithumbnail;
|
||||
new_video_note->thumbnail = old_video_note->thumbnail;
|
||||
new_video_note->thumbnail.file_id = td_->file_manager_->dup_file_id(new_video_note->thumbnail.file_id);
|
||||
new_video_note->thumbnail.file_id =
|
||||
td_->file_manager_->dup_file_id(new_video_note->thumbnail.file_id, "dup_video_note");
|
||||
new_video_note->transcription_info = TranscriptionInfo::copy_if_transcribed(old_video_note->transcription_info);
|
||||
return new_id;
|
||||
}
|
||||
@ -173,7 +174,8 @@ void VideoNotesManager::create_video_note(FileId file_id, string minithumbnail,
|
||||
|
||||
void VideoNotesManager::register_video_note(FileId video_note_file_id, FullMessageId full_message_id,
|
||||
const char *source) {
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server() ||
|
||||
td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Register video note " << video_note_file_id << " from " << full_message_id << " from " << source;
|
||||
@ -185,7 +187,8 @@ void VideoNotesManager::register_video_note(FileId video_note_file_id, FullMessa
|
||||
|
||||
void VideoNotesManager::unregister_video_note(FileId video_note_file_id, FullMessageId full_message_id,
|
||||
const char *source) {
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server() ||
|
||||
td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Unregister video note " << video_note_file_id << " from " << full_message_id << " from " << source;
|
||||
|
@ -139,8 +139,9 @@ FileId VideosManager::dup_video(FileId new_id, FileId old_id) {
|
||||
CHECK(new_video == nullptr);
|
||||
new_video = make_unique<Video>(*old_video);
|
||||
new_video->file_id = new_id;
|
||||
new_video->thumbnail.file_id = td_->file_manager_->dup_file_id(new_video->thumbnail.file_id);
|
||||
new_video->animated_thumbnail.file_id = td_->file_manager_->dup_file_id(new_video->animated_thumbnail.file_id);
|
||||
new_video->thumbnail.file_id = td_->file_manager_->dup_file_id(new_video->thumbnail.file_id, "dup_video");
|
||||
new_video->animated_thumbnail.file_id =
|
||||
td_->file_manager_->dup_file_id(new_video->animated_thumbnail.file_id, "dup_video");
|
||||
return new_id;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
#include "td/telegram/VoiceNotesManager.h"
|
||||
|
||||
#include "td/telegram/AuthManager.h"
|
||||
#include "td/telegram/Dimensions.h"
|
||||
#include "td/telegram/files/FileManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
@ -16,6 +17,7 @@
|
||||
#include "td/telegram/telegram_api.h"
|
||||
#include "td/telegram/UpdatesManager.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/logging.h"
|
||||
|
||||
namespace td {
|
||||
@ -134,7 +136,8 @@ void VoiceNotesManager::create_voice_note(FileId file_id, string mime_type, int3
|
||||
|
||||
void VoiceNotesManager::register_voice_note(FileId voice_note_file_id, FullMessageId full_message_id,
|
||||
const char *source) {
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server() ||
|
||||
td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Register voice note " << voice_note_file_id << " from " << full_message_id << " from " << source;
|
||||
@ -146,7 +149,8 @@ void VoiceNotesManager::register_voice_note(FileId voice_note_file_id, FullMessa
|
||||
|
||||
void VoiceNotesManager::unregister_voice_note(FileId voice_note_file_id, FullMessageId full_message_id,
|
||||
const char *source) {
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server()) {
|
||||
if (full_message_id.get_message_id().is_scheduled() || !full_message_id.get_message_id().is_server() ||
|
||||
td_->auth_manager_->is_bot()) {
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "Unregister voice note " << voice_note_file_id << " from " << full_message_id << " from " << source;
|
||||
|
@ -7,10 +7,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -54,8 +54,8 @@ class WebPageId {
|
||||
};
|
||||
|
||||
struct WebPageIdHash {
|
||||
std::size_t operator()(WebPageId web_page_id) const {
|
||||
return std::hash<int64>()(web_page_id.get());
|
||||
uint32 operator()(WebPageId web_page_id) const {
|
||||
return Hash<int64>()(web_page_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -414,7 +414,7 @@ WebPagesManager::WebPagesManager(Td *td, ActorShared<> parent) : td_(td), parent
|
||||
void WebPagesManager::tear_down() {
|
||||
parent_.reset();
|
||||
|
||||
LOG(DEBUG) << "Have " << web_pages_.size() << " web pages to free";
|
||||
LOG(DEBUG) << "Have " << web_pages_.calc_size() << " web pages to free";
|
||||
}
|
||||
|
||||
WebPagesManager::~WebPagesManager() {
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -56,8 +56,8 @@ class FileId {
|
||||
};
|
||||
|
||||
struct FileIdHash {
|
||||
std::size_t operator()(FileId file_id) const {
|
||||
return std::hash<int32>()(file_id.get());
|
||||
uint32 operator()(FileId file_id) const {
|
||||
return Hash<int32>()(file_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -32,7 +32,7 @@ int VERBOSITY_NAME(file_loader) = VERBOSITY_NAME(DEBUG) + 2;
|
||||
namespace {
|
||||
|
||||
Result<std::pair<FileFd, string>> try_create_new_file(CSlice path, CSlice file_name) {
|
||||
LOG(DEBUG) << "Trying to create new file " << file_name << " in the directory \"" << path << '"';
|
||||
LOG(DEBUG) << "Trying to create new file \"" << file_name << "\" in the directory \"" << path << '"';
|
||||
auto name = PSTRING() << path << file_name;
|
||||
auto r_fd = FileFd::open(name, FileFd::Read | FileFd::Write | FileFd::CreateNew, 0640);
|
||||
if (r_fd.is_error()) {
|
||||
|
@ -396,6 +396,9 @@ void FileNode::set_encryption_key(FileEncryptionKey key) {
|
||||
void FileNode::set_upload_pause(FileId upload_pause) {
|
||||
if (upload_pause_ != upload_pause) {
|
||||
LOG(INFO) << "Change file " << main_file_id_ << " upload_pause from " << upload_pause_ << " to " << upload_pause;
|
||||
if (upload_pause_.is_valid() != upload_pause.is_valid()) {
|
||||
on_info_changed();
|
||||
}
|
||||
upload_pause_ = upload_pause;
|
||||
}
|
||||
}
|
||||
@ -662,7 +665,7 @@ int64 FileView::local_total_size() const {
|
||||
}
|
||||
|
||||
bool FileView::is_uploading() const {
|
||||
return node_->upload_priority_ != 0 || node_->generate_upload_priority_ != 0;
|
||||
return node_->upload_priority_ != 0 || node_->generate_upload_priority_ != 0 || node_->upload_pause_.is_valid();
|
||||
}
|
||||
|
||||
int64 FileView::remote_size() const {
|
||||
@ -1087,14 +1090,14 @@ FileManager::FileIdInfo *FileManager::get_file_id_info(FileId file_id) {
|
||||
return &file_id_info_[file_id.get()];
|
||||
}
|
||||
|
||||
FileId FileManager::dup_file_id(FileId file_id) {
|
||||
FileId FileManager::dup_file_id(FileId file_id, const char *source) {
|
||||
int32 file_node_id;
|
||||
auto *file_node = get_file_node_raw(file_id, &file_node_id);
|
||||
if (!file_node) {
|
||||
return FileId();
|
||||
}
|
||||
auto result = FileId(create_file_id(file_node_id, file_node).get(), file_id.get_remote());
|
||||
LOG(INFO) << "Dup file " << file_id << " to " << result;
|
||||
LOG(INFO) << "Dup file " << file_id << " to " << result << " from " << source;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1108,10 +1111,14 @@ FileId FileManager::create_file_id(int32 file_node_id, FileNode *file_node) {
|
||||
void FileManager::try_forget_file_id(FileId file_id) {
|
||||
auto *info = get_file_id_info(file_id);
|
||||
if (info->send_updates_flag_ || info->pin_flag_ || info->sent_file_id_flag_) {
|
||||
LOG(DEBUG) << "Can't forget file " << file_id << ", because of"
|
||||
<< (info->send_updates_flag_ ? " (sent updates)" : "") << (info->pin_flag_ ? " (pin)" : "")
|
||||
<< (info->sent_file_id_flag_ ? " (sent file identifier)" : "");
|
||||
return;
|
||||
}
|
||||
auto file_node = get_file_node(file_id);
|
||||
if (file_node->main_file_id_ == file_id) {
|
||||
LOG(DEBUG) << "Can't forget main file " << file_id;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1141,14 +1148,15 @@ void FileManager::on_file_unlink(const FullLocalFileLocation &location) {
|
||||
}
|
||||
|
||||
Result<FileId> FileManager::register_local(FullLocalFileLocation location, DialogId owner_dialog_id, int64 size,
|
||||
bool get_by_hash, bool force, bool skip_file_size_checks) {
|
||||
bool get_by_hash, bool force, bool skip_file_size_checks,
|
||||
FileId merge_file_id) {
|
||||
// TODO: use get_by_hash
|
||||
FileData data;
|
||||
data.local_ = LocalFileLocation(std::move(location));
|
||||
data.owner_dialog_id_ = owner_dialog_id;
|
||||
data.size_ = size;
|
||||
return register_file(std::move(data), FileLocationSource::None /*won't be used*/, "register_local", force,
|
||||
skip_file_size_checks);
|
||||
return register_file(std::move(data), FileLocationSource::None /*won't be used*/, merge_file_id, "register_local",
|
||||
force, skip_file_size_checks);
|
||||
}
|
||||
|
||||
FileId FileManager::register_remote(FullRemoteFileLocation location, FileLocationSource file_location_source,
|
||||
@ -1161,7 +1169,7 @@ FileId FileManager::register_remote(FullRemoteFileLocation location, FileLocatio
|
||||
data.expected_size_ = expected_size;
|
||||
data.remote_name_ = std::move(remote_name);
|
||||
|
||||
auto file_id = register_file(std::move(data), file_location_source, "register_remote", false).move_as_ok();
|
||||
auto file_id = register_file(std::move(data), file_location_source, FileId(), "register_remote", false).move_as_ok();
|
||||
if (!url.empty()) {
|
||||
auto file_node = get_file_node(file_id);
|
||||
CHECK(file_node);
|
||||
@ -1197,11 +1205,12 @@ Result<FileId> FileManager::register_generate(FileType file_type, FileLocationSo
|
||||
td::make_unique<FullGenerateFileLocation>(file_type, std::move(original_path), std::move(conversion));
|
||||
data.owner_dialog_id_ = owner_dialog_id;
|
||||
data.expected_size_ = expected_size;
|
||||
return register_file(std::move(data), file_location_source, "register_generate", false);
|
||||
return register_file(std::move(data), file_location_source, FileId(), "register_generate", false);
|
||||
}
|
||||
|
||||
Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource file_location_source, const char *source,
|
||||
bool force, bool skip_file_size_checks) {
|
||||
Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource file_location_source,
|
||||
FileId merge_file_id, const char *source, bool force,
|
||||
bool skip_file_size_checks) {
|
||||
bool has_remote = data.remote_.type() == RemoteFileLocation::Type::Full;
|
||||
bool has_generate = data.generate_ != nullptr;
|
||||
if (data.local_.type() == LocalFileLocation::Type::Full && !force) {
|
||||
@ -1274,15 +1283,14 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
|
||||
FileView file_view(get_file_node(file_id));
|
||||
|
||||
vector<FileId> to_merge;
|
||||
auto register_location = [&](const auto &location, auto &mp) {
|
||||
auto register_location = [&](const auto &location, auto &mp) -> FileId * {
|
||||
auto &other_id = mp[location];
|
||||
if (other_id.empty()) {
|
||||
other_id = file_id;
|
||||
get_file_id_info(file_id)->pin_flag_ = true;
|
||||
return true;
|
||||
return &other_id;
|
||||
} else {
|
||||
to_merge.push_back(other_id);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
bool new_remote = false;
|
||||
@ -1303,17 +1311,17 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
|
||||
}
|
||||
}
|
||||
}
|
||||
bool new_local = false;
|
||||
FileId *new_local_file_id = nullptr;
|
||||
if (file_view.has_local_location()) {
|
||||
new_local = register_location(file_view.local_location(), local_location_to_file_id_);
|
||||
new_local_file_id = register_location(file_view.local_location(), local_location_to_file_id_);
|
||||
}
|
||||
bool new_generate = false;
|
||||
FileId *new_generate_file_id = nullptr;
|
||||
if (file_view.has_generate_location()) {
|
||||
new_generate = register_location(file_view.generate_location(), generate_location_to_file_id_);
|
||||
new_generate_file_id = register_location(file_view.generate_location(), generate_location_to_file_id_);
|
||||
}
|
||||
td::unique(to_merge);
|
||||
|
||||
int new_cnt = new_remote + new_local + new_generate;
|
||||
int new_cnt = new_remote + (new_local_file_id != nullptr) + (new_generate_file_id != nullptr);
|
||||
if (data.pmc_id_ == 0 && file_db_ && new_cnt > 0) {
|
||||
node->need_load_from_pmc_ = true;
|
||||
}
|
||||
@ -1322,10 +1330,25 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
|
||||
// may invalidate node
|
||||
merge(file_id, id, no_sync_merge).ignore();
|
||||
}
|
||||
Status status;
|
||||
if (merge_file_id.is_valid()) {
|
||||
status = merge(file_id, merge_file_id);
|
||||
}
|
||||
|
||||
try_flush_node(get_file_node(file_id), "register_file");
|
||||
auto main_file_id = get_file_node(file_id)->main_file_id_;
|
||||
try_forget_file_id(file_id);
|
||||
if (main_file_id != file_id) {
|
||||
if (new_local_file_id != nullptr) {
|
||||
*new_local_file_id = main_file_id;
|
||||
}
|
||||
if (new_generate_file_id != nullptr) {
|
||||
*new_generate_file_id = main_file_id;
|
||||
}
|
||||
try_forget_file_id(file_id);
|
||||
}
|
||||
if ((new_local_file_id != nullptr) || (new_generate_file_id != nullptr)) {
|
||||
get_file_id_info(main_file_id)->pin_flag_ = true;
|
||||
}
|
||||
|
||||
if (!data.file_source_ids_.empty()) {
|
||||
VLOG(file_references) << "Loaded " << data.file_source_ids_ << " for file " << main_file_id << " from " << source;
|
||||
@ -1334,6 +1357,9 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
|
||||
context_->add_file_source(main_file_id, file_source_id);
|
||||
}
|
||||
}
|
||||
if (status.is_error()) {
|
||||
return std::move(status);
|
||||
}
|
||||
return FileId(main_file_id.get(), remote_key);
|
||||
}
|
||||
|
||||
@ -1495,7 +1521,7 @@ void FileManager::do_cancel_generate(FileNodePtr node) {
|
||||
node->set_generate_priority(0, 0);
|
||||
}
|
||||
|
||||
Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sync) {
|
||||
Status FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sync) {
|
||||
if (!x_file_id.is_valid()) {
|
||||
return Status::Error("First file_id is invalid");
|
||||
}
|
||||
@ -1507,7 +1533,7 @@ Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy
|
||||
|
||||
if (!y_file_id.is_valid()) {
|
||||
LOG(DEBUG) << "Old file is invalid";
|
||||
return x_node->main_file_id_;
|
||||
return Status::OK();
|
||||
}
|
||||
FileNodePtr y_node = get_file_node(y_file_id);
|
||||
if (!y_node) {
|
||||
@ -1522,13 +1548,14 @@ Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy
|
||||
if (x_file_id != y_file_id) {
|
||||
LOG(DEBUG) << "New file " << x_file_id << " and old file " << y_file_id << " are already merged";
|
||||
}
|
||||
return x_node->main_file_id_;
|
||||
try_flush_node_info(x_node, "merge 1");
|
||||
return Status::OK();
|
||||
}
|
||||
if (y_file_id == y_node->upload_pause_) {
|
||||
y_node->set_upload_pause(FileId());
|
||||
}
|
||||
|
||||
LOG(DEBUG) << "Merge new file " << x_file_id << " and old file " << y_file_id;
|
||||
LOG(INFO) << "Merge new file " << x_file_id << " and old file " << y_file_id;
|
||||
if (x_node->remote_.full && y_node->remote_.full && !x_node->remote_.full.value().is_web() &&
|
||||
!y_node->remote_.full.value().is_web() && y_node->remote_.is_full_alive &&
|
||||
x_node->remote_.full_source == FileLocationSource::FromServer &&
|
||||
@ -1573,6 +1600,8 @@ Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy
|
||||
y_node->main_file_id_, y_node->main_file_id_priority_);
|
||||
|
||||
if (size_i == -1) {
|
||||
try_flush_node_info(x_node, "merge 2");
|
||||
try_flush_node_info(y_node, "merge 3");
|
||||
return Status::Error(PSLICE() << "Can't merge files. Different size: " << x_node->size_ << " and "
|
||||
<< y_node->size_);
|
||||
}
|
||||
@ -1581,6 +1610,8 @@ Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy
|
||||
LOG(ERROR) << "Different encryption key in files, but lets choose same key as remote location";
|
||||
encryption_key_i = remote_i;
|
||||
} else {
|
||||
try_flush_node_info(x_node, "merge 4");
|
||||
try_flush_node_info(y_node, "merge 5");
|
||||
return Status::Error("Can't merge files. Different encryption keys");
|
||||
}
|
||||
}
|
||||
@ -1652,7 +1683,7 @@ Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy
|
||||
other_node->upload_id_ = 0;
|
||||
other_node->upload_was_update_file_reference_ = false;
|
||||
other_node->upload_priority_ = 0;
|
||||
other_node->set_upload_pause(FileId());
|
||||
other_node->upload_pause_ = FileId();
|
||||
} else {
|
||||
do_cancel_upload(other_node);
|
||||
}
|
||||
@ -1766,7 +1797,7 @@ Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy
|
||||
}
|
||||
try_flush_node_full(node, node_i != remote_i, node_i != local_i, node_i != generate_i, other_pmc_id);
|
||||
|
||||
return node->main_file_id_;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void FileManager::add_file_source(FileId file_id, FileSourceId file_source_id) {
|
||||
@ -2024,9 +2055,9 @@ void FileManager::load_from_pmc(FileNodePtr node, bool new_remote, bool new_loca
|
||||
<< ", new_remote = " << new_remote << ", new_local = " << new_local << ", new_generate = " << new_generate;
|
||||
auto load = [&](auto location, const char *source) {
|
||||
TRY_RESULT(file_data, file_db_->get_file_data_sync(location));
|
||||
TRY_RESULT(new_file_id, register_file(std::move(file_data), FileLocationSource::FromDatabase, source, false));
|
||||
TRY_RESULT(main_file_id, merge(file_id, new_file_id));
|
||||
file_id = main_file_id;
|
||||
TRY_RESULT(new_file_id,
|
||||
register_file(std::move(file_data), FileLocationSource::FromDatabase, FileId(), source, false));
|
||||
TRY_STATUS(merge(file_id, new_file_id)); // merge manually to keep merge parameters order
|
||||
return Status::OK();
|
||||
};
|
||||
if (new_remote) {
|
||||
@ -2628,6 +2659,9 @@ void FileManager::resume_upload(FileId file_id, vector<int> bad_parts, std::shar
|
||||
if (node->upload_pause_ == file_id) {
|
||||
node->set_upload_pause(FileId());
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
try_flush_node(node, "resume_upload");
|
||||
};
|
||||
FileView file_view(node);
|
||||
if (file_view.has_active_upload_remote_location() && can_reuse_remote_file(file_view.get_type())) {
|
||||
LOG(INFO) << "File " << file_id << " is already uploaded";
|
||||
@ -2683,7 +2717,6 @@ void FileManager::resume_upload(FileId file_id, vector<int> bad_parts, std::shar
|
||||
|
||||
run_generate(node);
|
||||
run_upload(node, std::move(bad_parts));
|
||||
try_flush_node(node, "resume_upload");
|
||||
}
|
||||
|
||||
bool FileManager::delete_partial_remote_location(FileId file_id) {
|
||||
@ -2695,6 +2728,9 @@ bool FileManager::delete_partial_remote_location(FileId file_id) {
|
||||
if (node->upload_pause_ == file_id) {
|
||||
node->set_upload_pause(FileId());
|
||||
}
|
||||
SCOPE_EXIT {
|
||||
try_flush_node(node, "delete_partial_remote_location");
|
||||
};
|
||||
if (node->remote_.is_full_alive) {
|
||||
LOG(INFO) << "File " << file_id << " is already uploaded";
|
||||
return true;
|
||||
@ -2716,7 +2752,6 @@ bool FileManager::delete_partial_remote_location(FileId file_id) {
|
||||
}
|
||||
|
||||
run_upload(node, vector<int>());
|
||||
try_flush_node(node, "delete_partial_remote_location");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3019,7 +3054,7 @@ Result<FileId> FileManager::from_persistent_id_generated(Slice binary, FileType
|
||||
}
|
||||
FileData data;
|
||||
data.generate_ = make_unique<FullGenerateFileLocation>(std::move(generate_location));
|
||||
return register_file(std::move(data), FileLocationSource::FromUser, "from_persistent_id_generated", false)
|
||||
return register_file(std::move(data), FileLocationSource::FromUser, FileId(), "from_persistent_id_generated", false)
|
||||
.move_as_ok();
|
||||
}
|
||||
|
||||
@ -3047,8 +3082,8 @@ Result<FileId> FileManager::from_persistent_id_v23(Slice binary, FileType file_t
|
||||
}
|
||||
FileData data;
|
||||
data.remote_ = RemoteFileLocation(std::move(remote_location));
|
||||
auto file_id =
|
||||
register_file(std::move(data), FileLocationSource::FromUser, "from_persistent_id_v23", false).move_as_ok();
|
||||
auto file_id = register_file(std::move(data), FileLocationSource::FromUser, FileId(), "from_persistent_id_v23", false)
|
||||
.move_as_ok();
|
||||
return file_id;
|
||||
}
|
||||
|
||||
@ -3167,14 +3202,17 @@ Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> re
|
||||
}
|
||||
|
||||
if (!file_view.has_remote_location()) {
|
||||
// TODO why not return file_id here? We will dup it anyway
|
||||
// But it will not be duped if has_input_media(), so for now we can't return main_file_id
|
||||
// There are no reasons to dup file_id, because it will be duped anyway before upload/reupload
|
||||
// It will not be duped in dup_message_content only if has_input_media(),
|
||||
// but currently in this case the file never needs to be reuploaded
|
||||
|
||||
if (file_view.has_url() && !is_encrypted) {
|
||||
if (!is_encrypted) {
|
||||
// URLs in non-secret chats never needs to be reuploaded, so they don't need to be duped
|
||||
// non-URLs without remote location will be duped at dup_message_content, because they have no input media
|
||||
return file_node->main_file_id_;
|
||||
}
|
||||
return dup_file_id(file_id);
|
||||
|
||||
return dup_file_id(file_id, "check_input_file_id");
|
||||
}
|
||||
|
||||
int32 remote_id = file_id.get_remote();
|
||||
@ -3248,6 +3286,7 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
|
||||
if (r_file_content.is_ok()) {
|
||||
hash = sha256(r_file_content.ok());
|
||||
auto file_id = file_hash_to_file_id_.get(hash);
|
||||
LOG(INFO) << "Found file " << file_id << " by hash " << hex_encode(hash);
|
||||
if (file_id.is_valid()) {
|
||||
auto file_view = get_file_view(file_id);
|
||||
if (!file_view.empty()) {
|
||||
@ -3257,6 +3296,9 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
|
||||
if (file_view.has_remote_location() && !file_view.remote_location().is_web()) {
|
||||
return file_id;
|
||||
}
|
||||
if (file_view.is_uploading()) {
|
||||
hash.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3603,9 +3645,12 @@ void FileManager::on_partial_upload(QueryId query_id, PartialRemoteFileLocation
|
||||
LOG(DEBUG) << "Receive on_partial_upload for file " << file_id << " with " << partial_remote << " and ready size "
|
||||
<< ready_size;
|
||||
if (!file_node) {
|
||||
LOG(ERROR) << "Can't find being uploaded file " << file_id;
|
||||
return;
|
||||
}
|
||||
if (file_node->upload_id_ != query_id) {
|
||||
LOG(DEBUG) << "Upload identifier of file " << file_id << " is " << file_node->upload_id_ << " instead of "
|
||||
<< query_id;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3623,7 +3668,7 @@ void FileManager::on_download_ok(QueryId query_id, FullLocalFileLocation local,
|
||||
std::tie(query, was_active) = finish_query(query_id);
|
||||
auto file_id = query.file_id_;
|
||||
LOG(INFO) << "ON DOWNLOAD OK of " << (is_new ? "new" : "checked") << " file " << file_id << " of size " << size;
|
||||
auto r_new_file_id = register_local(std::move(local), DialogId(), size, false, false, true);
|
||||
auto r_new_file_id = register_local(std::move(local), DialogId(), size, false, false, true, file_id);
|
||||
Status status = Status::OK();
|
||||
if (r_new_file_id.is_error()) {
|
||||
status = Status::Error(PSLICE() << "Can't register local file after download: " << r_new_file_id.error().message());
|
||||
@ -3631,10 +3676,6 @@ void FileManager::on_download_ok(QueryId query_id, FullLocalFileLocation local,
|
||||
if (is_new && context_->need_notify_on_new_files()) {
|
||||
context_->on_new_file(size, get_file_view(r_new_file_id.ok()).get_allocated_local_size(), 1);
|
||||
}
|
||||
auto r_file_id = merge(r_new_file_id.ok(), file_id);
|
||||
if (r_file_id.is_error()) {
|
||||
status = r_file_id.move_as_error();
|
||||
}
|
||||
}
|
||||
if (status.is_error()) {
|
||||
LOG(ERROR) << status.message();
|
||||
@ -3688,8 +3729,8 @@ void FileManager::on_upload_ok(QueryId query_id, FileType file_type, PartialRemo
|
||||
partial_remote.file_id_, partial_remote.part_count_, "", file_view.encryption_key().calc_fingerprint());
|
||||
}
|
||||
if (file_info->upload_callback_) {
|
||||
file_info->upload_callback_->on_upload_encrypted_ok(file_id, std::move(input_file));
|
||||
file_node->set_upload_pause(file_id);
|
||||
file_info->upload_callback_->on_upload_encrypted_ok(file_id, std::move(input_file));
|
||||
file_info->upload_callback_.reset();
|
||||
}
|
||||
} else if (file_view.is_secure()) {
|
||||
@ -3698,8 +3739,8 @@ void FileManager::on_upload_ok(QueryId query_id, FileType file_type, PartialRemo
|
||||
partial_remote.file_id_, partial_remote.part_count_, "" /*md5*/, BufferSlice() /*file_hash*/,
|
||||
BufferSlice() /*encrypted_secret*/);
|
||||
if (file_info->upload_callback_) {
|
||||
file_node->set_upload_pause(file_id);
|
||||
file_info->upload_callback_->on_upload_secure_ok(file_id, std::move(input_file));
|
||||
file_node->upload_pause_ = file_id;
|
||||
file_info->upload_callback_.reset();
|
||||
}
|
||||
} else {
|
||||
@ -3712,13 +3753,15 @@ void FileManager::on_upload_ok(QueryId query_id, FileType file_type, PartialRemo
|
||||
std::move(file_name), "");
|
||||
}
|
||||
if (file_info->upload_callback_) {
|
||||
file_info->upload_callback_->on_upload_ok(file_id, std::move(input_file));
|
||||
file_node->set_upload_pause(file_id);
|
||||
file_info->upload_callback_->on_upload_ok(file_id, std::move(input_file));
|
||||
file_info->upload_callback_.reset();
|
||||
}
|
||||
}
|
||||
// don't flush node info, because nothing actually changed
|
||||
}
|
||||
|
||||
// for upload by hash
|
||||
void FileManager::on_upload_full_ok(QueryId query_id, FullRemoteFileLocation remote) {
|
||||
if (is_closed_) {
|
||||
return;
|
||||
@ -3784,19 +3827,12 @@ void FileManager::on_generate_ok(QueryId query_id, FullLocalFileLocation local)
|
||||
|
||||
auto old_upload_id = file_node->upload_id_;
|
||||
|
||||
auto r_new_file_id = register_local(local, DialogId(), 0);
|
||||
Status status;
|
||||
if (r_new_file_id.is_error()) {
|
||||
status = Status::Error(PSLICE() << "Can't register local file after generate: " << r_new_file_id.error());
|
||||
} else {
|
||||
auto result = merge(r_new_file_id.ok(), generate_file_id);
|
||||
if (result.is_error()) {
|
||||
status = result.move_as_error();
|
||||
}
|
||||
}
|
||||
auto r_new_file_id = register_local(local, DialogId(), 0, false, false, false, generate_file_id);
|
||||
file_node = get_file_node(generate_file_id);
|
||||
if (status.is_error()) {
|
||||
return on_error_impl(file_node, query.type_, was_active, std::move(status));
|
||||
if (r_new_file_id.is_error()) {
|
||||
return on_error_impl(
|
||||
file_node, query.type_, was_active,
|
||||
Status::Error(PSLICE() << "Can't register local file after generate: " << r_new_file_id.error()));
|
||||
}
|
||||
CHECK(file_node);
|
||||
|
||||
@ -3842,7 +3878,7 @@ void FileManager::on_error(QueryId query_id, Status status) {
|
||||
|
||||
void FileManager::on_error_impl(FileNodePtr node, Query::Type type, bool was_active, Status status) {
|
||||
SCOPE_EXIT {
|
||||
try_flush_node(node, "on_error");
|
||||
try_flush_node(node, "on_error_impl");
|
||||
};
|
||||
|
||||
if (status.message() == "FILE_PART_INVALID") {
|
||||
@ -3932,8 +3968,13 @@ void FileManager::on_error_impl(FileNodePtr node, Query::Type type, bool was_act
|
||||
status = Global::request_aborted_error();
|
||||
} else {
|
||||
if (status.code() != -1) {
|
||||
LOG(WARNING) << "Failed to " << type << " file " << node->main_file_id_ << " of type "
|
||||
<< FileView(node).get_type() << ": " << status;
|
||||
if (type == Query::Type::Generate && node->generate_ != nullptr) {
|
||||
LOG(WARNING) << "Failed to generate file " << node->main_file_id_ << " with " << *node->generate_ << ": "
|
||||
<< status;
|
||||
} else {
|
||||
LOG(WARNING) << "Failed to " << type << " file " << node->main_file_id_ << " of type "
|
||||
<< FileView(node).get_type() << ": " << status;
|
||||
}
|
||||
}
|
||||
if (status.code() == 0) {
|
||||
// Remove partial locations
|
||||
|
@ -423,14 +423,14 @@ class FileManager final : public FileLoadManager::Callback {
|
||||
|
||||
void init_actor();
|
||||
|
||||
FileId dup_file_id(FileId file_id);
|
||||
FileId dup_file_id(FileId file_id, const char *source);
|
||||
|
||||
void on_file_unlink(const FullLocalFileLocation &location);
|
||||
|
||||
FileId register_empty(FileType type);
|
||||
Result<FileId> register_local(FullLocalFileLocation location, DialogId owner_dialog_id, int64 size,
|
||||
bool get_by_hash = false, bool force = false,
|
||||
bool skip_file_size_checks = false) TD_WARN_UNUSED_RESULT;
|
||||
bool get_by_hash = false, bool force = false, bool skip_file_size_checks = false,
|
||||
FileId merge_file_id = FileId()) TD_WARN_UNUSED_RESULT;
|
||||
FileId register_remote(FullRemoteFileLocation location, FileLocationSource file_location_source,
|
||||
DialogId owner_dialog_id, int64 size, int64 expected_size,
|
||||
string remote_name) TD_WARN_UNUSED_RESULT;
|
||||
@ -438,7 +438,7 @@ class FileManager final : public FileLoadManager::Callback {
|
||||
string conversion, DialogId owner_dialog_id,
|
||||
int64 expected_size) TD_WARN_UNUSED_RESULT;
|
||||
|
||||
Result<FileId> merge(FileId x_file_id, FileId y_file_id, bool no_sync = false) TD_WARN_UNUSED_RESULT;
|
||||
Status merge(FileId x_file_id, FileId y_file_id, bool no_sync = false);
|
||||
|
||||
void add_file_source(FileId file_id, FileSourceId file_source_id);
|
||||
|
||||
@ -522,8 +522,8 @@ class FileManager final : public FileLoadManager::Callback {
|
||||
|
||||
FileId register_url(string url, FileType file_type, FileLocationSource file_location_source,
|
||||
DialogId owner_dialog_id);
|
||||
Result<FileId> register_file(FileData &&data, FileLocationSource file_location_source, const char *source, bool force,
|
||||
bool skip_file_size_checks = false);
|
||||
Result<FileId> register_file(FileData &&data, FileLocationSource file_location_source, FileId merge_file_id,
|
||||
const char *source, bool force, bool skip_file_size_checks = false);
|
||||
|
||||
static constexpr int8 FROM_BYTES_PRIORITY = 10;
|
||||
|
||||
@ -603,7 +603,7 @@ class FileManager final : public FileLoadManager::Callback {
|
||||
|
||||
std::set<std::string> bad_paths_;
|
||||
|
||||
int file_node_size_warning_exp_ = 12;
|
||||
int file_node_size_warning_exp_ = 10;
|
||||
|
||||
FileId next_file_id();
|
||||
FileNodeId next_file_node_id();
|
||||
|
@ -240,7 +240,7 @@ FileId FileManager::parse_file(ParserT &parser) {
|
||||
if (file_id.empty()) {
|
||||
return register_empty(full_generated_location.file_type_);
|
||||
}
|
||||
auto download_file_id = dup_file_id(file_id);
|
||||
auto download_file_id = dup_file_id(file_id, "parse_download_file_id");
|
||||
full_generated_location.conversion_ = PSTRING() << "#file_id#" << download_file_id.get();
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/StringBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace td {
|
||||
@ -47,8 +47,8 @@ class FileSourceId {
|
||||
};
|
||||
|
||||
struct FileSourceIdHash {
|
||||
std::size_t operator()(FileSourceId file_source_id) const {
|
||||
return std::hash<int32>()(file_source_id.get());
|
||||
uint32 operator()(FileSourceId file_source_id) const {
|
||||
return Hash<int32>()(file_source_id.get());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "td/db/SqliteKeyValue.h"
|
||||
|
||||
#include "td/utils/format.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/PathView.h"
|
||||
@ -30,7 +31,6 @@
|
||||
#include "td/utils/Time.h"
|
||||
#include "td/utils/tl_parsers.h"
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
@ -102,7 +102,7 @@ struct FsFileInfo {
|
||||
|
||||
template <class CallbackT>
|
||||
void scan_fs(CancellationToken &token, CallbackT &&callback) {
|
||||
std::unordered_set<string> scanned_file_dirs;
|
||||
std::unordered_set<string, Hash<string>> scanned_file_dirs;
|
||||
auto scan_dir = [&](FileType file_type, const string &file_dir) {
|
||||
LOG(INFO) << "Trying to scan directory " << file_dir;
|
||||
if (!scanned_file_dirs.insert(file_dir).second) {
|
||||
@ -188,17 +188,17 @@ void FileStatsWorker::get_stats(bool need_all_files, bool split_by_owner_dialog_
|
||||
return promise.set_error(Global::request_aborted_error());
|
||||
}
|
||||
|
||||
std::unordered_map<size_t, size_t> hash_to_pos;
|
||||
std::unordered_map<int64, size_t, Hash<int64>> hash_to_pos;
|
||||
size_t pos = 0;
|
||||
for (auto &full_info : full_infos) {
|
||||
hash_to_pos[std::hash<std::string>()(full_info.path)] = pos;
|
||||
hash_to_pos[Hash<string>()(full_info.path)] = pos;
|
||||
pos++;
|
||||
if (token_) {
|
||||
return promise.set_error(Global::request_aborted_error());
|
||||
}
|
||||
}
|
||||
scan_db(token_, [&](DbFileInfo &db_info) {
|
||||
auto it = hash_to_pos.find(std::hash<std::string>()(db_info.path));
|
||||
auto it = hash_to_pos.find(Hash<string>()(db_info.path));
|
||||
if (it == hash_to_pos.end()) {
|
||||
return;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ namespace detail {
|
||||
class StatsCallback final : public mtproto::RawConnection::StatsCallback {
|
||||
public:
|
||||
StatsCallback(std::shared_ptr<NetStatsCallback> net_stats_callback, ActorId<ConnectionCreator> connection_creator,
|
||||
size_t hash, DcOptionsSet::Stat *option_stat)
|
||||
uint32 hash, DcOptionsSet::Stat *option_stat)
|
||||
: net_stats_callback_(std::move(net_stats_callback))
|
||||
, connection_creator_(std::move(connection_creator))
|
||||
, hash_(hash)
|
||||
@ -84,7 +84,7 @@ class StatsCallback final : public mtproto::RawConnection::StatsCallback {
|
||||
private:
|
||||
std::shared_ptr<NetStatsCallback> net_stats_callback_;
|
||||
ActorId<ConnectionCreator> connection_creator_;
|
||||
size_t hash_;
|
||||
uint32 hash_;
|
||||
DcOptionsSet::Stat *option_stat_;
|
||||
};
|
||||
|
||||
@ -595,7 +595,7 @@ void ConnectionCreator::on_logging_out(bool is_logging_out) {
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionCreator::on_pong(size_t hash) {
|
||||
void ConnectionCreator::on_pong(uint32 hash) {
|
||||
G()->save_server_time();
|
||||
if (active_proxy_id_ != 0) {
|
||||
auto now = G()->unix_time();
|
||||
@ -607,14 +607,14 @@ void ConnectionCreator::on_pong(size_t hash) {
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionCreator::on_mtproto_error(size_t hash) {
|
||||
void ConnectionCreator::on_mtproto_error(uint32 hash) {
|
||||
auto &client = clients_[hash];
|
||||
client.hash = hash;
|
||||
client.mtproto_error_flood_control.add_event(static_cast<int32>(Time::now_cached()));
|
||||
client.mtproto_error_flood_control.add_event(Time::now_cached());
|
||||
}
|
||||
|
||||
void ConnectionCreator::request_raw_connection(DcId dc_id, bool allow_media_only, bool is_media,
|
||||
Promise<unique_ptr<mtproto::RawConnection>> promise, size_t hash,
|
||||
Promise<unique_ptr<mtproto::RawConnection>> promise, uint32 hash,
|
||||
unique_ptr<mtproto::AuthData> auth_data) {
|
||||
auto &client = clients_[hash];
|
||||
if (!client.inited) {
|
||||
@ -892,12 +892,12 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
|
||||
wakeup_at = max(client.sanity_flood_control.get_wakeup_at(), wakeup_at);
|
||||
|
||||
if (!act_as_if_online) {
|
||||
wakeup_at = max(wakeup_at, client.backoff.get_wakeup_at());
|
||||
wakeup_at = max(wakeup_at, static_cast<double>(client.backoff.get_wakeup_at()));
|
||||
}
|
||||
if (wakeup_at > Time::now()) {
|
||||
return client_set_timeout_at(client, wakeup_at);
|
||||
}
|
||||
client.sanity_flood_control.add_event(static_cast<int32>(Time::now()));
|
||||
client.sanity_flood_control.add_event(Time::now());
|
||||
if (!act_as_if_online) {
|
||||
client.backoff.add_event(static_cast<int32>(Time::now()));
|
||||
}
|
||||
@ -916,7 +916,7 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
|
||||
}
|
||||
|
||||
// Events with failed socket creation are ignored
|
||||
flood_control.add_event(static_cast<int32>(Time::now()));
|
||||
flood_control.add_event(Time::now());
|
||||
|
||||
auto socket_fd = r_socket_fd.move_as_ok();
|
||||
IPAddress debug_ip;
|
||||
@ -957,7 +957,7 @@ void ConnectionCreator::client_loop(ClientInfo &client) {
|
||||
}
|
||||
|
||||
void ConnectionCreator::client_create_raw_connection(Result<ConnectionData> r_connection_data, bool check_mode,
|
||||
mtproto::TransportType transport_type, size_t hash,
|
||||
mtproto::TransportType transport_type, uint32 hash,
|
||||
string debug_str, uint32 network_generation) {
|
||||
unique_ptr<mtproto::AuthData> auth_data;
|
||||
uint64 auth_data_generation{0};
|
||||
@ -1018,7 +1018,7 @@ void ConnectionCreator::client_set_timeout_at(ClientInfo &client, double wakeup_
|
||||
<< wakeup_at - Time::now_cached();
|
||||
}
|
||||
|
||||
void ConnectionCreator::client_add_connection(size_t hash, Result<unique_ptr<mtproto::RawConnection>> r_raw_connection,
|
||||
void ConnectionCreator::client_add_connection(uint32 hash, Result<unique_ptr<mtproto::RawConnection>> r_raw_connection,
|
||||
bool check_flag, uint64 auth_data_generation, int64 session_id) {
|
||||
auto &client = clients_[hash];
|
||||
client.add_session_id(session_id);
|
||||
@ -1044,7 +1044,7 @@ void ConnectionCreator::client_add_connection(size_t hash, Result<unique_ptr<mtp
|
||||
client_loop(client);
|
||||
}
|
||||
|
||||
void ConnectionCreator::client_wakeup(size_t hash) {
|
||||
void ConnectionCreator::client_wakeup(uint32 hash) {
|
||||
VLOG(connections) << tag("hash", format::as_hex(hash)) << " wakeup";
|
||||
G()->save_server_time();
|
||||
client_loop(clients_[hash]);
|
||||
|
@ -59,10 +59,10 @@ class ConnectionCreator final : public NetQueryCallback {
|
||||
|
||||
void on_dc_options(DcOptions new_dc_options);
|
||||
void on_dc_update(DcId dc_id, string ip_port, Promise<> promise);
|
||||
void on_pong(size_t hash);
|
||||
void on_mtproto_error(size_t hash);
|
||||
void on_pong(uint32 hash);
|
||||
void on_mtproto_error(uint32 hash);
|
||||
void request_raw_connection(DcId dc_id, bool allow_media_only, bool is_media,
|
||||
Promise<unique_ptr<mtproto::RawConnection>> promise, size_t hash = 0,
|
||||
Promise<unique_ptr<mtproto::RawConnection>> promise, uint32 hash = 0,
|
||||
unique_ptr<mtproto::AuthData> auth_data = {});
|
||||
void request_raw_connection_by_ip(IPAddress ip_address, mtproto::TransportType transport_type,
|
||||
Promise<unique_ptr<mtproto::RawConnection>> promise);
|
||||
@ -159,7 +159,7 @@ class ConnectionCreator final : public NetQueryCallback {
|
||||
static constexpr double READY_CONNECTIONS_TIMEOUT = 10;
|
||||
|
||||
bool inited{false};
|
||||
size_t hash{0};
|
||||
uint32 hash{0};
|
||||
DcId dc_id;
|
||||
bool allow_media_only{false};
|
||||
bool is_media{false};
|
||||
@ -167,7 +167,7 @@ class ConnectionCreator final : public NetQueryCallback {
|
||||
unique_ptr<mtproto::AuthData> auth_data;
|
||||
uint64 auth_data_generation{0};
|
||||
};
|
||||
std::map<size_t, ClientInfo> clients_;
|
||||
std::map<uint32, ClientInfo> clients_;
|
||||
|
||||
std::shared_ptr<NetStatsCallback> media_net_stats_callback_;
|
||||
std::shared_ptr<NetStatsCallback> common_net_stats_callback_;
|
||||
@ -209,7 +209,7 @@ class ConnectionCreator final : public NetQueryCallback {
|
||||
Result<SocketFd> do_request_connection(DcId dc_id, bool allow_media_only);
|
||||
Result<std::pair<unique_ptr<mtproto::RawConnection>, bool>> do_request_raw_connection(DcId dc_id,
|
||||
bool allow_media_only,
|
||||
bool is_media, size_t hash);
|
||||
bool is_media, uint32 hash);
|
||||
|
||||
void on_network(bool network_flag, uint32 network_generation);
|
||||
void on_online(bool online_flag);
|
||||
@ -217,12 +217,12 @@ class ConnectionCreator final : public NetQueryCallback {
|
||||
|
||||
static void update_mtproto_header(const Proxy &proxy);
|
||||
|
||||
void client_wakeup(size_t hash);
|
||||
void client_wakeup(uint32 hash);
|
||||
void client_loop(ClientInfo &client);
|
||||
void client_create_raw_connection(Result<ConnectionData> r_connection_data, bool check_mode,
|
||||
mtproto::TransportType transport_type, size_t hash, string debug_str,
|
||||
mtproto::TransportType transport_type, uint32 hash, string debug_str,
|
||||
uint32 network_generation);
|
||||
void client_add_connection(size_t hash, Result<unique_ptr<mtproto::RawConnection>> r_raw_connection, bool check_flag,
|
||||
void client_add_connection(uint32 hash, Result<unique_ptr<mtproto::RawConnection>> r_raw_connection, bool check_flag,
|
||||
uint64 auth_data_generation, int64 session_id);
|
||||
void client_set_timeout_at(ClientInfo &client, double wakeup_at);
|
||||
|
||||
|
@ -61,8 +61,9 @@ void PublicRsaKeyWatchdog::loop() {
|
||||
if (has_query_) {
|
||||
return;
|
||||
}
|
||||
if (Time::now_cached() < flood_control_.get_wakeup_at()) {
|
||||
set_timeout_in(flood_control_.get_wakeup_at() - Time::now_cached() + 0.01);
|
||||
auto now = Time::now();
|
||||
if (now < flood_control_.get_wakeup_at()) {
|
||||
set_timeout_at(flood_control_.get_wakeup_at() + 0.01);
|
||||
return;
|
||||
}
|
||||
bool ok = true;
|
||||
@ -74,7 +75,7 @@ void PublicRsaKeyWatchdog::loop() {
|
||||
if (ok) {
|
||||
return;
|
||||
}
|
||||
flood_control_.add_event(static_cast<int32>(Time::now_cached()));
|
||||
flood_control_.add_event(now);
|
||||
has_query_ = true;
|
||||
auto query = G()->net_query_creator().create(telegram_api::help_getCdnConfig());
|
||||
query->total_timeout_limit_ = 60 * 60 * 24;
|
||||
|
@ -16,13 +16,12 @@
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace td {
|
||||
|
||||
namespace mtproto {
|
||||
@ -31,7 +30,7 @@ class RawConnection;
|
||||
|
||||
class SessionCallback final : public Session::Callback {
|
||||
public:
|
||||
SessionCallback(ActorShared<SessionProxy> parent, DcId dc_id, bool allow_media_only, bool is_media, size_t hash)
|
||||
SessionCallback(ActorShared<SessionProxy> parent, DcId dc_id, bool allow_media_only, bool is_media, uint32 hash)
|
||||
: parent_(std::move(parent))
|
||||
, dc_id_(dc_id)
|
||||
, allow_media_only_(allow_media_only)
|
||||
@ -75,7 +74,7 @@ class SessionCallback final : public Session::Callback {
|
||||
DcId dc_id_;
|
||||
bool allow_media_only_ = false;
|
||||
bool is_media_ = false;
|
||||
size_t hash_ = 0;
|
||||
uint32 hash_ = 0;
|
||||
};
|
||||
|
||||
SessionProxy::SessionProxy(unique_ptr<Callback> callback, std::shared_ptr<AuthDataShared> shared_auth_data,
|
||||
@ -201,7 +200,7 @@ void SessionProxy::open_session(bool force) {
|
||||
auto dc_id = auth_data_->dc_id();
|
||||
string name = PSTRING() << "Session" << get_name().substr(Slice("SessionProxy").size());
|
||||
string hash_string = PSTRING() << name << " " << dc_id.get_raw_id() << " " << allow_media_only_;
|
||||
auto hash = std::hash<std::string>()(hash_string);
|
||||
auto hash = Hash<string>()(hash_string);
|
||||
int32 raw_dc_id = dc_id.get_raw_id();
|
||||
int32 int_dc_id = raw_dc_id;
|
||||
if (G()->is_test_dc()) {
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/port/RwMutex.h"
|
||||
@ -192,9 +193,9 @@ class BinlogKeyValue final : public KeyValueSyncInterface {
|
||||
binlog_->lazy_sync(std::move(promise));
|
||||
}
|
||||
|
||||
std::unordered_map<string, string> prefix_get(Slice prefix) final {
|
||||
std::unordered_map<string, string, Hash<string>> prefix_get(Slice prefix) final {
|
||||
auto lock = rw_mutex_.lock_write().move_as_ok();
|
||||
std::unordered_map<string, string> res;
|
||||
std::unordered_map<string, string, Hash<string>> res;
|
||||
for (const auto &kv : map_) {
|
||||
if (begins_with(kv.first, prefix)) {
|
||||
res.emplace(kv.first.substr(prefix.size()), kv.second.first);
|
||||
@ -203,9 +204,9 @@ class BinlogKeyValue final : public KeyValueSyncInterface {
|
||||
return res;
|
||||
}
|
||||
|
||||
std::unordered_map<string, string> get_all() final {
|
||||
std::unordered_map<string, string, Hash<string>> get_all() final {
|
||||
auto lock = rw_mutex_.lock_write().move_as_ok();
|
||||
std::unordered_map<string, string> res;
|
||||
std::unordered_map<string, string, Hash<string>> res;
|
||||
for (const auto &kv : map_) {
|
||||
res.emplace(kv.first, kv.second.first);
|
||||
}
|
||||
@ -238,7 +239,7 @@ class BinlogKeyValue final : public KeyValueSyncInterface {
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<string, std::pair<string, uint64>> map_;
|
||||
std::unordered_map<string, std::pair<string, uint64>, Hash<string>> map_;
|
||||
std::shared_ptr<BinlogT> binlog_;
|
||||
RwMutex rw_mutex_;
|
||||
int32 magic_ = MAGIC;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/Promise.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
@ -33,9 +34,9 @@ class KeyValueSyncInterface {
|
||||
|
||||
virtual string get(const string &key) = 0;
|
||||
|
||||
virtual std::unordered_map<string, string> prefix_get(Slice prefix) = 0;
|
||||
virtual std::unordered_map<string, string, Hash<string>> prefix_get(Slice prefix) = 0;
|
||||
|
||||
virtual std::unordered_map<string, string> get_all() = 0;
|
||||
virtual std::unordered_map<string, string, Hash<string>> get_all() = 0;
|
||||
|
||||
virtual SeqNo erase(const string &key) = 0;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
#include <unordered_map>
|
||||
@ -66,12 +67,12 @@ class SeqKeyValue {
|
||||
return map_.size();
|
||||
}
|
||||
|
||||
std::unordered_map<string, string> get_all() const {
|
||||
std::unordered_map<string, string, Hash<string>> get_all() const {
|
||||
return map_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<string, string> map_;
|
||||
std::unordered_map<string, string, Hash<string>> map_;
|
||||
SeqNo current_id_ = 0;
|
||||
SeqNo next_seq_no() {
|
||||
return ++current_id_;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "td/db/binlog/BinlogInterface.h"
|
||||
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/StorerBase.h"
|
||||
@ -83,8 +84,8 @@ bool EventId::is_valid_id(int32 id) {
|
||||
|
||||
class TQueueImpl final : public TQueue {
|
||||
static constexpr size_t MAX_EVENT_LENGTH = 65536 * 8;
|
||||
static constexpr size_t MAX_QUEUE_EVENTS = 1000000;
|
||||
static constexpr size_t MAX_TOTAL_EVENT_LENGTH = 1 << 30;
|
||||
static constexpr size_t MAX_QUEUE_EVENTS = 100000;
|
||||
static constexpr size_t MAX_TOTAL_EVENT_LENGTH = 1 << 27;
|
||||
|
||||
public:
|
||||
void set_callback(unique_ptr<StorageCallback> callback) final {
|
||||
@ -158,7 +159,9 @@ class TQueueImpl final : public TQueue {
|
||||
while (true) {
|
||||
if (q.tail_id.empty()) {
|
||||
if (hint_new_id.empty()) {
|
||||
q.tail_id = EventId::from_int32(Random::fast(2 * MAX_QUEUE_EVENTS + 1, EventId::MAX_ID / 2)).move_as_ok();
|
||||
q.tail_id = EventId::from_int32(
|
||||
Random::fast(2 * max(static_cast<int>(MAX_QUEUE_EVENTS), 1000000) + 1, EventId::MAX_ID / 2))
|
||||
.move_as_ok();
|
||||
} else {
|
||||
q.tail_id = hint_new_id;
|
||||
}
|
||||
@ -226,13 +229,22 @@ class TQueueImpl final : public TQueue {
|
||||
return;
|
||||
}
|
||||
|
||||
auto start_time = Time::now();
|
||||
auto total_event_length = q.total_event_length;
|
||||
|
||||
auto end_it = q.events.end();
|
||||
while (keep_count-- > 0) {
|
||||
for (size_t i = 0; i < keep_count; i++) {
|
||||
--end_it;
|
||||
}
|
||||
for (auto it = q.events.begin(); it != end_it;) {
|
||||
pop(q, queue_id, it, q.tail_id);
|
||||
}
|
||||
|
||||
auto clear_time = Time::now() - start_time;
|
||||
if (clear_time > 0.1) {
|
||||
LOG(WARNING) << "Cleared " << (size - keep_count) << " TQueue events with total size "
|
||||
<< (total_event_length - q.total_event_length) << " in " << clear_time << " seconds";
|
||||
}
|
||||
}
|
||||
|
||||
Result<size_t> get(QueueId queue_id, EventId from_id, bool forget_previous, int32 unix_time_now,
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "td/db/SeqKeyValue.h"
|
||||
|
||||
#include "td/utils/HashTableUtils.h"
|
||||
#include "td/utils/port/RwMutex.h"
|
||||
#include "td/utils/Slice.h"
|
||||
|
||||
@ -63,7 +64,7 @@ class TsSeqKeyValue {
|
||||
return kv_.size();
|
||||
}
|
||||
|
||||
std::unordered_map<string, string> get_all() const {
|
||||
std::unordered_map<string, string, Hash<string>> get_all() const {
|
||||
auto lock = rw_mutex_.lock_write().move_as_ok();
|
||||
return kv_.get_all();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ set(TDNET_SOURCE
|
||||
td/net/HttpQuery.cpp
|
||||
td/net/HttpReader.cpp
|
||||
td/net/Socks5.cpp
|
||||
td/net/SslCtx.cpp
|
||||
td/net/SslStream.cpp
|
||||
td/net/TcpListener.cpp
|
||||
td/net/TransparentProxy.cpp
|
||||
@ -42,6 +43,7 @@ set(TDNET_SOURCE
|
||||
td/net/HttpReader.h
|
||||
td/net/NetStats.h
|
||||
td/net/Socks5.h
|
||||
td/net/SslCtx.h
|
||||
td/net/SslStream.h
|
||||
td/net/TcpListener.h
|
||||
td/net/TransparentProxy.h
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "td/net/GetHostByNameActor.h"
|
||||
|
||||
#include "td/net/HttpQuery.h"
|
||||
#include "td/net/SslStream.h"
|
||||
#include "td/net/SslCtx.h"
|
||||
#include "td/net/Wget.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
@ -51,7 +51,7 @@ class GoogleDnsResolver final : public Actor {
|
||||
"GoogleDnsResolver", std::move(wget_promise),
|
||||
PSTRING() << "https://dns.google/resolve?name=" << url_encode(host_) << "&type=" << (prefer_ipv6_ ? 28 : 1),
|
||||
std::vector<std::pair<string, string>>({{"Host", "dns.google"}}), timeout, ttl, prefer_ipv6_,
|
||||
SslStream::VerifyPeer::Off);
|
||||
SslCtx::VerifyPeer::Off);
|
||||
}
|
||||
|
||||
static Result<IPAddress> get_ip_address(Result<unique_ptr<HttpQuery>> r_http_query) {
|
||||
|
@ -555,8 +555,6 @@ void HttpReader::process_header(MutableSlice header_name, MutableSlice header_va
|
||||
to_lower_inplace(header_name);
|
||||
LOG(DEBUG) << "Process header [" << header_name << "=>" << header_value << "]";
|
||||
query_->headers_.emplace_back(header_name, header_value);
|
||||
// TODO: check if protocol is HTTP/1.1
|
||||
query_->keep_alive_ = true;
|
||||
if (header_name == "content-length") {
|
||||
auto content_length = to_integer<uint64>(header_value);
|
||||
if (content_length > MAX_CONTENT_SIZE) {
|
||||
@ -567,6 +565,8 @@ void HttpReader::process_header(MutableSlice header_name, MutableSlice header_va
|
||||
to_lower_inplace(header_value);
|
||||
if (header_value == "close") {
|
||||
query_->keep_alive_ = false;
|
||||
} else {
|
||||
query_->keep_alive_ = true;
|
||||
}
|
||||
} else if (header_name == "content-type") {
|
||||
content_type_ = header_value;
|
||||
@ -706,8 +706,12 @@ Status HttpReader::parse_head(MutableSlice head) {
|
||||
} else if (type == "POST") {
|
||||
query_->type_ = HttpQuery::Type::Post;
|
||||
} else if (type.size() >= 4 && type.substr(0, 4) == "HTTP") {
|
||||
if (type == "HTTP/1.1" || type == "HTTP/1.0") {
|
||||
if (type == "HTTP/1.1") {
|
||||
query_->type_ = HttpQuery::Type::Response;
|
||||
query_->keep_alive_ = true;
|
||||
} else if (type == "HTTP/1.0") {
|
||||
query_->type_ = HttpQuery::Type::Response;
|
||||
query_->keep_alive_ = false;
|
||||
} else {
|
||||
LOG(INFO) << "Unsupported HTTP version: " << type;
|
||||
return Status::Error(505, "HTTP Version Not Supported");
|
||||
@ -748,7 +752,6 @@ Status HttpReader::parse_head(MutableSlice head) {
|
||||
transfer_encoding_ = Slice();
|
||||
content_encoding_ = Slice();
|
||||
|
||||
query_->keep_alive_ = false;
|
||||
query_->headers_.clear();
|
||||
query_->files_.clear();
|
||||
query_->content_ = MutableSlice();
|
||||
|
312
tdnet/td/net/SslCtx.cpp
Normal file
312
tdnet/td/net/SslCtx.cpp
Normal file
@ -0,0 +1,312 @@
|
||||
//
|
||||
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include "td/net/SslCtx.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "td/utils/FlatHashMap.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/port/wstring_convert.h"
|
||||
#include "td/utils/SliceBuilder.h"
|
||||
#include "td/utils/Time.h"
|
||||
|
||||
#if !TD_EMSCRIPTEN
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#if TD_PORT_WINDOWS
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
namespace td {
|
||||
|
||||
namespace detail {
|
||||
namespace {
|
||||
int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
if (!preverify_ok) {
|
||||
char buf[256];
|
||||
X509_NAME_oneline(X509_get_subject_name(X509_STORE_CTX_get_current_cert(ctx)), buf, 256);
|
||||
|
||||
int err = X509_STORE_CTX_get_error(ctx);
|
||||
auto warning = PSTRING() << "verify error:num=" << err << ":" << X509_verify_cert_error_string(err)
|
||||
<< ":depth=" << X509_STORE_CTX_get_error_depth(ctx) << ":" << Slice(buf, std::strlen(buf));
|
||||
double now = Time::now();
|
||||
|
||||
static std::mutex warning_mutex;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(warning_mutex);
|
||||
static FlatHashMap<string, double> next_warning_time;
|
||||
double &next = next_warning_time[warning];
|
||||
if (next <= now) {
|
||||
next = now + 300; // one warning per 5 minutes
|
||||
LOG(WARNING) << warning;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return preverify_ok;
|
||||
}
|
||||
|
||||
using SslCtxPtr = std::shared_ptr<SSL_CTX>;
|
||||
|
||||
Result<SslCtxPtr> do_create_ssl_ctx(CSlice cert_file, SslCtx::VerifyPeer verify_peer) {
|
||||
auto ssl_method =
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
TLS_client_method();
|
||||
#else
|
||||
SSLv23_client_method();
|
||||
#endif
|
||||
if (ssl_method == nullptr) {
|
||||
return create_openssl_error(-6, "Failed to create an SSL client method");
|
||||
}
|
||||
auto ssl_ctx = SSL_CTX_new(ssl_method);
|
||||
if (!ssl_ctx) {
|
||||
return create_openssl_error(-7, "Failed to create an SSL context");
|
||||
}
|
||||
auto ssl_ctx_ptr = SslCtxPtr(ssl_ctx, SSL_CTX_free);
|
||||
long options = 0;
|
||||
#ifdef SSL_OP_NO_SSLv2
|
||||
options |= SSL_OP_NO_SSLv2;
|
||||
#endif
|
||||
#ifdef SSL_OP_NO_SSLv3
|
||||
options |= SSL_OP_NO_SSLv3;
|
||||
#endif
|
||||
SSL_CTX_set_options(ssl_ctx, options);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_VERSION);
|
||||
#endif
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
|
||||
if (cert_file.empty()) {
|
||||
#if TD_PORT_WINDOWS
|
||||
LOG(DEBUG) << "Begin to load system store";
|
||||
auto flags = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER;
|
||||
HCERTSTORE system_store =
|
||||
CertOpenStore(CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, HCRYPTPROV_LEGACY(), flags,
|
||||
static_cast<const void *>(to_wstring("ROOT").ok().c_str()));
|
||||
|
||||
if (system_store) {
|
||||
X509_STORE *store = X509_STORE_new();
|
||||
|
||||
for (PCCERT_CONTEXT cert_context = CertEnumCertificatesInStore(system_store, nullptr); cert_context != nullptr;
|
||||
cert_context = CertEnumCertificatesInStore(system_store, cert_context)) {
|
||||
const unsigned char *in = cert_context->pbCertEncoded;
|
||||
X509 *x509 = d2i_X509(nullptr, &in, static_cast<long>(cert_context->cbCertEncoded));
|
||||
if (x509 != nullptr) {
|
||||
if (X509_STORE_add_cert(store, x509) != 1) {
|
||||
auto error_code = ERR_peek_error();
|
||||
auto error = create_openssl_error(-20, "Failed to add certificate");
|
||||
if (ERR_GET_REASON(error_code) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
|
||||
LOG(ERROR) << error;
|
||||
} else {
|
||||
LOG(INFO) << error;
|
||||
}
|
||||
}
|
||||
|
||||
X509_free(x509);
|
||||
} else {
|
||||
LOG(ERROR) << create_openssl_error(-21, "Failed to load X509 certificate");
|
||||
}
|
||||
}
|
||||
|
||||
CertCloseStore(system_store, 0);
|
||||
|
||||
SSL_CTX_set_cert_store(ssl_ctx, store);
|
||||
LOG(DEBUG) << "End to load system store";
|
||||
} else {
|
||||
LOG(ERROR) << create_openssl_error(-22, "Failed to open system certificate store");
|
||||
}
|
||||
#else
|
||||
if (SSL_CTX_set_default_verify_paths(ssl_ctx) == 0) {
|
||||
auto error = create_openssl_error(-8, "Failed to load default verify paths");
|
||||
if (verify_peer == SslCtx::VerifyPeer::On) {
|
||||
return std::move(error);
|
||||
} else {
|
||||
LOG(ERROR) << error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (SSL_CTX_load_verify_locations(ssl_ctx, cert_file.c_str(), nullptr) == 0) {
|
||||
return create_openssl_error(-8, "Failed to set custom certificate file");
|
||||
}
|
||||
}
|
||||
|
||||
if (verify_peer == SslCtx::VerifyPeer::On) {
|
||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback);
|
||||
|
||||
constexpr int DEFAULT_VERIFY_DEPTH = 10;
|
||||
SSL_CTX_set_verify_depth(ssl_ctx, DEFAULT_VERIFY_DEPTH);
|
||||
} else {
|
||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, nullptr);
|
||||
}
|
||||
|
||||
string cipher_list;
|
||||
if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list.empty() ? "DEFAULT" : cipher_list.c_str()) == 0) {
|
||||
return create_openssl_error(-9, PSLICE() << "Failed to set cipher list \"" << cipher_list << '"');
|
||||
}
|
||||
|
||||
return std::move(ssl_ctx_ptr);
|
||||
}
|
||||
|
||||
Result<SslCtxPtr> get_default_ssl_ctx() {
|
||||
static auto ctx = do_create_ssl_ctx(CSlice(), SslCtx::VerifyPeer::On);
|
||||
if (ctx.is_error()) {
|
||||
return ctx.error().clone();
|
||||
}
|
||||
|
||||
return ctx.ok();
|
||||
}
|
||||
|
||||
Result<SslCtxPtr> get_default_unverified_ssl_ctx() {
|
||||
static auto ctx = do_create_ssl_ctx(CSlice(), SslCtx::VerifyPeer::Off);
|
||||
if (ctx.is_error()) {
|
||||
return ctx.error().clone();
|
||||
}
|
||||
|
||||
return ctx.ok();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class SslCtxImpl {
|
||||
public:
|
||||
Status init(CSlice cert_file, SslCtx::VerifyPeer verify_peer) {
|
||||
SslCtx::init_openssl();
|
||||
|
||||
clear_openssl_errors("Before SslCtx::init");
|
||||
|
||||
if (cert_file.empty()) {
|
||||
if (verify_peer == SslCtx::VerifyPeer::On) {
|
||||
TRY_RESULT_ASSIGN(ssl_ctx_ptr_, get_default_ssl_ctx());
|
||||
} else {
|
||||
TRY_RESULT_ASSIGN(ssl_ctx_ptr_, get_default_unverified_ssl_ctx());
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
auto start_time = Time::now();
|
||||
auto r_ssl_ctx_ptr = do_create_ssl_ctx(cert_file, verify_peer);
|
||||
auto elapsed_time = Time::now() - start_time;
|
||||
if (elapsed_time >= 0.1) {
|
||||
LOG(ERROR) << "SSL context creation took " << elapsed_time << " seconds";
|
||||
}
|
||||
if (r_ssl_ctx_ptr.is_error()) {
|
||||
return r_ssl_ctx_ptr.move_as_error();
|
||||
}
|
||||
ssl_ctx_ptr_ = r_ssl_ctx_ptr.move_as_ok();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void *get_openssl_ctx() const {
|
||||
return static_cast<void *>(ssl_ctx_ptr_.get());
|
||||
}
|
||||
|
||||
private:
|
||||
SslCtxPtr ssl_ctx_ptr_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
SslCtx::SslCtx() = default;
|
||||
|
||||
SslCtx::SslCtx(const SslCtx &other) {
|
||||
if (other.impl_) {
|
||||
impl_ = make_unique<detail::SslCtxImpl>(*other.impl_);
|
||||
}
|
||||
}
|
||||
|
||||
SslCtx &SslCtx::operator=(const SslCtx &other) {
|
||||
if (other.impl_) {
|
||||
impl_ = make_unique<detail::SslCtxImpl>(*other.impl_);
|
||||
} else {
|
||||
impl_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SslCtx::SslCtx(SslCtx &&) noexcept = default;
|
||||
|
||||
SslCtx &SslCtx::operator=(SslCtx &&) noexcept = default;
|
||||
|
||||
SslCtx::~SslCtx() = default;
|
||||
|
||||
void SslCtx::init_openssl() {
|
||||
static bool is_inited = [] {
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
return OPENSSL_init_ssl(0, nullptr) != 0;
|
||||
#else
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
return OpenSSL_add_ssl_algorithms() != 0;
|
||||
#endif
|
||||
}();
|
||||
CHECK(is_inited);
|
||||
}
|
||||
|
||||
Result<SslCtx> SslCtx::create(CSlice cert_file, VerifyPeer verify_peer) {
|
||||
auto impl = make_unique<detail::SslCtxImpl>();
|
||||
TRY_STATUS(impl->init(cert_file, verify_peer));
|
||||
return SslCtx(std::move(impl));
|
||||
}
|
||||
|
||||
void *SslCtx::get_openssl_ctx() const {
|
||||
return impl_ == nullptr ? nullptr : impl_->get_openssl_ctx();
|
||||
}
|
||||
|
||||
SslCtx::SslCtx(unique_ptr<detail::SslCtxImpl> impl) : impl_(std::move(impl)) {
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
||||
#else
|
||||
|
||||
namespace td {
|
||||
|
||||
namespace detail {
|
||||
class SslCtxImpl {};
|
||||
} // namespace detail
|
||||
|
||||
SslCtx::SslCtx() = default;
|
||||
|
||||
SslCtx::SslCtx(const SslCtx &other) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
SslCtx &SslCtx::operator=(const SslCtx &other) {
|
||||
UNREACHABLE();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SslCtx::SslCtx(SslCtx &&) noexcept = default;
|
||||
|
||||
SslCtx &SslCtx::operator=(SslCtx &&) noexcept = default;
|
||||
|
||||
SslCtx::~SslCtx() = default;
|
||||
|
||||
void SslCtx::init_openssl() {
|
||||
}
|
||||
|
||||
Result<SslCtx> SslCtx::create(CSlice cert_file, VerifyPeer verify_peer) {
|
||||
return Status::Error("Not supported in Emscripten");
|
||||
}
|
||||
|
||||
void *SslCtx::get_openssl_ctx() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SslCtx::SslCtx(unique_ptr<detail::SslCtxImpl> impl) : impl_(std::move(impl)) {
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user