Make country information static.
This commit is contained in:
parent
44556b3309
commit
8699d0aadb
@ -105,13 +105,13 @@ struct CountryInfoManager::CountryInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct CountryInfoManager::CountryList {
|
struct CountryInfoManager::CountryList {
|
||||||
vector<CountryInfo> countries_;
|
vector<CountryInfo> countries;
|
||||||
int32 hash = 0;
|
int32 hash = 0;
|
||||||
double next_reload_time = 0.0;
|
double next_reload_time = 0.0;
|
||||||
|
|
||||||
td_api::object_ptr<td_api::countries> get_countries_object() const {
|
td_api::object_ptr<td_api::countries> get_countries_object() const {
|
||||||
return td_api::make_object<td_api::countries>(
|
return td_api::make_object<td_api::countries>(
|
||||||
transform(countries_, [](const CountryInfo &info) { return info.get_country_info_object(); }));
|
transform(countries, [](const CountryInfo &info) { return info.get_country_info_object(); }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,8 +120,20 @@ CountryInfoManager::CountryInfoManager(Td *td, ActorShared<> parent) : td_(td),
|
|||||||
|
|
||||||
CountryInfoManager::~CountryInfoManager() = default;
|
CountryInfoManager::~CountryInfoManager() = default;
|
||||||
|
|
||||||
|
void CountryInfoManager::start_up() {
|
||||||
|
std::lock_guard<std::mutex> country_lock(country_mutex_);
|
||||||
|
manager_count_++;
|
||||||
|
}
|
||||||
|
|
||||||
void CountryInfoManager::tear_down() {
|
void CountryInfoManager::tear_down() {
|
||||||
parent_.reset();
|
parent_.reset();
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> country_lock(country_mutex_);
|
||||||
|
manager_count_--;
|
||||||
|
if (manager_count_ == 0) {
|
||||||
|
LOG(INFO) << "Clear country info";
|
||||||
|
countries_.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string CountryInfoManager::get_main_language_code() {
|
string CountryInfoManager::get_main_language_code() {
|
||||||
@ -141,25 +153,29 @@ void CountryInfoManager::do_get_countries(string language_code, bool is_recursiv
|
|||||||
is_recursive = false;
|
is_recursive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto list = get_country_list(language_code);
|
|
||||||
if (list == nullptr) {
|
{
|
||||||
|
std::lock_guard<std::mutex> country_lock(country_mutex_);
|
||||||
|
auto list = get_country_list(this, language_code);
|
||||||
|
if (list != nullptr) {
|
||||||
|
return promise.set_value(list->get_countries_object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_recursive) {
|
if (is_recursive) {
|
||||||
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
|
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
|
||||||
}
|
}
|
||||||
return load_country_list(language_code, 0,
|
load_country_list(language_code, 0,
|
||||||
PromiseCreator::lambda([actor_id = actor_id(this), language_code,
|
PromiseCreator::lambda([actor_id = actor_id(this), language_code,
|
||||||
promise = std::move(promise)](Result<Unit> &&result) mutable {
|
promise = std::move(promise)](Result<Unit> &&result) mutable {
|
||||||
if (result.is_error()) {
|
if (result.is_error()) {
|
||||||
return promise.set_error(result.move_as_error());
|
return promise.set_error(result.move_as_error());
|
||||||
}
|
}
|
||||||
send_closure(actor_id, &CountryInfoManager::do_get_countries, std::move(language_code),
|
send_closure(actor_id, &CountryInfoManager::do_get_countries, std::move(language_code), true,
|
||||||
true, std::move(promise));
|
std::move(promise));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.set_value(list->get_countries_object());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CountryInfoManager::get_phone_number_info(string phone_number_prefix,
|
void CountryInfoManager::get_phone_number_info(string phone_number_prefix,
|
||||||
Promise<td_api::object_ptr<td_api::phoneNumberInfo>> &&promise) {
|
Promise<td_api::object_ptr<td_api::phoneNumberInfo>> &&promise) {
|
||||||
td::remove_if(phone_number_prefix, [](char c) { return c < '0' || c > '9'; });
|
td::remove_if(phone_number_prefix, [](char c) { return c < '0' || c > '9'; });
|
||||||
@ -178,26 +194,28 @@ void CountryInfoManager::do_get_phone_number_info(string phone_number_prefix, st
|
|||||||
is_recursive = false;
|
is_recursive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto list = get_country_list(language_code);
|
{
|
||||||
if (list == nullptr) {
|
std::lock_guard<std::mutex> country_lock(country_mutex_);
|
||||||
|
auto list = get_country_list(this, language_code);
|
||||||
|
if (list != nullptr) {
|
||||||
|
return promise.set_value(get_phone_number_info_object(list, phone_number_prefix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_recursive) {
|
if (is_recursive) {
|
||||||
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
|
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
|
||||||
}
|
}
|
||||||
return load_country_list(language_code, 0,
|
load_country_list(language_code, 0,
|
||||||
PromiseCreator::lambda([actor_id = actor_id(this), phone_number_prefix, language_code,
|
PromiseCreator::lambda([actor_id = actor_id(this), phone_number_prefix, language_code,
|
||||||
promise = std::move(promise)](Result<Unit> &&result) mutable {
|
promise = std::move(promise)](Result<Unit> &&result) mutable {
|
||||||
if (result.is_error()) {
|
if (result.is_error()) {
|
||||||
return promise.set_error(result.move_as_error());
|
return promise.set_error(result.move_as_error());
|
||||||
}
|
}
|
||||||
send_closure(actor_id, &CountryInfoManager::do_get_phone_number_info,
|
send_closure(actor_id, &CountryInfoManager::do_get_phone_number_info,
|
||||||
std::move(phone_number_prefix), std::move(language_code), true,
|
std::move(phone_number_prefix), std::move(language_code), true, std::move(promise));
|
||||||
std::move(promise));
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.set_value(get_phone_number_info_object(list, phone_number_prefix));
|
|
||||||
}
|
|
||||||
|
|
||||||
td_api::object_ptr<td_api::phoneNumberInfo> CountryInfoManager::get_phone_number_info_object(const CountryList *list,
|
td_api::object_ptr<td_api::phoneNumberInfo> CountryInfoManager::get_phone_number_info_object(const CountryList *list,
|
||||||
Slice phone_number) {
|
Slice phone_number) {
|
||||||
CHECK(list != nullptr);
|
CHECK(list != nullptr);
|
||||||
@ -205,7 +223,7 @@ td_api::object_ptr<td_api::phoneNumberInfo> CountryInfoManager::get_phone_number
|
|||||||
const CallingCodeInfo *best_calling_code = nullptr;
|
const CallingCodeInfo *best_calling_code = nullptr;
|
||||||
size_t best_length = 0;
|
size_t best_length = 0;
|
||||||
bool is_prefix = false; // is phone number a prefix of a valid country_code + prefix
|
bool is_prefix = false; // is phone number a prefix of a valid country_code + prefix
|
||||||
for (auto &country : list->countries_) {
|
for (auto &country : list->countries) {
|
||||||
for (auto &calling_code : country.calling_codes) {
|
for (auto &calling_code : country.calling_codes) {
|
||||||
if (begins_with(phone_number, calling_code.calling_code)) {
|
if (begins_with(phone_number, calling_code.calling_code)) {
|
||||||
auto calling_code_size = calling_code.calling_code.size();
|
auto calling_code_size = calling_code.calling_code.size();
|
||||||
@ -315,9 +333,19 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
|
|||||||
pending_load_country_queries_.erase(query_it);
|
pending_load_country_queries_.erase(query_it);
|
||||||
|
|
||||||
if (r_country_list.is_error()) {
|
if (r_country_list.is_error()) {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> country_lock(country_mutex_);
|
||||||
auto it = countries_.find(language_code);
|
auto it = countries_.find(language_code);
|
||||||
if (it != countries_.end()) {
|
if (it != countries_.end()) {
|
||||||
it->second->next_reload_time = Time::now() + Random::fast(60, 120);
|
// don't try to reload countries more often than once in 1-2 minutes
|
||||||
|
it->second->next_reload_time = max(Time::now() + Random::fast(60, 120), it->second->next_reload_time);
|
||||||
|
|
||||||
|
// if we have data for the language, then we don't need to fail promises
|
||||||
|
for (auto &promise : promises) {
|
||||||
|
promise.set_value(Unit());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (auto &promise : promises) {
|
for (auto &promise : promises) {
|
||||||
promise.set_error(r_country_list.error().clone());
|
promise.set_error(r_country_list.error().clone());
|
||||||
@ -325,7 +353,10 @@ void CountryInfoManager::on_get_country_list(const string &language_code,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> country_lock(country_mutex_);
|
||||||
on_get_country_list_impl(language_code, r_country_list.move_as_ok());
|
on_get_country_list_impl(language_code, r_country_list.move_as_ok());
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &promise : promises) {
|
for (auto &promise : promises) {
|
||||||
promise.set_value(Unit());
|
promise.set_value(Unit());
|
||||||
@ -378,7 +409,7 @@ void CountryInfoManager::on_get_country_list_impl(const string &language_code,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
countries->countries_.push_back(std::move(info));
|
countries->countries.push_back(std::move(info));
|
||||||
}
|
}
|
||||||
countries->hash = list->hash_;
|
countries->hash = list->hash_;
|
||||||
countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400);
|
countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400);
|
||||||
@ -389,7 +420,8 @@ void CountryInfoManager::on_get_country_list_impl(const string &language_code,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(const string &language_code) {
|
const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(CountryInfoManager *manager,
|
||||||
|
const string &language_code) {
|
||||||
auto it = countries_.find(language_code);
|
auto it = countries_.find(language_code);
|
||||||
if (it == countries_.end()) {
|
if (it == countries_.end()) {
|
||||||
if (language_code == "en") {
|
if (language_code == "en") {
|
||||||
@ -467,7 +499,9 @@ const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(cons
|
|||||||
it = countries_.find(language_code);
|
it = countries_.find(language_code);
|
||||||
CHECK(it != countries_.end())
|
CHECK(it != countries_.end())
|
||||||
auto *country = it->second.get();
|
auto *country = it->second.get();
|
||||||
load_country_list(language_code, country->hash, Auto());
|
if (manager != nullptr) {
|
||||||
|
manager->load_country_list(language_code, country->hash, Auto());
|
||||||
|
}
|
||||||
return country;
|
return country;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -475,11 +509,15 @@ const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(cons
|
|||||||
|
|
||||||
auto *country = it->second.get();
|
auto *country = it->second.get();
|
||||||
CHECK(country != nullptr);
|
CHECK(country != nullptr);
|
||||||
if (country->next_reload_time < Time::now()) {
|
if (manager != nullptr && country->next_reload_time < Time::now()) {
|
||||||
load_country_list(language_code, country->hash, Auto());
|
manager->load_country_list(language_code, country->hash, Auto());
|
||||||
}
|
}
|
||||||
|
|
||||||
return country;
|
return country;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 CountryInfoManager::manager_count_ = 0;
|
||||||
|
std::mutex CountryInfoManager::country_mutex_;
|
||||||
|
std::unordered_map<string, unique_ptr<CountryInfoManager::CountryList>> CountryInfoManager::countries_;
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "td/utils/common.h"
|
#include "td/utils/common.h"
|
||||||
#include "td/utils/Status.h"
|
#include "td/utils/Status.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
@ -39,6 +40,7 @@ class CountryInfoManager final : public Actor {
|
|||||||
~CountryInfoManager() final;
|
~CountryInfoManager() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void start_up() final;
|
||||||
void tear_down() final;
|
void tear_down() final;
|
||||||
|
|
||||||
struct CallingCodeInfo;
|
struct CallingCodeInfo;
|
||||||
@ -58,16 +60,21 @@ class CountryInfoManager final : public Actor {
|
|||||||
void on_get_country_list(const string &language_code,
|
void on_get_country_list(const string &language_code,
|
||||||
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list);
|
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list);
|
||||||
|
|
||||||
void on_get_country_list_impl(const string &language_code,
|
static void on_get_country_list_impl(const string &language_code,
|
||||||
tl_object_ptr<telegram_api::help_CountriesList> country_list);
|
tl_object_ptr<telegram_api::help_CountriesList> country_list);
|
||||||
|
|
||||||
const CountryList *get_country_list(const string &language_code);
|
static const CountryList *get_country_list(CountryInfoManager *manager, const string &language_code);
|
||||||
|
|
||||||
static td_api::object_ptr<td_api::phoneNumberInfo> get_phone_number_info_object(const CountryList *list,
|
static td_api::object_ptr<td_api::phoneNumberInfo> get_phone_number_info_object(const CountryList *list,
|
||||||
Slice phone_number);
|
Slice phone_number);
|
||||||
|
|
||||||
|
static std::mutex country_mutex_;
|
||||||
|
|
||||||
|
static int32 manager_count_;
|
||||||
|
|
||||||
|
static std::unordered_map<string, unique_ptr<CountryList>> countries_;
|
||||||
|
|
||||||
std::unordered_map<string, vector<Promise<Unit>>> pending_load_country_queries_;
|
std::unordered_map<string, vector<Promise<Unit>>> pending_load_country_queries_;
|
||||||
std::unordered_map<string, unique_ptr<CountryList>> countries_;
|
|
||||||
|
|
||||||
Td *td_;
|
Td *td_;
|
||||||
ActorShared<> parent_;
|
ActorShared<> parent_;
|
||||||
|
Loading…
Reference in New Issue
Block a user