From 7c183449a885891783762bb5e46b7a28b369e0af Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 22 Jul 2018 20:22:19 +0300 Subject: [PATCH] Save language packs to database. GitOrigin-RevId: 2c40013068881e3170821585c25d29edcc78528c --- td/telegram/LanguagePackManager.cpp | 87 ++++++++++++++++++++++++++--- td/telegram/LanguagePackManager.h | 5 ++ 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/td/telegram/LanguagePackManager.cpp b/td/telegram/LanguagePackManager.cpp index 198150abc..a1b2207e1 100644 --- a/td/telegram/LanguagePackManager.cpp +++ b/td/telegram/LanguagePackManager.cpp @@ -23,6 +23,7 @@ #include "td/utils/Status.h" #include +#include namespace td { @@ -86,6 +87,15 @@ static Result open_database(const string &path) { return std::move(database); } +static int32 load_database_language_version(SqliteKeyValue *kv) { + string str_version = kv->get("!version"); + if (str_version.empty()) { + return -1; + } + + return to_integer(str_version); +} + void LanguagePackManager::start_up() { std::lock_guard lock(language_database_mutex_); manager_count_++; @@ -256,7 +266,7 @@ LanguagePackManager::Language *LanguagePackManager::get_language(LanguagePack *l } static string get_database_table_name(const string &language_pack, const string &language_code) { - return PSTRING() << language_pack << "_" << language_code; + return PSTRING() << "kv_" << language_pack << "_" << language_code; } LanguagePackManager::Language *LanguagePackManager::add_language(LanguageDatabase *database, @@ -418,12 +428,51 @@ void LanguagePackManager::get_language_pack_strings(string language_code, vector } } +bool LanguagePackManager::is_valid_key(Slice key) { + for (auto c : key) { + if (!is_alnum(c) && c != '_' && c != '.' && c != '-') { + return false; + } + } + return !key.empty(); +} + +void LanguagePackManager::add_strings_to_database(Language *language, int32 new_version, + vector> strings) { + if (new_version == -1 && strings.empty()) { + return; + } + + std::lock_guard lock(database_->mutex_); + auto kv = &language->kv_; + auto old_version = load_database_language_version(kv); + if (old_version >= new_version && (old_version != -1 || new_version != -1)) { + return; + } + + kv->begin_transaction(); + for (auto str : strings) { + if (!is_valid_key(str.first)) { + LOG(ERROR) << "Have invalid key \"" << str.first << '"'; + continue; + } + + kv->set(str.first, str.second); + } + if (old_version != new_version) { + kv->set("!version", to_string(new_version)); + } + kv->commit_transaction(); +} + void LanguagePackManager::on_get_language_pack_strings( string language_pack, string language_code, int32 version, bool is_diff, vector keys, vector> results, Promise> promise) { Language *language = get_language(database_, language_pack, language_code); bool is_version_changed = false; + int32 new_database_version = -1; + vector> database_strings; if (language == nullptr || (language->version_ < version || !keys.empty())) { if (language == nullptr) { language = add_language(database_, language_pack, language_code); @@ -435,6 +484,7 @@ void LanguagePackManager::on_get_language_pack_strings( if (language->version_ < version && !(is_diff && language->version_ == -1)) { LOG(INFO) << "Set language " << language_code << " version to " << version; language->version_ = version; + new_database_version = version; is_version_changed = true; } @@ -443,24 +493,40 @@ void LanguagePackManager::on_get_language_pack_strings( switch (result->get_id()) { case telegram_api::langPackString::ID: { auto str = static_cast(result.get()); - language->ordinary_strings_[str->key_] = std::move(str->value_); + auto it = language->ordinary_strings_.find(str->key_); + if (it == language->ordinary_strings_.end()) { + it = language->ordinary_strings_.emplace(str->key_, std::move(str->value_)).first; + } else { + it->second = 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_))); + strings.push_back(get_language_pack_string_object(*it)); } + database_strings.emplace_back(str->key_, PSTRING() << '1' << it->second); break; } case telegram_api::langPackStringPluralized::ID: { auto str = static_cast(result.get()); - language->pluralized_strings_[str->key_] = PluralizedString{ - std::move(str->zero_value_), std::move(str->one_value_), std::move(str->two_value_), - std::move(str->few_value_), std::move(str->many_value_), std::move(str->other_value_)}; + PluralizedString value{std::move(str->zero_value_), std::move(str->one_value_), + std::move(str->two_value_), std::move(str->few_value_), + std::move(str->many_value_), std::move(str->other_value_)}; + auto it = language->pluralized_strings_.find(str->key_); + if (it == language->pluralized_strings_.end()) { + it = language->pluralized_strings_.emplace(str->key_, std::move(value)).first; + } else { + it->second = std::move(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_))); + strings.push_back(get_language_pack_string_object(*it)); } + database_strings.emplace_back( + str->key_, PSTRING() << '2' << it->second.zero_value_ << '\x00' << it->second.one_value_ << '\x00' + << it->second.two_value_ << '\x00' << it->second.few_value_ << '\x00' + << it->second.many_value_ << '\x00' << it->second.other_value_); break; } case telegram_api::langPackStringDeleted::ID: { @@ -471,6 +537,7 @@ void LanguagePackManager::on_get_language_pack_strings( if (is_diff) { strings.push_back(get_language_pack_string_object(str->key_)); } + database_strings.emplace_back(str->key_, ""); break; } default: @@ -485,6 +552,7 @@ void LanguagePackManager::on_get_language_pack_strings( if (is_diff) { strings.push_back(get_language_pack_string_object(key)); } + database_strings.emplace_back(key, ""); } } @@ -493,10 +561,11 @@ void LanguagePackManager::on_get_language_pack_strings( send_closure(G()->td(), &Td::send_update, td_api::make_object(language_pack, language_code, std::move(strings))); } - - // TODO save language } } + + add_strings_to_database(language, new_database_version, std::move(database_strings)); + if (is_diff) { CHECK(language != nullptr); std::lock_guard lock(language->mutex_); diff --git a/td/telegram/LanguagePackManager.h b/td/telegram/LanguagePackManager.h index c56446149..e0346d805 100644 --- a/td/telegram/LanguagePackManager.h +++ b/td/telegram/LanguagePackManager.h @@ -15,6 +15,7 @@ #include "td/actor/PromiseFuture.h" #include "td/utils/Container.h" +#include "td/utils/Slice.h" #include "td/utils/Status.h" #include @@ -88,6 +89,10 @@ class LanguagePackManager : public NetQueryCallback { void inc_generation(); + bool is_valid_key(Slice key); + + void add_strings_to_database(Language *language, int32 new_version, vector> strings); + void on_get_language_pack_strings(string language_pack, string language_code, int32 version, bool is_diff, vector keys, vector> results, Promise> promise);