1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #include "main/main_app_config.h"
9
10 #include "main/main_account.h"
11 #include "base/call_delayed.h"
12 #include "apiwrap.h"
13
14 namespace Main {
15 namespace {
16
17 constexpr auto kRefreshTimeout = 3600 * crl::time(1000);
18
19 } // namespace
20
AppConfig(not_null<Account * > account)21 AppConfig::AppConfig(not_null<Account*> account) : _account(account) {
22 account->mtpMainSessionValue(
23 ) | rpl::start_with_next([=](not_null<MTP::Instance*> instance) {
24 _api.emplace(instance);
25 refresh();
26 }, _lifetime);
27
28 account->sessionChanges(
29 ) | rpl::filter([=](Session *session) {
30 return (session != nullptr);
31 }) | rpl::start_with_next([=] {
32 refresh();
33 }, _lifetime);
34 }
35
refresh()36 void AppConfig::refresh() {
37 if (_requestId || !_api) {
38 return;
39 }
40 _requestId = _api->request(MTPhelp_GetAppConfig(
41 )).done([=](const MTPJSONValue &result) {
42 _requestId = 0;
43 refreshDelayed();
44 if (result.type() == mtpc_jsonObject) {
45 _data.clear();
46 for (const auto &element : result.c_jsonObject().vvalue().v) {
47 element.match([&](const MTPDjsonObjectValue &data) {
48 _data.emplace_or_assign(qs(data.vkey()), data.vvalue());
49 });
50 }
51 DEBUG_LOG(("getAppConfig result handled."));
52 }
53 _refreshed.fire({});
54 }).fail([=](const MTP::Error &error) {
55 _requestId = 0;
56 refreshDelayed();
57 }).send();
58 }
59
refreshDelayed()60 void AppConfig::refreshDelayed() {
61 base::call_delayed(kRefreshTimeout, _account, [=] {
62 refresh();
63 });
64 }
65
refreshed() const66 rpl::producer<> AppConfig::refreshed() const {
67 return _refreshed.events();
68 }
69
value() const70 rpl::producer<> AppConfig::value() const {
71 return _refreshed.events_starting_with({});
72 }
73
74 template <typename Extractor>
getValue(const QString & key,Extractor && extractor) const75 auto AppConfig::getValue(const QString &key, Extractor &&extractor) const {
76 const auto i = _data.find(key);
77 return extractor((i != end(_data))
78 ? i->second
79 : MTPJSONValue(MTP_jsonNull()));
80 }
81
getBool(const QString & key,bool fallback) const82 bool AppConfig::getBool(const QString &key, bool fallback) const {
83 return getValue(key, [&](const MTPJSONValue &value) {
84 return value.match([&](const MTPDjsonBool &data) {
85 return mtpIsTrue(data.vvalue());
86 }, [&](const auto &data) {
87 return fallback;
88 });
89 });
90 }
91
getDouble(const QString & key,double fallback) const92 double AppConfig::getDouble(const QString &key, double fallback) const {
93 return getValue(key, [&](const MTPJSONValue &value) {
94 return value.match([&](const MTPDjsonNumber &data) {
95 return data.vvalue().v;
96 }, [&](const auto &data) {
97 return fallback;
98 });
99 });
100 }
101
getString(const QString & key,const QString & fallback) const102 QString AppConfig::getString(
103 const QString &key,
104 const QString &fallback) const {
105 return getValue(key, [&](const MTPJSONValue &value) {
106 return value.match([&](const MTPDjsonString &data) {
107 return qs(data.vvalue());
108 }, [&](const auto &data) {
109 return fallback;
110 });
111 });
112 }
113
getStringArray(const QString & key,std::vector<QString> && fallback) const114 std::vector<QString> AppConfig::getStringArray(
115 const QString &key,
116 std::vector<QString> &&fallback) const {
117 return getValue(key, [&](const MTPJSONValue &value) {
118 return value.match([&](const MTPDjsonArray &data) {
119 auto result = std::vector<QString>();
120 result.reserve(data.vvalue().v.size());
121 for (const auto &entry : data.vvalue().v) {
122 if (entry.type() != mtpc_jsonString) {
123 return std::move(fallback);
124 }
125 result.push_back(qs(entry.c_jsonString().vvalue()));
126 }
127 return result;
128 }, [&](const auto &data) {
129 return std::move(fallback);
130 });
131 });
132 }
133
getStringMapArray(const QString & key,std::vector<std::map<QString,QString>> && fallback) const134 std::vector<std::map<QString, QString>> AppConfig::getStringMapArray(
135 const QString &key,
136 std::vector<std::map<QString, QString>> &&fallback) const {
137 return getValue(key, [&](const MTPJSONValue &value) {
138 return value.match([&](const MTPDjsonArray &data) {
139 auto result = std::vector<std::map<QString, QString>>();
140 result.reserve(data.vvalue().v.size());
141 for (const auto &entry : data.vvalue().v) {
142 if (entry.type() != mtpc_jsonObject) {
143 return std::move(fallback);
144 }
145 auto element = std::map<QString, QString>();
146 for (const auto &field : entry.c_jsonObject().vvalue().v) {
147 const auto &data = field.c_jsonObjectValue();
148 if (data.vvalue().type() != mtpc_jsonString) {
149 return std::move(fallback);
150 }
151 element.emplace(
152 qs(data.vkey()),
153 qs(data.vvalue().c_jsonString().vvalue()));
154 }
155 result.push_back(std::move(element));
156 }
157 return result;
158 }, [&](const auto &data) {
159 return std::move(fallback);
160 });
161 });
162 }
163
suggestionCurrent(const QString & key) const164 bool AppConfig::suggestionCurrent(const QString &key) const {
165 return !_dismissedSuggestions.contains(key)
166 && ranges::contains(
167 get<std::vector<QString>>(
168 u"pending_suggestions"_q,
169 std::vector<QString>()),
170 key);
171 }
172
suggestionRequested(const QString & key) const173 rpl::producer<> AppConfig::suggestionRequested(const QString &key) const {
174 return value(
175 ) | rpl::filter([=] {
176 return suggestionCurrent(key);
177 });
178 }
179
dismissSuggestion(const QString & key)180 void AppConfig::dismissSuggestion(const QString &key) {
181 if (!_dismissedSuggestions.emplace(key).second) {
182 return;
183 }
184 _api->request(MTPhelp_DismissSuggestion(
185 MTP_inputPeerEmpty(),
186 MTP_string(key)
187 )).send();
188 }
189
190 } // namespace Main
191