Add td_api::getCountries.
GitOrigin-RevId: 1c70e6e267b9582afe50014ffc9d1ef81a33f123
This commit is contained in:
parent
eff3dd9f36
commit
3860953251
@ -1177,6 +1177,18 @@ webPageInstantView page_blocks:vector<PageBlock> view_count:int32 version:int32
|
||||
webPage url:string display_url:string type:string site_name:string title:string description:formattedText photo:photo embed_url:string embed_type:string embed_width:int32 embed_height:int32 duration:int32 author:string animation:animation audio:audio document:document sticker:sticker video:video video_note:videoNote voice_note:voiceNote instant_view_version:int32 = WebPage;
|
||||
|
||||
|
||||
//@description Contains information about a country
|
||||
//@country_code A two-letter ISO 3166-1 alpha-2 country code
|
||||
//@name Native name of the country
|
||||
//@english_name English name of the country
|
||||
//@is_hidden True, if the country should be hidden from the list of all countries
|
||||
//@calling_codes List of country calling codes
|
||||
countryInfo country_code:string name:string english_name:string is_hidden:Bool calling_codes:vector<string> = CountryInfo;
|
||||
|
||||
//@description Contains information about countries @countries The list of countries
|
||||
countries countries:vector<countryInfo> = Countries;
|
||||
|
||||
|
||||
//@description Describes an action associated with a bank card number @text Action text @url The URL to be opened
|
||||
bankCardActionOpenUrl text:string url:string = BankCardActionOpenUrl;
|
||||
|
||||
@ -4654,6 +4666,9 @@ answerCustomQuery custom_query_id:int64 data:string = Ok;
|
||||
setAlarm seconds:double = Ok;
|
||||
|
||||
|
||||
//@description Returns information about existing countries. Can be called before authorization
|
||||
getCountries = Countries;
|
||||
|
||||
//@description Uses current user IP address to find their country. Returns two-letter ISO 3166-1 alpha-2 country code. Can be called before authorization
|
||||
getCountryCode = Text;
|
||||
|
||||
|
Binary file not shown.
@ -7,10 +7,13 @@
|
||||
#include "td/telegram/CountryInfoManager.h"
|
||||
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/LanguagePackManager.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/misc.h"
|
||||
#include "td/utils/Random.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
namespace td {
|
||||
@ -44,6 +47,66 @@ class GetNearestDcQuery : public Td::ResultHandler {
|
||||
}
|
||||
};
|
||||
|
||||
class GetCountriesListQuery : public Td::ResultHandler {
|
||||
Promise<tl_object_ptr<telegram_api::help_CountriesList>> promise_;
|
||||
|
||||
public:
|
||||
explicit GetCountriesListQuery(Promise<tl_object_ptr<telegram_api::help_CountriesList>> &&promise)
|
||||
: promise_(std::move(promise)) {
|
||||
}
|
||||
|
||||
void send(const string &language_code, int32 hash) {
|
||||
send_query(G()->net_query_creator().create_unauth(telegram_api::help_getCountriesList(language_code, hash)));
|
||||
}
|
||||
|
||||
void on_result(uint64 id, BufferSlice packet) override {
|
||||
auto result_ptr = fetch_result<telegram_api::help_getCountriesList>(packet);
|
||||
if (result_ptr.is_error()) {
|
||||
return on_error(id, result_ptr.move_as_error());
|
||||
}
|
||||
|
||||
promise_.set_value(result_ptr.move_as_ok());
|
||||
}
|
||||
|
||||
void on_error(uint64 id, Status status) override {
|
||||
if (!G()->is_expected_error(status)) {
|
||||
LOG(ERROR) << "GetCountriesList returned " << status;
|
||||
}
|
||||
promise_.set_error(std::move(status));
|
||||
}
|
||||
};
|
||||
|
||||
struct CountryInfoManager::CallingCodeInfo {
|
||||
int32 calling_code = 0;
|
||||
vector<string> prefixes;
|
||||
vector<string> patterns;
|
||||
};
|
||||
|
||||
struct CountryInfoManager::CountryInfo {
|
||||
string country_code;
|
||||
string default_name;
|
||||
string name;
|
||||
vector<CallingCodeInfo> calling_codes;
|
||||
bool is_hidden = false;
|
||||
|
||||
td_api::object_ptr<td_api::countryInfo> get_country_info_object() const {
|
||||
return td_api::make_object<td_api::countryInfo>(
|
||||
country_code, name.empty() ? default_name : name, default_name, is_hidden,
|
||||
transform(calling_codes, [](const CallingCodeInfo &info) { return to_string(info.calling_code); }));
|
||||
}
|
||||
};
|
||||
|
||||
struct CountryInfoManager::CountryList {
|
||||
vector<CountryInfo> countries_;
|
||||
int32 hash = 0;
|
||||
double next_reload_time = 0.0;
|
||||
|
||||
td_api::object_ptr<td_api::countries> get_countries_object() const {
|
||||
return td_api::make_object<td_api::countries>(
|
||||
transform(countries_, [](const CountryInfo &info) { return info.get_country_info_object(); }));
|
||||
}
|
||||
};
|
||||
|
||||
CountryInfoManager::CountryInfoManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
||||
}
|
||||
|
||||
@ -51,8 +114,142 @@ void CountryInfoManager::tear_down() {
|
||||
parent_.reset();
|
||||
}
|
||||
|
||||
string CountryInfoManager::get_main_language_code() {
|
||||
return to_lower(td_->language_pack_manager_->get_actor_unsafe()->get_main_language_code());
|
||||
}
|
||||
|
||||
void CountryInfoManager::get_countries(Promise<td_api::object_ptr<td_api::countries>> &&promise) {
|
||||
do_get_countries(get_main_language_code(), false, std::move(promise));
|
||||
}
|
||||
|
||||
void CountryInfoManager::do_get_countries(string language_code, bool is_recursive,
|
||||
Promise<td_api::object_ptr<td_api::countries>> &&promise) {
|
||||
auto list = get_country_list(language_code);
|
||||
if (list == nullptr) {
|
||||
if (is_recursive) {
|
||||
return promise.set_error(Status::Error(500, "Requested data is inaccessible"));
|
||||
}
|
||||
return load_country_list(language_code, 0,
|
||||
PromiseCreator::lambda([actor_id = actor_id(this), language_code,
|
||||
promise = std::move(promise)](Result<Unit> &&result) mutable {
|
||||
if (result.is_error()) {
|
||||
return promise.set_error(result.move_as_error());
|
||||
}
|
||||
send_closure(actor_id, &CountryInfoManager::do_get_countries, std::move(language_code),
|
||||
true, std::move(promise));
|
||||
}));
|
||||
}
|
||||
|
||||
promise.set_value(list->get_countries_object());
|
||||
}
|
||||
|
||||
void CountryInfoManager::get_current_country_code(Promise<string> &&promise) {
|
||||
td_->create_handler<GetNearestDcQuery>(std::move(promise))->send();
|
||||
}
|
||||
|
||||
void CountryInfoManager::load_country_list(string language_code, int32 hash, Promise<Unit> &&promise) {
|
||||
auto &queries = pending_load_country_queries_[language_code];
|
||||
if (!promise && !queries.empty()) {
|
||||
return;
|
||||
}
|
||||
queries.push_back(std::move(promise));
|
||||
if (queries.size() == 1) {
|
||||
auto query_promise = PromiseCreator::lambda(
|
||||
[actor_id = actor_id(this), language_code](Result<tl_object_ptr<telegram_api::help_CountriesList>> &&result) {
|
||||
send_closure(actor_id, &CountryInfoManager::on_get_country_list, language_code, std::move(result));
|
||||
});
|
||||
td_->create_handler<GetCountriesListQuery>(std::move(query_promise))->send(language_code, hash);
|
||||
}
|
||||
}
|
||||
|
||||
void CountryInfoManager::on_get_country_list(const string &language_code,
|
||||
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list) {
|
||||
auto query_it = pending_load_country_queries_.find(language_code);
|
||||
CHECK(query_it != pending_load_country_queries_.end());
|
||||
auto promises = std::move(query_it->second);
|
||||
CHECK(!promises.empty());
|
||||
pending_load_country_queries_.erase(query_it);
|
||||
|
||||
auto &countries = countries_[language_code];
|
||||
if (r_country_list.is_error()) {
|
||||
if (countries != nullptr) {
|
||||
countries->next_reload_time = Time::now() + Random::fast(60, 120);
|
||||
}
|
||||
for (auto &promise : promises) {
|
||||
promise.set_error(r_country_list.error().clone());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto country_list = r_country_list.move_as_ok();
|
||||
CHECK(country_list != nullptr);
|
||||
switch (country_list->get_id()) {
|
||||
case telegram_api::help_countriesListNotModified::ID:
|
||||
if (countries == nullptr) {
|
||||
LOG(ERROR) << "Receive countriesListNotModified for unknown list with language code " << language_code;
|
||||
countries_.erase(language_code);
|
||||
} else {
|
||||
LOG(INFO) << "List of countries with language code " << language_code << " is not modified";
|
||||
countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400);
|
||||
}
|
||||
break;
|
||||
case telegram_api::help_countriesList::ID: {
|
||||
auto list = move_tl_object_as<telegram_api::help_countriesList>(country_list);
|
||||
if (countries == nullptr) {
|
||||
countries = make_unique<CountryList>();
|
||||
}
|
||||
for (auto &c : list->countries_) {
|
||||
CountryInfo info;
|
||||
info.country_code = std::move(c->iso2_);
|
||||
info.default_name = std::move(c->default_name_);
|
||||
info.name = std::move(c->name_);
|
||||
info.is_hidden = std::move(c->hidden_);
|
||||
for (auto &code : c->country_codes_) {
|
||||
auto r_calling_code = to_integer_safe<int32>(code->country_code_);
|
||||
if (r_calling_code.is_error() || r_calling_code.ok() <= 0) {
|
||||
LOG(ERROR) << "Receive invalid calling code " << code->country_code_ << " for country "
|
||||
<< info.country_code;
|
||||
} else {
|
||||
CallingCodeInfo calling_code_info;
|
||||
calling_code_info.calling_code = r_calling_code.ok();
|
||||
calling_code_info.prefixes = std::move(code->prefixes_);
|
||||
calling_code_info.patterns = std::move(code->patterns_);
|
||||
info.calling_codes.push_back(std::move(calling_code_info));
|
||||
}
|
||||
}
|
||||
if (info.calling_codes.empty()) {
|
||||
LOG(ERROR) << "Receive empty list of calling codes for " << info.country_code;
|
||||
continue;
|
||||
}
|
||||
|
||||
countries->countries_.push_back(std::move(info));
|
||||
}
|
||||
countries->hash = list->hash_;
|
||||
countries->next_reload_time = Time::now() + Random::fast(86400, 2 * 86400);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
for (auto &promise : promises) {
|
||||
promise.set_value(Unit());
|
||||
}
|
||||
}
|
||||
|
||||
const CountryInfoManager::CountryList *CountryInfoManager::get_country_list(const string &language_code) {
|
||||
auto it = countries_.find(language_code);
|
||||
if (it == countries_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *country = it->second.get();
|
||||
CHECK(country != nullptr);
|
||||
if (country->next_reload_time < Time::now()) {
|
||||
load_country_list(language_code, country->hash, Auto());
|
||||
}
|
||||
|
||||
return country;
|
||||
}
|
||||
|
||||
} // namespace td
|
||||
|
@ -6,10 +6,16 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "td/telegram/td_api.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/actor/actor.h"
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
|
||||
#include "td/utils/common.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace td {
|
||||
|
||||
@ -19,11 +25,32 @@ class CountryInfoManager : public Actor {
|
||||
public:
|
||||
explicit CountryInfoManager(Td *td, ActorShared<> parent);
|
||||
|
||||
void get_countries(Promise<td_api::object_ptr<td_api::countries>> &&promise);
|
||||
|
||||
void get_current_country_code(Promise<string> &&promise);
|
||||
|
||||
private:
|
||||
void tear_down() override;
|
||||
|
||||
struct CallingCodeInfo;
|
||||
struct CountryInfo;
|
||||
struct CountryList;
|
||||
|
||||
string get_main_language_code();
|
||||
|
||||
void do_get_countries(string language_code, bool is_recursive,
|
||||
Promise<td_api::object_ptr<td_api::countries>> &&promise);
|
||||
|
||||
void load_country_list(string language_code, int32 hash, Promise<Unit> &&promise);
|
||||
|
||||
void on_get_country_list(const string &language_code,
|
||||
Result<tl_object_ptr<telegram_api::help_CountriesList>> r_country_list);
|
||||
|
||||
const CountryList *get_country_list(const string &language_code);
|
||||
|
||||
std::unordered_map<string, vector<Promise<Unit>>> pending_load_country_queries_;
|
||||
std::unordered_map<string, unique_ptr<CountryList>> countries_;
|
||||
|
||||
Td *td_;
|
||||
ActorShared<> parent_;
|
||||
};
|
||||
|
@ -238,6 +238,50 @@ void LanguagePackManager::tear_down() {
|
||||
}
|
||||
}
|
||||
|
||||
string LanguagePackManager::get_main_language_code() {
|
||||
if (language_pack_.empty() || language_code_.empty()) {
|
||||
return "en";
|
||||
}
|
||||
if (language_code_.size() <= 2) {
|
||||
return language_code_;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> packs_lock(database_->mutex_);
|
||||
auto pack_it = database_->language_packs_.find(language_pack_);
|
||||
CHECK(pack_it != database_->language_packs_.end());
|
||||
|
||||
LanguageInfo *info = nullptr;
|
||||
LanguagePack *pack = pack_it->second.get();
|
||||
std::lock_guard<std::mutex> languages_lock(pack->mutex_);
|
||||
if (is_custom_language_code(language_code_)) {
|
||||
auto custom_it = pack->custom_language_pack_infos_.find(language_code_);
|
||||
if (custom_it != pack->custom_language_pack_infos_.end()) {
|
||||
info = &custom_it->second;
|
||||
}
|
||||
} else {
|
||||
for (auto &server_info : pack->server_language_pack_infos_) {
|
||||
if (server_info.first == language_code_) {
|
||||
info = &server_info.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info == nullptr) {
|
||||
LOG(ERROR) << "Failed to find information about chosen language " << language_code_;
|
||||
if (!is_custom_language_code(language_code_)) {
|
||||
search_language_info(language_code_, Auto());
|
||||
}
|
||||
} else {
|
||||
if (!info->base_language_code_.empty()) {
|
||||
return info->base_language_code_;
|
||||
}
|
||||
if (!info->plural_code_.empty()) {
|
||||
return info->plural_code_;
|
||||
}
|
||||
}
|
||||
return "en";
|
||||
}
|
||||
|
||||
vector<string> LanguagePackManager::get_used_language_codes() {
|
||||
if (language_pack_.empty() || language_code_.empty()) {
|
||||
return {};
|
||||
|
@ -43,6 +43,8 @@ class LanguagePackManager : public NetQueryCallback {
|
||||
|
||||
static bool is_custom_language_code(Slice language_code);
|
||||
|
||||
string get_main_language_code();
|
||||
|
||||
vector<string> get_used_language_codes();
|
||||
|
||||
void on_language_pack_changed();
|
||||
|
@ -3298,6 +3298,7 @@ bool Td::is_preauthentication_request(int32 id) {
|
||||
case td_api::getNetworkStatistics::ID:
|
||||
case td_api::addNetworkStatistics::ID:
|
||||
case td_api::resetNetworkStatistics::ID:
|
||||
case td_api::getCountries::ID:
|
||||
case td_api::getCountryCode::ID:
|
||||
case td_api::getDeepLinkInfo::ID:
|
||||
case td_api::getApplicationConfig::ID:
|
||||
@ -7653,6 +7654,11 @@ void Td::on_request(uint64 id, td_api::acceptTermsOfService &request) {
|
||||
accept_terms_of_service(this, std::move(request.terms_of_service_id_), std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getCountries &request) {
|
||||
CREATE_REQUEST_PROMISE();
|
||||
country_info_manager_->get_countries(std::move(promise));
|
||||
}
|
||||
|
||||
void Td::on_request(uint64 id, const td_api::getCountryCode &request) {
|
||||
CREATE_REQUEST_PROMISE();
|
||||
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<string> result) mutable {
|
||||
|
@ -1054,6 +1054,8 @@ class Td final : public NetQueryCallback {
|
||||
|
||||
void on_request(uint64 id, td_api::acceptTermsOfService &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getCountries &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getCountryCode &request);
|
||||
|
||||
void on_request(uint64 id, const td_api::getInviteText &request);
|
||||
|
@ -2268,8 +2268,10 @@ class CliClient final : public Actor {
|
||||
send_request(td_api::make_object<td_api::removeBackground>(to_integer<int64>(args)));
|
||||
} else if (op == "rbgs") {
|
||||
send_request(td_api::make_object<td_api::resetBackgrounds>());
|
||||
} else if (op == "gccode") {
|
||||
} else if (op == "gcoc") {
|
||||
send_request(td_api::make_object<td_api::getCountryCode>());
|
||||
} else if (op == "gcos") {
|
||||
send_request(td_api::make_object<td_api::getCountries>());
|
||||
} else if (op == "git") {
|
||||
send_request(td_api::make_object<td_api::getInviteText>());
|
||||
} else if (op == "atos") {
|
||||
|
Loading…
Reference in New Issue
Block a user