Support for language pack updatimg. td_api::updateLanguagePack.

GitOrigin-RevId: edc3bf65914b73d168d33eea38ff05cc2efd80ec
This commit is contained in:
levlam 2018-07-17 05:58:34 +03:00
parent f9726a5e19
commit e819a0ed56
8 changed files with 154 additions and 27 deletions

View File

@ -2210,6 +2210,9 @@ updateFavoriteStickers sticker_ids:vector<int32> = Update;
//@description The list of saved animations was updated @animation_ids The new list of file identifiers of saved animations //@description The list of saved animations was updated @animation_ids The new list of file identifiers of saved animations
updateSavedAnimations animation_ids:vector<int32> = Update; updateSavedAnimations animation_ids:vector<int32> = Update;
//@description Some language pack strings was updated @language_pack Changed language pack @language_code Code of the language, which was updated @strings List of changed language pack strings
updateLanguagePack language_pack:string language_code:string strings:vector<LanguagePackString> = Update;
//@description The connection state has changed @state The new connection state //@description The connection state has changed @state The new connection state
updateConnectionState state:ConnectionState = Update; updateConnectionState state:ConnectionState = Update;

Binary file not shown.

View File

@ -41,6 +41,7 @@ class ConfigManager;
class ConnectionCreator; class ConnectionCreator;
class ContactsManager; class ContactsManager;
class FileManager; class FileManager;
class LanguagePackManager;
class MtprotoHeader; class MtprotoHeader;
class MessagesManager; class MessagesManager;
class NetQueryDispatcher; class NetQueryDispatcher;
@ -159,6 +160,12 @@ class Global : public ActorContext {
void set_file_manager(ActorId<FileManager> file_manager) { void set_file_manager(ActorId<FileManager> file_manager) {
file_manager_ = std::move(file_manager); file_manager_ = std::move(file_manager);
} }
ActorId<LanguagePackManager> language_pack_manager() const {
return language_pack_manager_;
}
void set_language_pack_manager(ActorId<LanguagePackManager> language_pack_manager) {
language_pack_manager_ = language_pack_manager;
}
ActorId<MessagesManager> messages_manager() const { ActorId<MessagesManager> messages_manager() const {
return messages_manager_; return messages_manager_;
} }
@ -309,6 +316,7 @@ class Global : public ActorContext {
ActorId<ContactsManager> contacts_manager_; ActorId<ContactsManager> contacts_manager_;
ActorId<FileManager> file_manager_; ActorId<FileManager> file_manager_;
ActorId<MessagesManager> messages_manager_; ActorId<MessagesManager> messages_manager_;
ActorId<LanguagePackManager> language_pack_manager_;
ActorId<PasswordManager> password_manager_; ActorId<PasswordManager> password_manager_;
ActorId<SecretChatsManager> secret_chats_manager_; ActorId<SecretChatsManager> secret_chats_manager_;
ActorId<CallManager> call_manager_; ActorId<CallManager> call_manager_;

View File

@ -10,6 +10,7 @@
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/Td.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
@ -22,9 +23,9 @@ namespace td {
void LanguagePackManager::start_up() { void LanguagePackManager::start_up() {
language_pack_ = G()->shared_config().get_option_string("language_pack"); language_pack_ = G()->shared_config().get_option_string("language_pack");
language_code_ = G()->shared_config().get_option_string("language_code"); language_code_ = G()->shared_config().get_option_string("language_code");
language_pack_version_ = G()->shared_config().get_option_integer("language_pack_version", -1); LOG(INFO) << "Use language pack " << language_pack_ << " with language " << language_code_;
LOG(INFO) << "Use language pack " << language_pack_ << " with language " << language_code_ << " of version "
<< language_pack_version_; // TODO load language_pack_version from database
} }
void LanguagePackManager::on_language_pack_changed() { void LanguagePackManager::on_language_pack_changed() {
@ -47,23 +48,81 @@ void LanguagePackManager::on_language_code_changed() {
inc_generation(); inc_generation();
} }
void LanguagePackManager::on_language_pack_version_changed() { void LanguagePackManager::on_language_pack_version_changed(int32 new_version) {
auto new_language_pack_version = G()->shared_config().get_option_integer("language_pack_version"); Language *language = get_language(language_pack_, language_code_);
if (new_language_pack_version == language_pack_version_) { auto version = language == nullptr ? -1 : language->version_;
return; if (version == -1) {
}
if (language_pack_version_ == -1) {
return; return;
} }
// TODO update language pack auto new_language_pack_version =
language_pack_version_ = new_language_pack_version; new_version >= 0 ? new_version : G()->shared_config().get_option_integer("language_pack_version", -1);
if (new_language_pack_version <= version) {
return;
}
std::lock_guard<std::mutex> lock(language->mutex_);
if (language->has_get_difference_query_) {
return;
}
language->has_get_difference_query_ = true;
auto request_promise =
PromiseCreator::lambda([actor_id = actor_id(this), language_pack = language_pack_, language_code = language_code_,
from_version = version](Result<NetQueryPtr> r_query) mutable {
auto r_result = fetch_result<telegram_api::langpack_getDifference>(std::move(r_query));
if (r_result.is_error()) {
send_closure(actor_id, &LanguagePackManager::on_failed_get_difference, std::move(language_pack),
std::move(language_code));
return;
}
auto result = r_result.move_as_ok();
LOG(INFO) << "Receive language pack difference for language " << result->lang_code_ << " from version "
<< result->from_version_ << " with version " << result->version_ << " of size "
<< result->strings_.size();
LOG_IF(ERROR, result->lang_code_ != language_code)
<< "Receive strings for " << result->lang_code_ << " instead of " << language_code;
LOG_IF(ERROR, result->from_version_ != from_version)
<< "Receive strings from " << result->from_version_ << " instead of " << from_version;
send_closure(actor_id, &LanguagePackManager::on_get_language_pack_strings, std::move(language_pack),
std::move(language_code), result->version_, true, vector<string>(), std::move(result->strings_),
Promise<td_api::object_ptr<td_api::languagePackStrings>>());
});
send_with_promise(G()->net_query_creator().create(create_storer(telegram_api::langpack_getDifference(version))),
std::move(request_promise));
}
void LanguagePackManager::on_update_language_pack(tl_object_ptr<telegram_api::langPackDifference> difference) {
LOG(INFO) << "Receive update language pack difference for language " << difference->lang_code_ << " from version "
<< difference->from_version_ << " with version " << difference->version_ << " of size "
<< difference->strings_.size();
if (difference->lang_code_ != language_code_) {
LOG(WARNING) << "Ignore difference for language " << difference->lang_code_;
return;
}
Language *language = get_language(language_pack_, language_code_);
auto version = language == nullptr ? -1 : language->version_;
if (difference->version_ <= version) {
LOG(INFO) << "Skip applying already applied updates";
return;
}
if (version == -1 || version < difference->from_version_) {
LOG(INFO) << "Can't apply difference";
return on_language_pack_version_changed(difference->version_);
}
on_get_language_pack_strings(language_pack_, std::move(difference->lang_code_), difference->version_, true,
vector<string>(), std::move(difference->strings_),
Promise<td_api::object_ptr<td_api::languagePackStrings>>());
} }
void LanguagePackManager::inc_generation() { void LanguagePackManager::inc_generation() {
generation_++; generation_++;
G()->shared_config().set_option_empty("language_pack_version"); G()->shared_config().set_option_empty("language_pack_version");
language_pack_version_ = -1;
// TODO preload language and load language_pack_version from database
} }
LanguagePackManager::Language *LanguagePackManager::get_language(const string &language_pack, LanguagePackManager::Language *LanguagePackManager::get_language(const string &language_pack,
@ -221,7 +280,7 @@ void LanguagePackManager::get_language_pack_strings(string language_code, vector
<< "Receive strings for " << result->lang_code_ << " instead of " << language_code; << "Receive strings for " << result->lang_code_ << " instead of " << language_code;
LOG_IF(ERROR, result->from_version_ != 0) << "Receive lang pack from version " << result->from_version_; LOG_IF(ERROR, result->from_version_ != 0) << "Receive lang pack from version " << result->from_version_;
send_closure(actor_id, &LanguagePackManager::on_get_language_pack_strings, std::move(language_pack), send_closure(actor_id, &LanguagePackManager::on_get_language_pack_strings, std::move(language_pack),
std::move(language_code), result->version_, vector<string>(), std::move(result->strings_), std::move(language_code), result->version_, false, vector<string>(), std::move(result->strings_),
std::move(promise)); std::move(promise));
}); });
send_with_promise(G()->net_query_creator().create(create_storer(telegram_api::langpack_getLangPack(language_code))), send_with_promise(G()->net_query_creator().create(create_storer(telegram_api::langpack_getLangPack(language_code))),
@ -236,7 +295,7 @@ void LanguagePackManager::get_language_pack_strings(string language_code, vector
} }
send_closure(actor_id, &LanguagePackManager::on_get_language_pack_strings, std::move(language_pack), send_closure(actor_id, &LanguagePackManager::on_get_language_pack_strings, std::move(language_pack),
std::move(language_code), -1, std::move(keys), r_result.move_as_ok(), std::move(promise)); std::move(language_code), -1, false, std::move(keys), r_result.move_as_ok(), std::move(promise));
}); });
send_with_promise(G()->net_query_creator().create( send_with_promise(G()->net_query_creator().create(
create_storer(telegram_api::langpack_getStrings(language_code, std::move(keys)))), create_storer(telegram_api::langpack_getStrings(language_code, std::move(keys)))),
@ -245,10 +304,11 @@ void LanguagePackManager::get_language_pack_strings(string language_code, vector
} }
void LanguagePackManager::on_get_language_pack_strings( void LanguagePackManager::on_get_language_pack_strings(
string language_pack, string language_code, int32 version, vector<string> keys, string language_pack, string language_code, int32 version, bool is_diff, vector<string> keys,
vector<tl_object_ptr<telegram_api::LangPackString>> results, vector<tl_object_ptr<telegram_api::LangPackString>> results,
Promise<td_api::object_ptr<td_api::languagePackStrings>> promise) { Promise<td_api::object_ptr<td_api::languagePackStrings>> promise) {
Language *language = get_language(language_pack, language_code); Language *language = get_language(language_pack, language_code);
bool is_version_changed = false;
if (language == nullptr || (language->version_ < version || !keys.empty())) { if (language == nullptr || (language->version_ < version || !keys.empty())) {
if (language == nullptr) { if (language == nullptr) {
language = add_language(language_pack, language_code); language = add_language(language_pack, language_code);
@ -256,9 +316,13 @@ void LanguagePackManager::on_get_language_pack_strings(
} }
std::lock_guard<std::mutex> lock(language->mutex_); std::lock_guard<std::mutex> lock(language->mutex_);
if (language->version_ < version || !keys.empty()) { if (language->version_ < version || !keys.empty()) {
if (language->version_ < version) { vector<td_api::object_ptr<td_api::LanguagePackString>> strings;
if (language->version_ < version && !(is_diff && language->version_ == -1)) {
LOG(INFO) << "Set language " << language_code << " version to " << version;
language->version_ = version; language->version_ = version;
is_version_changed = true;
} }
for (auto &result : results) { for (auto &result : results) {
CHECK(result != nullptr); CHECK(result != nullptr);
switch (result->get_id()) { switch (result->get_id()) {
@ -267,6 +331,9 @@ void LanguagePackManager::on_get_language_pack_strings(
language->ordinary_strings_[str->key_] = std::move(str->value_); language->ordinary_strings_[str->key_] = std::move(str->value_);
language->pluralized_strings_.erase(str->key_); language->pluralized_strings_.erase(str->key_);
language->deleted_strings_.erase(str->key_); language->deleted_strings_.erase(str->key_);
if (is_diff) {
strings.push_back(get_language_pack_string_object(*language->ordinary_strings_.find(str->key_)));
}
break; break;
} }
case telegram_api::langPackStringPluralized::ID: { case telegram_api::langPackStringPluralized::ID: {
@ -276,6 +343,9 @@ void LanguagePackManager::on_get_language_pack_strings(
std::move(str->few_value_), std::move(str->many_value_), std::move(str->other_value_)}; std::move(str->few_value_), std::move(str->many_value_), std::move(str->other_value_)};
language->ordinary_strings_.erase(str->key_); language->ordinary_strings_.erase(str->key_);
language->deleted_strings_.erase(str->key_); language->deleted_strings_.erase(str->key_);
if (is_diff) {
strings.push_back(get_language_pack_string_object(*language->pluralized_strings_.find(str->key_)));
}
break; break;
} }
case telegram_api::langPackStringDeleted::ID: { case telegram_api::langPackStringDeleted::ID: {
@ -283,6 +353,9 @@ void LanguagePackManager::on_get_language_pack_strings(
language->ordinary_strings_.erase(str->key_); language->ordinary_strings_.erase(str->key_);
language->pluralized_strings_.erase(str->key_); language->pluralized_strings_.erase(str->key_);
language->deleted_strings_.insert(std::move(str->key_)); language->deleted_strings_.insert(std::move(str->key_));
if (is_diff) {
strings.push_back(get_language_pack_string_object(str->key_));
}
break; break;
} }
default: default:
@ -294,15 +367,49 @@ void LanguagePackManager::on_get_language_pack_strings(
if (!language_has_string_unsafe(language, key)) { if (!language_has_string_unsafe(language, key)) {
LOG(ERROR) << "Doesn't receive key " << key << " from server"; LOG(ERROR) << "Doesn't receive key " << key << " from server";
language->deleted_strings_.insert(key); language->deleted_strings_.insert(key);
if (is_diff) {
strings.push_back(get_language_pack_string_object(key));
} }
} }
}
if (is_diff) {
// do we need to send update to all client instances?
send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateLanguagePack>(language_pack, language_code, std::move(strings)));
}
// TODO save language // TODO save language
} }
} }
if (is_diff) {
CHECK(language != nullptr);
std::lock_guard<std::mutex> lock(language->mutex_);
if (language->has_get_difference_query_) {
language->has_get_difference_query_ = false;
is_version_changed = true;
}
}
if (is_version_changed && language_pack == language_pack_ && language_code == language_code_) {
send_closure_later(actor_id(this), &LanguagePackManager::on_language_pack_version_changed, -1);
}
if (promise) {
promise.set_value(get_language_pack_strings_object(language, keys)); promise.set_value(get_language_pack_strings_object(language, keys));
} }
}
void LanguagePackManager::on_failed_get_difference(string language_pack, string language_code) {
Language *language = get_language(language_pack, language_code);
CHECK(language != nullptr);
std::lock_guard<std::mutex> lock(language->mutex_);
if (language->has_get_difference_query_) {
language->has_get_difference_query_ = false;
if (language_pack == language_pack_ && language_code == language_code_) {
send_closure_later(actor_id(this), &LanguagePackManager::on_language_pack_version_changed, -1);
}
}
}
void LanguagePackManager::on_result(NetQueryPtr query) { void LanguagePackManager::on_result(NetQueryPtr query) {
auto token = get_link_token(); auto token = get_link_token();

View File

@ -33,13 +33,15 @@ class LanguagePackManager : public NetQueryCallback {
void on_language_code_changed(); void on_language_code_changed();
void on_language_pack_version_changed(); void on_language_pack_version_changed(int32 new_version);
void get_languages(Promise<td_api::object_ptr<td_api::languagePack>> promise); void get_languages(Promise<td_api::object_ptr<td_api::languagePack>> promise);
void get_language_pack_strings(string language_code, vector<string> keys, void get_language_pack_strings(string language_code, vector<string> keys,
Promise<td_api::object_ptr<td_api::languagePackStrings>> promise); Promise<td_api::object_ptr<td_api::languagePackStrings>> promise);
void on_update_language_pack(tl_object_ptr<telegram_api::langPackDifference> difference);
private: private:
struct PluralizedString { struct PluralizedString {
string zero_value_; string zero_value_;
@ -53,6 +55,7 @@ class LanguagePackManager : public NetQueryCallback {
struct Language { struct Language {
std::mutex mutex_; // TODO RwMutex std::mutex mutex_; // TODO RwMutex
std::atomic<int32> version_{-1}; std::atomic<int32> version_{-1};
bool has_get_difference_query_ = false;
std::unordered_map<string, string> ordinary_strings_; std::unordered_map<string, string> ordinary_strings_;
std::unordered_map<string, PluralizedString> pluralized_strings_; std::unordered_map<string, PluralizedString> pluralized_strings_;
std::unordered_set<string> deleted_strings_; std::unordered_set<string> deleted_strings_;
@ -69,8 +72,6 @@ class LanguagePackManager : public NetQueryCallback {
string language_code_; string language_code_;
uint32 generation_ = 0; uint32 generation_ = 0;
int32 language_pack_version_ = -1;
static std::mutex language_packs_mutex_; static std::mutex language_packs_mutex_;
static std::unordered_map<string, std::unique_ptr<LanguagePack>> language_packs_; static std::unordered_map<string, std::unique_ptr<LanguagePack>> language_packs_;
@ -93,10 +94,12 @@ class LanguagePackManager : public NetQueryCallback {
void inc_generation(); void inc_generation();
void on_get_language_pack_strings(string language_pack, string language_code, int32 version, vector<string> keys, void on_get_language_pack_strings(string language_pack, string language_code, int32 version, bool is_diff,
vector<tl_object_ptr<telegram_api::LangPackString>> results, vector<string> keys, vector<tl_object_ptr<telegram_api::LangPackString>> results,
Promise<td_api::object_ptr<td_api::languagePackStrings>> promise); Promise<td_api::object_ptr<td_api::languagePackStrings>> promise);
void on_failed_get_difference(string language_pack, string language_code);
void on_result(NetQueryPtr query) override; void on_result(NetQueryPtr query) override;
void start_up() override; void start_up() override;

View File

@ -3512,7 +3512,7 @@ void Td::on_config_option_updated(const string &name) {
G()->net_query_dispatcher().update_mtproto_header(); G()->net_query_dispatcher().update_mtproto_header();
} }
} else if (name == "language_pack_version") { } else if (name == "language_pack_version") {
send_closure(language_pack_manager_, &LanguagePackManager::on_language_pack_version_changed); send_closure(language_pack_manager_, &LanguagePackManager::on_language_pack_version_changed, -1);
return; return;
} else if (is_internal_config_option(name)) { } else if (is_internal_config_option(name)) {
return; return;
@ -4075,6 +4075,7 @@ Status Td::init(DbKey key) {
device_token_manager_ = create_actor<DeviceTokenManager>("DeviceTokenManager", create_reference()); device_token_manager_ = create_actor<DeviceTokenManager>("DeviceTokenManager", create_reference());
hashtag_hints_ = create_actor<HashtagHints>("HashtagHints", "text", create_reference()); hashtag_hints_ = create_actor<HashtagHints>("HashtagHints", "text", create_reference());
language_pack_manager_ = create_actor<LanguagePackManager>("LanguagePackManager", create_reference()); language_pack_manager_ = create_actor<LanguagePackManager>("LanguagePackManager", create_reference());
G()->set_language_pack_manager(language_pack_manager_.get());
password_manager_ = create_actor<PasswordManager>("PasswordManager", create_reference()); password_manager_ = create_actor<PasswordManager>("PasswordManager", create_reference());
G()->set_password_manager(password_manager_.get()); G()->set_password_manager(password_manager_.get());
privacy_manager_ = create_actor<PrivacyManager>("PrivacyManager", create_reference()); privacy_manager_ = create_actor<PrivacyManager>("PrivacyManager", create_reference());

View File

@ -19,6 +19,7 @@
#include "td/telegram/DialogId.h" #include "td/telegram/DialogId.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/InlineQueriesManager.h" #include "td/telegram/InlineQueriesManager.h"
#include "td/telegram/LanguagePackManager.h"
#include "td/telegram/Location.h" #include "td/telegram/Location.h"
#include "td/telegram/MessageId.h" #include "td/telegram/MessageId.h"
#include "td/telegram/MessagesManager.h" #include "td/telegram/MessagesManager.h"
@ -1816,12 +1817,16 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateContactsReset>
td_->contacts_manager_->on_update_contacts_reset(); td_->contacts_manager_->on_update_contacts_reset();
} }
// unsupported updates
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateLangPackTooLong> update, bool /*force_apply*/) { void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateLangPackTooLong> update, bool /*force_apply*/) {
send_closure(G()->language_pack_manager(), &LanguagePackManager::on_language_pack_version_changed,
std::numeric_limits<int32>::max());
} }
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateLangPack> update, bool /*force_apply*/) { void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateLangPack> update, bool /*force_apply*/) {
send_closure(G()->language_pack_manager(), &LanguagePackManager::on_update_language_pack,
std::move(update->difference_));
} }
// unsupported updates
} // namespace td } // namespace td

View File

@ -267,10 +267,10 @@ class UpdatesManager : public Actor {
void on_update(tl_object_ptr<telegram_api::updateContactsReset> update, bool /*force_apply*/); void on_update(tl_object_ptr<telegram_api::updateContactsReset> update, bool /*force_apply*/);
// unsupported updates
void on_update(tl_object_ptr<telegram_api::updateLangPackTooLong> update, bool /*force_apply*/); void on_update(tl_object_ptr<telegram_api::updateLangPackTooLong> update, bool /*force_apply*/);
void on_update(tl_object_ptr<telegram_api::updateLangPack> update, bool /*force_apply*/); void on_update(tl_object_ptr<telegram_api::updateLangPack> update, bool /*force_apply*/);
// unsupported updates
}; };
} // namespace td } // namespace td