From e819a0ed567872389aa8556a2261c4abec0b381a Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 17 Jul 2018 05:58:34 +0300 Subject: [PATCH] Support for language pack updatimg. td_api::updateLanguagePack. GitOrigin-RevId: edc3bf65914b73d168d33eea38ff05cc2efd80ec --- td/generate/scheme/td_api.tl | 3 + td/generate/scheme/td_api.tlo | Bin 129176 -> 129368 bytes td/telegram/Global.h | 8 ++ td/telegram/LanguagePackManager.cpp | 141 ++++++++++++++++++++++++---- td/telegram/LanguagePackManager.h | 13 ++- td/telegram/Td.cpp | 3 +- td/telegram/UpdatesManager.cpp | 9 +- td/telegram/UpdatesManager.h | 4 +- 8 files changed, 154 insertions(+), 27 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index eb9878f13..ac5e62b76 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2210,6 +2210,9 @@ updateFavoriteStickers sticker_ids:vector = Update; //@description The list of saved animations was updated @animation_ids The new list of file identifiers of saved animations updateSavedAnimations animation_ids:vector = 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 = Update; + //@description The connection state has changed @state The new connection state updateConnectionState state:ConnectionState = Update; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index b442faaa543f6b8d1f38548648ddb8fd1835c948..d72152a79cc1c86790964dd9aec419bb43d5b6a6 100644 GIT binary patch delta 1518 zcmZ8hO-vI}5N7z7pjLu`C=!Vfif+Re3KVFe<);)_=$4;&kc3ttpjJ{95;WBmMd6^P zW*Z)flGKP7<6#XX9ONJu<$wnhO-e$viNq5JA)0W|#ND^^D7vS~H#6US?|buhb~`P) zlO{LkXS&WTr1ts;yrY8&)&+NdX%e{aP82Ln6hP=ul9D9ZJXmSa!$T1b0z5pVL8cLm zG_V<=mj<&&Fr+J8>+iCJL^8ocF$t7Gq2xK6o_t+pD=dQ&S}B&n3mWV)B=izQGFp!L zNI6c6Jpxhcds9TLCg5m?&x9$pL-H->%~Zevn#rsH0}b{Bg&9KGV-~2Od7%;tXyC8J zBg`|zRs{w!mjb6W!Fg3!so-wf60SmtZ>!)2MJ#5l@tCn@(Toz68jc7%aFTdxu&t*$ zE|Md1H450Q#=NcuX&=-;HRV@M!x8;9STsqd+Wq9ywcw>yTeV0)%bP6N9JItQi6eUs zU6x{{3soK_6!O{c2h| z96CnU=b>1NE}Auk!vd7B{|rb5K8MHxI=s3sl}P3;L8;_FpF#{Bz*B{u4o$NZyNdF7OnB(yP delta 1433 zcmY*ZUr1A76!)i7my8%;=!1!p(gs(&)A@hXP3N3C-JMQ)$Y_E>(V|rb7KVzIJ{TEy z^a&a4p`Lmf73?7&tcUO=NGLE6^1+857Gy>E&_nlr_k3>Mr^E03&hPxb^PTVR{48EO zC{FcOS~3_e8jDX(Oi$&xUWF^`3!p46RHqlJv3k5fOR`cKZXQHr)be0f#seN$9B}Z! zgX)*PraYgJ#~p9to&1sP}9Yy)c4=vlMrhOSoA06S+Y4S3Fj!z1Jc6gJ&R`D7z? zOFo36j=!m8ZYLyO5pz;X(JIu~M#bYM9OD^F6Y6+yWGEpJoy+!IXyW-`GpczIZ>A$W z6Nsk;b?j*&P8)_RT8OFPVP2AGA&Z+WxWy4yD{-Q&#ChFH7B!B_a?E;1X`KZLsOabP;S+OYn*NJ z(oy6^NNQ5DvWs4vG=#i3#e<}moPHAIzh3g-?56VZZbA|Q*$~KYf#@w*pofM(BZA}{ zoNTv;>PvmO3+#P~dN$*uTuRGvM|(bmZQ3^H(f7HsWcYuz{CzztwE+2cerlMPYu@nba^{|8p5HUh9LD(5bYDY)|XY(-dq6Z zj^2Y3pn=Z@u+3X2{j{np`%sJ<-|DBX@;k&0C^jIB3&dGMBjKap^ zAq3d^7Od file_manager) { file_manager_ = std::move(file_manager); } + ActorId language_pack_manager() const { + return language_pack_manager_; + } + void set_language_pack_manager(ActorId language_pack_manager) { + language_pack_manager_ = language_pack_manager; + } ActorId messages_manager() const { return messages_manager_; } @@ -309,6 +316,7 @@ class Global : public ActorContext { ActorId contacts_manager_; ActorId file_manager_; ActorId messages_manager_; + ActorId language_pack_manager_; ActorId password_manager_; ActorId secret_chats_manager_; ActorId call_manager_; diff --git a/td/telegram/LanguagePackManager.cpp b/td/telegram/LanguagePackManager.cpp index ece5be945..97bff7d88 100644 --- a/td/telegram/LanguagePackManager.cpp +++ b/td/telegram/LanguagePackManager.cpp @@ -10,6 +10,7 @@ #include "td/telegram/Global.h" #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/net/NetQueryDispatcher.h" +#include "td/telegram/Td.h" #include "td/utils/logging.h" #include "td/utils/misc.h" @@ -22,9 +23,9 @@ namespace td { void LanguagePackManager::start_up() { language_pack_ = G()->shared_config().get_option_string("language_pack"); 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_ << " of version " - << language_pack_version_; + LOG(INFO) << "Use language pack " << language_pack_ << " with language " << language_code_; + + // TODO load language_pack_version from database } void LanguagePackManager::on_language_pack_changed() { @@ -47,23 +48,81 @@ void LanguagePackManager::on_language_code_changed() { inc_generation(); } -void LanguagePackManager::on_language_pack_version_changed() { - auto new_language_pack_version = G()->shared_config().get_option_integer("language_pack_version"); - if (new_language_pack_version == language_pack_version_) { - return; - } - if (language_pack_version_ == -1) { +void LanguagePackManager::on_language_pack_version_changed(int32 new_version) { + Language *language = get_language(language_pack_, language_code_); + auto version = language == nullptr ? -1 : language->version_; + if (version == -1) { return; } - // TODO update language pack - language_pack_version_ = new_language_pack_version; + auto 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 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 r_query) mutable { + auto r_result = fetch_result(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(), std::move(result->strings_), + Promise>()); + }); + 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 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(), std::move(difference->strings_), + Promise>()); } void LanguagePackManager::inc_generation() { generation_++; 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, @@ -221,7 +280,7 @@ void LanguagePackManager::get_language_pack_strings(string language_code, vector << "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_; send_closure(actor_id, &LanguagePackManager::on_get_language_pack_strings, std::move(language_pack), - std::move(language_code), result->version_, vector(), std::move(result->strings_), + std::move(language_code), result->version_, false, vector(), std::move(result->strings_), std::move(promise)); }); 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), - 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( 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( - string language_pack, string language_code, int32 version, vector keys, + string language_pack, string language_code, int32 version, bool is_diff, vector keys, vector> results, Promise> promise) { 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 = add_language(language_pack, language_code); @@ -256,9 +316,13 @@ void LanguagePackManager::on_get_language_pack_strings( } std::lock_guard lock(language->mutex_); if (language->version_ < version || !keys.empty()) { - if (language->version_ < version) { + vector> strings; + if (language->version_ < version && !(is_diff && language->version_ == -1)) { + LOG(INFO) << "Set language " << language_code << " version to " << version; language->version_ = version; + is_version_changed = true; } + for (auto &result : results) { CHECK(result != nullptr); 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->pluralized_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; } 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_)}; language->ordinary_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; } case telegram_api::langPackStringDeleted::ID: { @@ -283,6 +353,9 @@ void LanguagePackManager::on_get_language_pack_strings( language->ordinary_strings_.erase(str->key_); language->pluralized_strings_.erase(str->key_); language->deleted_strings_.insert(std::move(str->key_)); + if (is_diff) { + strings.push_back(get_language_pack_string_object(str->key_)); + } break; } default: @@ -294,14 +367,48 @@ void LanguagePackManager::on_get_language_pack_strings( if (!language_has_string_unsafe(language, key)) { LOG(ERROR) << "Doesn't receive key " << key << " from server"; 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(language_pack, language_code, std::move(strings))); + } + // TODO save language } } + if (is_diff) { + CHECK(language != nullptr); + std::lock_guard 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); + } - promise.set_value(get_language_pack_strings_object(language, keys)); + if (promise) { + 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 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) { diff --git a/td/telegram/LanguagePackManager.h b/td/telegram/LanguagePackManager.h index 4799ca552..cbe388edc 100644 --- a/td/telegram/LanguagePackManager.h +++ b/td/telegram/LanguagePackManager.h @@ -33,13 +33,15 @@ class LanguagePackManager : public NetQueryCallback { void on_language_code_changed(); - void on_language_pack_version_changed(); + void on_language_pack_version_changed(int32 new_version); void get_languages(Promise> promise); void get_language_pack_strings(string language_code, vector keys, Promise> promise); + void on_update_language_pack(tl_object_ptr difference); + private: struct PluralizedString { string zero_value_; @@ -53,6 +55,7 @@ class LanguagePackManager : public NetQueryCallback { struct Language { std::mutex mutex_; // TODO RwMutex std::atomic version_{-1}; + bool has_get_difference_query_ = false; std::unordered_map ordinary_strings_; std::unordered_map pluralized_strings_; std::unordered_set deleted_strings_; @@ -69,8 +72,6 @@ class LanguagePackManager : public NetQueryCallback { string language_code_; uint32 generation_ = 0; - int32 language_pack_version_ = -1; - static std::mutex language_packs_mutex_; static std::unordered_map> language_packs_; @@ -93,10 +94,12 @@ class LanguagePackManager : public NetQueryCallback { void inc_generation(); - void on_get_language_pack_strings(string language_pack, string language_code, int32 version, vector keys, - vector> results, + void on_get_language_pack_strings(string language_pack, string language_code, int32 version, bool is_diff, + vector keys, vector> results, Promise> promise); + void on_failed_get_difference(string language_pack, string language_code); + void on_result(NetQueryPtr query) override; void start_up() override; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index f667a2429..b265f8a57 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -3512,7 +3512,7 @@ void Td::on_config_option_updated(const string &name) { G()->net_query_dispatcher().update_mtproto_header(); } } 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; } else if (is_internal_config_option(name)) { return; @@ -4075,6 +4075,7 @@ Status Td::init(DbKey key) { device_token_manager_ = create_actor("DeviceTokenManager", create_reference()); hashtag_hints_ = create_actor("HashtagHints", "text", create_reference()); language_pack_manager_ = create_actor("LanguagePackManager", create_reference()); + G()->set_language_pack_manager(language_pack_manager_.get()); password_manager_ = create_actor("PasswordManager", create_reference()); G()->set_password_manager(password_manager_.get()); privacy_manager_ = create_actor("PrivacyManager", create_reference()); diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 80895b24e..ff0716e8f 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -19,6 +19,7 @@ #include "td/telegram/DialogId.h" #include "td/telegram/Global.h" #include "td/telegram/InlineQueriesManager.h" +#include "td/telegram/LanguagePackManager.h" #include "td/telegram/Location.h" #include "td/telegram/MessageId.h" #include "td/telegram/MessagesManager.h" @@ -1816,12 +1817,16 @@ void UpdatesManager::on_update(tl_object_ptr td_->contacts_manager_->on_update_contacts_reset(); } -// unsupported updates - void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/) { + send_closure(G()->language_pack_manager(), &LanguagePackManager::on_language_pack_version_changed, + std::numeric_limits::max()); } void UpdatesManager::on_update(tl_object_ptr update, bool /*force_apply*/) { + send_closure(G()->language_pack_manager(), &LanguagePackManager::on_update_language_pack, + std::move(update->difference_)); } +// unsupported updates + } // namespace td diff --git a/td/telegram/UpdatesManager.h b/td/telegram/UpdatesManager.h index 7a92f8c5c..473589527 100644 --- a/td/telegram/UpdatesManager.h +++ b/td/telegram/UpdatesManager.h @@ -267,10 +267,10 @@ class UpdatesManager : public Actor { void on_update(tl_object_ptr update, bool /*force_apply*/); - // unsupported updates - void on_update(tl_object_ptr update, bool /*force_apply*/); void on_update(tl_object_ptr update, bool /*force_apply*/); + + // unsupported updates }; } // namespace td