main_domain.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "main/main_domain.h"
  8. #include "core/application.h"
  9. #include "core/core_settings.h"
  10. #include "core/shortcuts.h"
  11. #include "core/crash_reports.h"
  12. #include "main/main_account.h"
  13. #include "main/main_session.h"
  14. #include "data/data_session.h"
  15. #include "data/data_changes.h"
  16. #include "data/data_user.h"
  17. #include "mtproto/mtproto_config.h"
  18. #include "mtproto/mtproto_dc_options.h"
  19. #include "storage/storage_domain.h"
  20. #include "storage/storage_account.h"
  21. #include "storage/localstorage.h"
  22. #include "export/export_settings.h"
  23. #include "window/notifications_manager.h"
  24. #include "window/window_controller.h"
  25. #include "data/data_peer_values.h" // Data::AmPremiumValue.
  26. namespace Main {
  27. Domain::Domain(const QString &dataName)
  28. : _dataName(dataName)
  29. , _local(std::make_unique<Storage::Domain>(this, dataName)) {
  30. _active.changes(
  31. ) | rpl::take(1) | rpl::start_with_next([=] {
  32. // In case we had a legacy passcoded app we start settings here.
  33. Core::App().startSettingsAndBackground();
  34. crl::on_main(this, [=] {
  35. Core::App().notifications().createManager();
  36. });
  37. }, _lifetime);
  38. _active.changes(
  39. ) | rpl::map([](Main::Account *account) {
  40. return account ? account->sessionValue() : rpl::never<Session*>();
  41. }) | rpl::flatten_latest(
  42. ) | rpl::map([](Main::Session *session) {
  43. return session
  44. ? session->changes().peerFlagsValue(
  45. session->user(),
  46. Data::PeerUpdate::Flag::Username)
  47. : rpl::never<Data::PeerUpdate>();
  48. }) | rpl::flatten_latest(
  49. ) | rpl::start_with_next([](const Data::PeerUpdate &update) {
  50. CrashReports::SetAnnotation("Username", update.peer->username());
  51. }, _lifetime);
  52. }
  53. Domain::~Domain() = default;
  54. bool Domain::started() const {
  55. return !_accounts.empty();
  56. }
  57. Storage::StartResult Domain::start(const QByteArray &passcode) {
  58. Expects(!started());
  59. const auto result = _local->start(passcode);
  60. if (result == Storage::StartResult::Success) {
  61. activateAfterStarting();
  62. crl::on_main(&Core::App(), [=] { suggestExportIfNeeded(); });
  63. } else {
  64. Assert(!started());
  65. }
  66. return result;
  67. }
  68. void Domain::finish() {
  69. _accountToActivate = -1;
  70. _active.reset(nullptr);
  71. base::take(_accounts);
  72. }
  73. void Domain::suggestExportIfNeeded() {
  74. Expects(started());
  75. for (const auto &[index, account] : _accounts) {
  76. if (const auto session = account->maybeSession()) {
  77. const auto settings = session->local().readExportSettings();
  78. if (const auto availableAt = settings.availableAt) {
  79. session->data().suggestStartExport(availableAt);
  80. }
  81. }
  82. }
  83. }
  84. void Domain::accountAddedInStorage(AccountWithIndex accountWithIndex) {
  85. Expects(accountWithIndex.account != nullptr);
  86. for (const auto &[index, _] : _accounts) {
  87. if (index == accountWithIndex.index) {
  88. Unexpected("Repeated account index.");
  89. }
  90. }
  91. _accounts.push_back(std::move(accountWithIndex));
  92. }
  93. void Domain::activateFromStorage(int index) {
  94. _accountToActivate = index;
  95. }
  96. int Domain::activeForStorage() const {
  97. return _accountToActivate;
  98. }
  99. void Domain::resetWithForgottenPasscode() {
  100. if (_accounts.empty()) {
  101. _local->startFromScratch();
  102. activateAfterStarting();
  103. } else {
  104. for (const auto &[index, account] : _accounts) {
  105. account->logOut();
  106. }
  107. }
  108. }
  109. void Domain::activateAfterStarting() {
  110. Expects(started());
  111. auto toActivate = _accounts.front().account.get();
  112. for (const auto &[index, account] : _accounts) {
  113. if (index == _accountToActivate) {
  114. toActivate = account.get();
  115. }
  116. watchSession(account.get());
  117. }
  118. activate(toActivate);
  119. removePasscodeIfEmpty();
  120. }
  121. const std::vector<Domain::AccountWithIndex> &Domain::accounts() const {
  122. return _accounts;
  123. }
  124. std::vector<not_null<Account*>> Domain::orderedAccounts() const {
  125. const auto order = Core::App().settings().accountsOrder();
  126. auto accounts = ranges::views::all(
  127. _accounts
  128. ) | ranges::views::transform([](const Domain::AccountWithIndex &a) {
  129. return not_null{ a.account.get() };
  130. }) | ranges::to_vector;
  131. ranges::stable_sort(accounts, [&](
  132. not_null<Account*> a,
  133. not_null<Account*> b) {
  134. const auto aIt = a->sessionExists()
  135. ? ranges::find(order, a->session().uniqueId())
  136. : end(order);
  137. const auto bIt = b->sessionExists()
  138. ? ranges::find(order, b->session().uniqueId())
  139. : end(order);
  140. return aIt < bIt;
  141. });
  142. return accounts;
  143. }
  144. rpl::producer<> Domain::accountsChanges() const {
  145. return _accountsChanges.events();
  146. }
  147. Account *Domain::maybeLastOrSomeAuthedAccount() {
  148. auto result = (Account*)nullptr;
  149. for (const auto &[index, account] : _accounts) {
  150. if (!account->sessionExists()) {
  151. continue;
  152. } else if (index == _lastActiveIndex) {
  153. return account.get();
  154. } else if (!result) {
  155. result = account.get();
  156. }
  157. }
  158. return result;
  159. }
  160. int Domain::accountsAuthedCount() const {
  161. auto result = 0;
  162. for (const auto &[index, account] : _accounts) {
  163. if (account->sessionExists()) {
  164. ++result;
  165. }
  166. }
  167. return result;
  168. }
  169. rpl::producer<Account*> Domain::activeValue() const {
  170. return _active.value();
  171. }
  172. Account &Domain::active() const {
  173. Expects(!_accounts.empty());
  174. Ensures(_active.current() != nullptr);
  175. return *_active.current();
  176. }
  177. rpl::producer<not_null<Account*>> Domain::activeChanges() const {
  178. return _active.changes() | rpl::map([](Account *value) {
  179. return not_null{ value };
  180. });
  181. }
  182. rpl::producer<Session*> Domain::activeSessionChanges() const {
  183. return _activeSessions.events();
  184. }
  185. rpl::producer<Session*> Domain::activeSessionValue() const {
  186. const auto current = _accounts.empty()
  187. ? nullptr
  188. : active().maybeSession();
  189. return rpl::single(current) | rpl::then(_activeSessions.events());
  190. }
  191. int Domain::unreadBadge() const {
  192. return _unreadBadge;
  193. }
  194. bool Domain::unreadBadgeMuted() const {
  195. return _unreadBadgeMuted;
  196. }
  197. rpl::producer<> Domain::unreadBadgeChanges() const {
  198. return _unreadBadgeChanges.events();
  199. }
  200. void Domain::notifyUnreadBadgeChanged() {
  201. for (const auto &[index, account] : _accounts) {
  202. if (const auto session = account->maybeSession()) {
  203. session->data().notifyUnreadBadgeChanged();
  204. }
  205. }
  206. }
  207. void Domain::updateUnreadBadge() {
  208. _unreadBadge = 0;
  209. _unreadBadgeMuted = true;
  210. for (const auto &[index, account] : _accounts) {
  211. if (const auto session = account->maybeSession()) {
  212. const auto data = &session->data();
  213. _unreadBadge += data->unreadBadge();
  214. if (!data->unreadBadgeMuted()) {
  215. _unreadBadgeMuted = false;
  216. }
  217. }
  218. }
  219. _unreadBadgeChanges.fire({});
  220. }
  221. void Domain::scheduleUpdateUnreadBadge() {
  222. if (_unreadBadgeUpdateScheduled) {
  223. return;
  224. }
  225. _unreadBadgeUpdateScheduled = true;
  226. Core::App().postponeCall(crl::guard(&Core::App(), [=] {
  227. _unreadBadgeUpdateScheduled = false;
  228. updateUnreadBadge();
  229. }));
  230. }
  231. not_null<Main::Account*> Domain::add(MTP::Environment environment) {
  232. Expects(started());
  233. Expects(_accounts.size() < kPremiumMaxAccounts);
  234. static const auto cloneConfig = [](const MTP::Config &config) {
  235. return std::make_unique<MTP::Config>(config);
  236. };
  237. auto mainDcId = MTP::Instance::Fields::kNotSetMainDc;
  238. const auto accountConfig = [&](not_null<Account*> account) {
  239. mainDcId = account->mtp().mainDcId();
  240. return cloneConfig(account->mtp().config());
  241. };
  242. auto config = [&] {
  243. if (_active.current()->mtp().environment() == environment) {
  244. return accountConfig(_active.current());
  245. }
  246. for (const auto &[index, account] : _accounts) {
  247. if (account->mtp().environment() == environment) {
  248. return accountConfig(account.get());
  249. }
  250. }
  251. return (environment == MTP::Environment::Production)
  252. ? cloneConfig(Core::App().fallbackProductionConfig())
  253. : std::make_unique<MTP::Config>(environment);
  254. }();
  255. auto index = 0;
  256. while (ranges::contains(_accounts, index, &AccountWithIndex::index)) {
  257. ++index;
  258. }
  259. _accounts.push_back(AccountWithIndex{
  260. .index = index,
  261. .account = std::make_unique<Account>(this, _dataName, index)
  262. });
  263. const auto account = _accounts.back().account.get();
  264. account->setMtpMainDcId(mainDcId);
  265. _local->startAdded(account, std::move(config));
  266. watchSession(account);
  267. _accountsChanges.fire({});
  268. auto &settings = Core::App().settings();
  269. if (_accounts.size() == 2 && !settings.mainMenuAccountsShown()) {
  270. settings.setMainMenuAccountsShown(true);
  271. Core::App().saveSettingsDelayed();
  272. }
  273. return account;
  274. }
  275. void Domain::addActivated(MTP::Environment environment, bool newWindow) {
  276. const auto added = [&](not_null<Main::Account*> account) {
  277. if (newWindow) {
  278. Core::App().ensureSeparateWindowFor(account);
  279. } else if (const auto window = Core::App().separateWindowFor(
  280. account)) {
  281. window->activate();
  282. } else {
  283. activate(account);
  284. }
  285. };
  286. if (accounts().size() < maxAccounts()) {
  287. added(add(environment));
  288. } else {
  289. for (auto &[index, account] : accounts()) {
  290. if (!account->sessionExists()
  291. && account->mtp().environment() == environment) {
  292. added(account.get());
  293. break;
  294. }
  295. }
  296. }
  297. }
  298. void Domain::watchSession(not_null<Account*> account) {
  299. account->sessionValue(
  300. ) | rpl::filter([=](Session *session) {
  301. return session != nullptr;
  302. }) | rpl::start_with_next([=](Session *session) {
  303. session->data().unreadBadgeChanges(
  304. ) | rpl::start_with_next([=] {
  305. scheduleUpdateUnreadBadge();
  306. }, session->lifetime());
  307. Data::AmPremiumValue(
  308. session
  309. ) | rpl::start_with_next([=] {
  310. _lastMaxAccounts = maxAccounts();
  311. }, session->lifetime());
  312. }, account->lifetime());
  313. account->sessionChanges(
  314. ) | rpl::filter([=](Session *session) {
  315. return !session;
  316. }) | rpl::start_with_next([=] {
  317. scheduleUpdateUnreadBadge();
  318. closeAccountWindows(account);
  319. crl::on_main(&Core::App(), [=] {
  320. removeRedundantAccounts();
  321. });
  322. }, account->lifetime());
  323. }
  324. void Domain::closeAccountWindows(not_null<Main::Account*> account) {
  325. auto another = (Main::Account*)nullptr;
  326. for (auto i = _accounts.begin(); i != _accounts.end(); ++i) {
  327. const auto other = not_null(i->account.get());
  328. if (other == account) {
  329. continue;
  330. } else if (Core::App().separateWindowFor(other)) {
  331. const auto that = Core::App().separateWindowFor(account);
  332. if (that) {
  333. that->close();
  334. }
  335. } else if (!another
  336. || (other->sessionExists() && !another->sessionExists())) {
  337. another = other;
  338. }
  339. }
  340. if (another) {
  341. activate(another);
  342. }
  343. }
  344. bool Domain::removePasscodeIfEmpty() {
  345. if (_accounts.size() != 1 || _active.current()->sessionExists()) {
  346. return false;
  347. }
  348. Local::reset();
  349. // We completely logged out, remove the passcode if it was there.
  350. if (Core::App().passcodeLocked()) {
  351. Core::App().unlockPasscode();
  352. }
  353. if (!_local->hasLocalPasscode()) {
  354. return false;
  355. }
  356. _local->setPasscode(QByteArray());
  357. Core::App().settings().setSystemUnlockEnabled(false);
  358. Core::App().saveSettingsDelayed();
  359. return true;
  360. }
  361. void Domain::removeRedundantAccounts() {
  362. Expects(started());
  363. const auto was = _accounts.size();
  364. for (auto i = _accounts.begin(); i != _accounts.end();) {
  365. if (Core::App().separateWindowFor(not_null(i->account.get()))
  366. || i->account->sessionExists()) {
  367. ++i;
  368. continue;
  369. }
  370. checkForLastProductionConfig(i->account.get());
  371. i = _accounts.erase(i);
  372. }
  373. if (!removePasscodeIfEmpty() && _accounts.size() != was) {
  374. scheduleWriteAccounts();
  375. _accountsChanges.fire({});
  376. }
  377. }
  378. void Domain::checkForLastProductionConfig(
  379. not_null<Main::Account*> account) {
  380. const auto mtp = &account->mtp();
  381. if (mtp->environment() != MTP::Environment::Production) {
  382. return;
  383. }
  384. for (const auto &[index, other] : _accounts) {
  385. if (other.get() != account
  386. && other->mtp().environment() == MTP::Environment::Production) {
  387. return;
  388. }
  389. }
  390. Core::App().refreshFallbackProductionConfig(mtp->config());
  391. }
  392. void Domain::maybeActivate(not_null<Main::Account*> account) {
  393. if (Core::App().separateWindowFor(account)) {
  394. activate(account);
  395. } else {
  396. Core::App().preventOrInvoke(crl::guard(account, [=] {
  397. activate(account);
  398. }));
  399. }
  400. }
  401. void Domain::activate(not_null<Main::Account*> account) {
  402. if (const auto window = Core::App().separateWindowFor(account)) {
  403. window->activate();
  404. }
  405. if (_active.current() == account.get()) {
  406. return;
  407. }
  408. const auto i = ranges::find(_accounts, account.get(), [](
  409. const AccountWithIndex &value) {
  410. return value.account.get();
  411. });
  412. Assert(i != end(_accounts));
  413. const auto changed = (_accountToActivate != i->index);
  414. auto wasAuthed = false;
  415. _activeLifetime.destroy();
  416. if (_active.current()) {
  417. _lastActiveIndex = _accountToActivate;
  418. wasAuthed = _active.current()->sessionExists();
  419. }
  420. _accountToActivate = i->index;
  421. _active = account.get();
  422. _active.current()->sessionValue(
  423. ) | rpl::start_to_stream(_activeSessions, _activeLifetime);
  424. if (changed) {
  425. if (wasAuthed) {
  426. scheduleWriteAccounts();
  427. } else {
  428. crl::on_main(&Core::App(), [=] {
  429. removeRedundantAccounts();
  430. });
  431. }
  432. }
  433. }
  434. void Domain::scheduleWriteAccounts() {
  435. if (_writeAccountsScheduled) {
  436. return;
  437. }
  438. _writeAccountsScheduled = true;
  439. crl::on_main(&Core::App(), [=] {
  440. _writeAccountsScheduled = false;
  441. _local->writeAccounts();
  442. });
  443. }
  444. int Domain::maxAccounts() const {
  445. const auto premiumCount = ranges::count_if(accounts(), [](
  446. const Main::Domain::AccountWithIndex &d) {
  447. return d.account->sessionExists()
  448. && (d.account->session().premium()
  449. || d.account->session().isTestMode());
  450. });
  451. return std::min(int(premiumCount) + kMaxAccounts, kPremiumMaxAccounts);
  452. }
  453. rpl::producer<int> Domain::maxAccountsChanges() const {
  454. return _lastMaxAccounts.changes();
  455. }
  456. } // namespace Main