| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "countries/countries_manager.h"
- #include "core/application.h"
- #include "countries/countries_instance.h"
- #include "main/main_app_config.h"
- #include "main/main_account.h"
- #include "main/main_domain.h"
- #include "mtproto/mtp_instance.h"
- #include <QtCore/QFile>
- namespace Countries {
- namespace {
- struct FileData {
- int hash = 0;
- std::vector<Info> infos;
- };
- auto ProcessAlternativeName(Info &&info) {
- if (info.name == u"USA"_q) {
- info.alternativeName = u"United States of America"_q;
- }
- return std::move(info);
- }
- [[nodiscard]] QByteArray SerializeCodeInfo(const CallingCodeInfo &info) {
- auto result = QByteArray();
- auto stream = QDataStream(&result, QIODevice::WriteOnly);
- stream.setVersion(QDataStream::Qt_5_3);
- stream
- << info.callingCode
- << int(info.prefixes.size())
- << int(info.patterns.size());
- for (const auto &prefix : info.prefixes) {
- stream << prefix;
- }
- for (const auto &pattern : info.patterns) {
- stream << pattern;
- }
- stream.device()->close();
- return result;
- }
- [[nodiscard]] CallingCodeInfo DeserializeCodeInfo(const QByteArray &data) {
- auto stream = QDataStream(data);
- auto result = CallingCodeInfo();
- auto prefixesCount = qint32(0);
- auto patternsCount = qint32(0);
- stream
- >> result.callingCode
- >> prefixesCount
- >> patternsCount;
- for (auto i = 0; i < prefixesCount; i++) {
- auto prefix = QString();
- stream >> prefix;
- result.prefixes.push_back(std::move(prefix));
- }
- for (auto i = 0; i < patternsCount; i++) {
- auto pattern = QString();
- stream >> pattern;
- result.patterns.push_back(std::move(pattern));
- }
- return (stream.status() != QDataStream::Ok)
- ? CallingCodeInfo()
- : result;
- }
- [[nodiscard]] QByteArray SerializeInfo(const Info &info) {
- auto result = QByteArray();
- auto stream = QDataStream(&result, QIODevice::WriteOnly);
- stream.setVersion(QDataStream::Qt_5_3);
- stream
- << info.name
- << info.iso2
- << info.alternativeName
- << info.isHidden
- << int(info.codes.size());
- for (const auto &code : info.codes) {
- stream << SerializeCodeInfo(code);
- }
- stream.device()->close();
- return result;
- }
- [[nodiscard]] Info DeserializeInfo(const QByteArray &data) {
- auto stream = QDataStream(data);
- auto result = Info();
- auto codesCount = qint32(0);
- stream
- >> result.name
- >> result.iso2
- >> result.alternativeName
- >> result.isHidden
- >> codesCount;
- for (auto i = 0; i < codesCount; i++) {
- auto code = QByteArray();
- stream >> code;
- result.codes.push_back(DeserializeCodeInfo(code));
- }
- return (stream.status() != QDataStream::Ok)
- ? Info()
- : result;
- }
- [[nodiscard]] QByteArray Serialize(const FileData &data) {
- auto result = QByteArray();
- auto stream = QDataStream(&result, QIODevice::WriteOnly);
- stream.setVersion(QDataStream::Qt_5_3);
- stream
- << data.hash
- << int(data.infos.size());
- for (const auto &info : data.infos) {
- stream << SerializeInfo(info);
- }
- stream.device()->close();
- return result;
- }
- [[nodiscard]] FileData Deserialize(const QByteArray &data) {
- auto stream = QDataStream(data);
- auto hash = int(0);
- auto infosCount = qint32(0);
- auto infos = std::vector<Info>();
- stream >> hash >> infosCount;
- for (auto i = 0; i < infosCount; i++) {
- auto info = QByteArray();
- stream >> info;
- infos.push_back(DeserializeInfo(info));
- }
- return (stream.status() != QDataStream::Ok)
- ? FileData()
- : FileData{ .hash = hash, .infos = std::move(infos) };
- }
- } // namespace
- Manager::Manager(not_null<Main::Domain*> domain)
- : _path(cWorkingDir() + "tdata/countries") {
- read();
- const auto mtpLifetime = _lifetime.make_state<rpl::lifetime>();
- domain->activeValue(
- ) | rpl::filter([=](Main::Account *account) {
- return (account != nullptr);
- }) | rpl::start_with_next_done([=](Main::Account *account) {
- *mtpLifetime = account->mtpMainSessionValue(
- ) | rpl::start_with_next([=](not_null<MTP::Instance*> instance) {
- _api.emplace(instance);
- request();
- });
- }, [=] {
- _api.reset();
- }, _lifetime);
- }
- void Manager::read() {
- auto file = QFile(_path);
- if (!file.open(QIODevice::ReadOnly)) {
- return;
- }
- auto stream = QDataStream(&file);
- auto data = QByteArray();
- stream >> data;
- auto fileData = Deserialize(data);
- _hash = fileData.hash;
- Instance().setList(base::take(fileData.infos));
- }
- void Manager::write() const {
- auto file = QFile(_path);
- if (!file.open(QIODevice::WriteOnly)) {
- return;
- }
- auto stream = QDataStream(&file);
- stream << Serialize({ .hash = _hash, .infos = Instance().list() });
- }
- void Manager::request() {
- Expects(_api.has_value());
- const auto convertMTP = [](const auto &vector, bool force = false) {
- if (!vector) {
- return std::vector<QString>(force ? 1 : 0);
- }
- return ranges::views::all(
- vector->v
- ) | ranges::views::transform([](const MTPstring &s) -> QString {
- return qs(s);
- }) | ranges::to_vector;
- };
- _api->request(MTPhelp_GetCountriesList(
- MTP_string(),
- MTP_int(_hash)
- )).done([=](const MTPhelp_CountriesList &result) {
- result.match([&](const MTPDhelp_countriesList &data) {
- _hash = data.vhash().v;
- auto infos = std::vector<Info>();
- for (const auto &country : data.vcountries().v) {
- const auto &countryData = country.c_help_country();
- if (countryData.is_hidden()) {
- continue;
- }
- auto info = Info(ProcessAlternativeName({
- .name = countryData.vdefault_name().v,
- .iso2 = countryData.viso2().v,
- .isHidden = countryData.is_hidden(),
- }));
- for (const auto &code : countryData.vcountry_codes().v) {
- const auto &codeData = code.c_help_countryCode();
- info.codes.push_back(CallingCodeInfo{
- .callingCode = codeData.vcountry_code().v,
- .prefixes = convertMTP(codeData.vprefixes(), true),
- .patterns = convertMTP(codeData.vpatterns()),
- });
- }
- infos.push_back(std::move(info));
- }
- Instance().setList(std::move(infos));
- write();
- }, [](const MTPDhelp_countriesListNotModified &data) {
- });
- _lifetime.destroy();
- }).fail([=](const MTP::Error &error) {
- LOG(("API Error: getting countries failed with error %1"
- ).arg(error.type()));
- _lifetime.destroy();
- }).send();
- }
- rpl::lifetime &Manager::lifetime() {
- return _lifetime;
- }
- Manager::~Manager() {
- }
- } // namespace Countries
|