Save language packs to database.

GitOrigin-RevId: 2c40013068881e3170821585c25d29edcc78528c
This commit is contained in:
levlam 2018-07-22 20:22:19 +03:00
parent a7c2a401b8
commit 7c183449a8
2 changed files with 83 additions and 9 deletions

View File

@ -23,6 +23,7 @@
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include <atomic> #include <atomic>
#include <utility>
namespace td { namespace td {
@ -86,6 +87,15 @@ static Result<SqliteDb> open_database(const string &path) {
return std::move(database); 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<int32>(str_version);
}
void LanguagePackManager::start_up() { void LanguagePackManager::start_up() {
std::lock_guard<std::mutex> lock(language_database_mutex_); std::lock_guard<std::mutex> lock(language_database_mutex_);
manager_count_++; 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) { 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, 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<std::pair<string, string>> strings) {
if (new_version == -1 && strings.empty()) {
return;
}
std::lock_guard<std::mutex> 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( void LanguagePackManager::on_get_language_pack_strings(
string language_pack, string language_code, int32 version, bool is_diff, 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(database_, language_pack, language_code); Language *language = get_language(database_, language_pack, language_code);
bool is_version_changed = false; bool is_version_changed = false;
int32 new_database_version = -1;
vector<std::pair<string, string>> database_strings;
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(database_, language_pack, language_code); 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)) { if (language->version_ < version && !(is_diff && language->version_ == -1)) {
LOG(INFO) << "Set language " << language_code << " version to " << version; LOG(INFO) << "Set language " << language_code << " version to " << version;
language->version_ = version; language->version_ = version;
new_database_version = version;
is_version_changed = true; is_version_changed = true;
} }
@ -443,24 +493,40 @@ void LanguagePackManager::on_get_language_pack_strings(
switch (result->get_id()) { switch (result->get_id()) {
case telegram_api::langPackString::ID: { case telegram_api::langPackString::ID: {
auto str = static_cast<telegram_api::langPackString *>(result.get()); auto str = static_cast<telegram_api::langPackString *>(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->pluralized_strings_.erase(str->key_);
language->deleted_strings_.erase(str->key_); language->deleted_strings_.erase(str->key_);
if (is_diff) { 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; break;
} }
case telegram_api::langPackStringPluralized::ID: { case telegram_api::langPackStringPluralized::ID: {
auto str = static_cast<const telegram_api::langPackStringPluralized *>(result.get()); auto str = static_cast<const telegram_api::langPackStringPluralized *>(result.get());
language->pluralized_strings_[str->key_] = PluralizedString{ PluralizedString value{std::move(str->zero_value_), std::move(str->one_value_),
std::move(str->zero_value_), std::move(str->one_value_), std::move(str->two_value_), std::move(str->two_value_), std::move(str->few_value_),
std::move(str->few_value_), std::move(str->many_value_), std::move(str->other_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->ordinary_strings_.erase(str->key_);
language->deleted_strings_.erase(str->key_); language->deleted_strings_.erase(str->key_);
if (is_diff) { 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; break;
} }
case telegram_api::langPackStringDeleted::ID: { case telegram_api::langPackStringDeleted::ID: {
@ -471,6 +537,7 @@ void LanguagePackManager::on_get_language_pack_strings(
if (is_diff) { if (is_diff) {
strings.push_back(get_language_pack_string_object(str->key_)); strings.push_back(get_language_pack_string_object(str->key_));
} }
database_strings.emplace_back(str->key_, "");
break; break;
} }
default: default:
@ -485,6 +552,7 @@ void LanguagePackManager::on_get_language_pack_strings(
if (is_diff) { if (is_diff) {
strings.push_back(get_language_pack_string_object(key)); 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, send_closure(G()->td(), &Td::send_update,
td_api::make_object<td_api::updateLanguagePack>(language_pack, language_code, std::move(strings))); td_api::make_object<td_api::updateLanguagePack>(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) { if (is_diff) {
CHECK(language != nullptr); CHECK(language != nullptr);
std::lock_guard<std::mutex> lock(language->mutex_); std::lock_guard<std::mutex> lock(language->mutex_);

View File

@ -15,6 +15,7 @@
#include "td/actor/PromiseFuture.h" #include "td/actor/PromiseFuture.h"
#include "td/utils/Container.h" #include "td/utils/Container.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include <mutex> #include <mutex>
@ -88,6 +89,10 @@ class LanguagePackManager : public NetQueryCallback {
void inc_generation(); void inc_generation();
bool is_valid_key(Slice key);
void add_strings_to_database(Language *language, int32 new_version, vector<std::pair<string, string>> strings);
void on_get_language_pack_strings(string language_pack, string language_code, int32 version, bool is_diff, void on_get_language_pack_strings(string language_pack, string language_code, int32 version, bool is_diff,
vector<string> keys, 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);