2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 06:35:14 +00:00

Move MTP::Instance to Main::Account.

This commit is contained in:
John Preston
2019-07-24 10:46:23 +02:00
parent db2018c765
commit 9cf4cf6dca
32 changed files with 715 additions and 526 deletions

View File

@@ -72,12 +72,6 @@ constexpr auto kQuitPreventTimeoutMs = 1500;
Application *Application::Instance = nullptr;
struct Application::Private {
UserId authSessionUserId = 0;
QByteArray authSessionUserSerialized;
int32 authSessionUserStreamVersion = 0;
std::unique_ptr<AuthSessionSettings> storedAuthSession;
MTP::Instance::Config mtpConfig;
MTP::AuthKeysList mtpKeysToDestroy;
base::Timer quitTimer;
};
@@ -87,6 +81,7 @@ Application::Application(not_null<Launcher*> launcher)
, _private(std::make_unique<Private>())
, _databases(std::make_unique<Storage::Databases>())
, _animationsManager(std::make_unique<Ui::Animations::Manager>())
, _dcOptions(std::make_unique<MTP::DcOptions>())
, _account(std::make_unique<Main::Account>(cDataFile()))
, _langpack(std::make_unique<Lang::Instance>())
, _emojiKeywords(std::make_unique<ChatHelpers::EmojiKeywords>())
@@ -95,9 +90,26 @@ Application::Application(not_null<Launcher*> launcher)
, _logoNoMargin(Window::LoadLogoNoMargin()) {
Expects(!_logo.isNull());
Expects(!_logoNoMargin.isNull());
Expects(Instance == nullptr);
Instance = this;
activeAccount().sessionChanges(
) | rpl::start_with_next([=] {
if (_mediaView) {
hideMediaView();
_mediaView->clearData();
}
}, _lifetime);
activeAccount().mtpChanges(
) | rpl::filter([=](MTP::Instance *instance) {
return instance != nullptr;
}) | rpl::start_with_next([=](not_null<MTP::Instance*> mtp) {
_langCloudManager = std::make_unique<Lang::CloudManager>(
langpack(),
mtp);
if (!UpdaterDisabled()) {
UpdateChecker().setMtproto(mtp.get());
}
}, _lifetime);
}
Application::~Application() {
@@ -109,14 +121,14 @@ Application::~Application() {
Local::finish();
// Some MTP requests can be cancelled from data clearing.
authSessionDestroy();
unlockTerms();
activeAccount().destroySession();
// The langpack manager should be destroyed before MTProto instance,
// because it is MTP::Sender and it may have pending requests.
_langCloudManager.reset();
_mtproto.reset();
_mtprotoForKeysDestroy.reset();
activeAccount().clearMtp();
Shortcuts::Finish();
@@ -199,7 +211,7 @@ void Application::run() {
DEBUG_LOG(("Application Info: passcode needed..."));
} else {
DEBUG_LOG(("Application Info: local map read..."));
startMtp();
activeAccount().startMtp();
DEBUG_LOG(("Application Info: MTP started..."));
if (activeAccount().sessionExists()) {
_window->setupMain();
@@ -327,31 +339,24 @@ bool Application::eventFilter(QObject *object, QEvent *e) {
void Application::setCurrentProxy(
const ProxyData &proxy,
ProxyData::Settings settings) {
const auto key = [&](const ProxyData &proxy) {
if (proxy.type == ProxyData::Type::Mtproto) {
return std::make_pair(proxy.host, proxy.port);
}
return std::make_pair(QString(), uint32(0));
};
const auto previousKey = key(
(Global::ProxySettings() == ProxyData::Settings::Enabled
const auto current = [&] {
return (Global::ProxySettings() == ProxyData::Settings::Enabled)
? Global::SelectedProxy()
: ProxyData()));
: ProxyData();
};
const auto was = current();
Global::SetSelectedProxy(proxy);
Global::SetProxySettings(settings);
const auto now = current();
refreshGlobalProxy();
if (_mtproto) {
_mtproto->restart();
if (previousKey != key(proxy)) {
_mtproto->reInitConnection(_mtproto->mainDcId());
}
}
if (_mtprotoForKeysDestroy) {
_mtprotoForKeysDestroy->restart();
}
_proxyChanges.fire({ was, now });
Global::RefConnectionTypeChanged().notify();
}
auto Application::proxyChanges() const -> rpl::producer<ProxyChange> {
return _proxyChanges.events();
}
void Application::badMtprotoConfigurationError() {
if (Global::ProxySettings() == ProxyData::Settings::Enabled
&& !_badProxyDisableBox) {
@@ -366,311 +371,16 @@ void Application::badMtprotoConfigurationError() {
}
}
void Application::setMtpMainDcId(MTP::DcId mainDcId) {
Expects(!_mtproto);
_private->mtpConfig.mainDcId = mainDcId;
}
void Application::setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData) {
Expects(!_mtproto);
_private->mtpConfig.keys.push_back(std::make_shared<MTP::AuthKey>(MTP::AuthKey::Type::ReadFromFile, dcId, keyData));
}
QByteArray Application::serializeMtpAuthorization() const {
auto serialize = [this](auto mainDcId, auto &keys, auto &keysToDestroy) {
auto keysSize = [](auto &list) {
return sizeof(qint32) + list.size() * (sizeof(qint32) + MTP::AuthKey::Data().size());
};
auto writeKeys = [](QDataStream &stream, auto &keys) {
stream << qint32(keys.size());
for (auto &key : keys) {
stream << qint32(key->dcId());
key->write(stream);
}
};
auto result = QByteArray();
auto size = sizeof(qint32) + sizeof(qint32); // userId + mainDcId
size += keysSize(keys) + keysSize(keysToDestroy);
result.reserve(size);
{
QDataStream stream(&result, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_1);
auto currentUserId = activeAccount().sessionExists()
? activeAccount().session().userId()
: 0;
stream << qint32(currentUserId) << qint32(mainDcId);
writeKeys(stream, keys);
writeKeys(stream, keysToDestroy);
DEBUG_LOG(("MTP Info: Keys written, userId: %1, dcId: %2").arg(currentUserId).arg(mainDcId));
}
return result;
};
if (_mtproto) {
auto keys = _mtproto->getKeysForWrite();
auto keysToDestroy = _mtprotoForKeysDestroy ? _mtprotoForKeysDestroy->getKeysForWrite() : MTP::AuthKeysList();
return serialize(_mtproto->mainDcId(), keys, keysToDestroy);
}
auto &keys = _private->mtpConfig.keys;
auto &keysToDestroy = _private->mtpKeysToDestroy;
return serialize(_private->mtpConfig.mainDcId, keys, keysToDestroy);
}
void Application::setAuthSessionUserId(UserId userId) {
Expects(!activeAccount().sessionExists());
_private->authSessionUserId = userId;
}
void Application::setAuthSessionFromStorage(
std::unique_ptr<AuthSessionSettings> data,
QByteArray &&selfSerialized,
int32 selfStreamVersion) {
Expects(!activeAccount().sessionExists());
DEBUG_LOG(("authSessionUserSerialized set: %1"
).arg(selfSerialized.size()));
_private->storedAuthSession = std::move(data);
_private->authSessionUserSerialized = std::move(selfSerialized);
_private->authSessionUserStreamVersion = selfStreamVersion;
}
AuthSessionSettings *Application::getAuthSessionSettings() {
if (_private->authSessionUserId) {
return _private->storedAuthSession
? _private->storedAuthSession.get()
: nullptr;
} else if (activeAccount().sessionExists()) {
return &activeAccount().session().settings();
}
return nullptr;
}
void Application::setMtpAuthorization(const QByteArray &serialized) {
Expects(!_mtproto);
QDataStream stream(serialized);
stream.setVersion(QDataStream::Qt_5_1);
auto userId = Serialize::read<qint32>(stream);
auto mainDcId = Serialize::read<qint32>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read main fields from serialized mtp authorization."));
return;
}
setAuthSessionUserId(userId);
_private->mtpConfig.mainDcId = mainDcId;
auto readKeys = [&stream](auto &keys) {
auto count = Serialize::read<qint32>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read keys count from serialized mtp authorization."));
return;
}
keys.reserve(count);
for (auto i = 0; i != count; ++i) {
auto dcId = Serialize::read<qint32>(stream);
auto keyData = Serialize::read<MTP::AuthKey::Data>(stream);
if (stream.status() != QDataStream::Ok) {
LOG(("MTP Error: could not read key from serialized mtp authorization."));
return;
}
keys.push_back(std::make_shared<MTP::AuthKey>(MTP::AuthKey::Type::ReadFromFile, dcId, keyData));
}
};
readKeys(_private->mtpConfig.keys);
readKeys(_private->mtpKeysToDestroy);
LOG(("MTP Info: read keys, current: %1, to destroy: %2").arg(_private->mtpConfig.keys.size()).arg(_private->mtpKeysToDestroy.size()));
}
void Application::startMtp() {
Expects(!_mtproto);
auto config = base::take(_private->mtpConfig);
config.deviceModel = _launcher->deviceModel();
config.systemVersion = _launcher->systemVersion();
_mtproto = std::make_unique<MTP::Instance>(
_dcOptions.get(),
MTP::Instance::Mode::Normal,
std::move(config));
_mtproto->setUserPhone(cLoggedPhoneNumber());
_private->mtpConfig.mainDcId = _mtproto->mainDcId();
_mtproto->setStateChangedHandler([](MTP::ShiftedDcId dc, int32 state) {
if (dc == MTP::maindc()) {
Global::RefConnectionTypeChanged().notify();
}
});
_mtproto->setSessionResetHandler([](MTP::ShiftedDcId shiftedDcId) {
if (App::main() && shiftedDcId == MTP::maindc()) {
App::main()->getDifference();
}
});
if (!_private->mtpKeysToDestroy.empty()) {
destroyMtpKeys(base::take(_private->mtpKeysToDestroy));
}
if (_private->authSessionUserId) {
DEBUG_LOG(("authSessionUserSerialized.size: %1"
).arg(_private->authSessionUserSerialized.size()));
QDataStream peekStream(_private->authSessionUserSerialized);
const auto phone = Serialize::peekUserPhone(
_private->authSessionUserStreamVersion,
peekStream);
const auto flags = MTPDuser::Flag::f_self | (phone.isEmpty()
? MTPDuser::Flag()
: MTPDuser::Flag::f_phone);
authSessionCreate(MTP_user(
MTP_flags(flags),
MTP_int(base::take(_private->authSessionUserId)),
MTPlong(), // access_hash
MTPstring(), // first_name
MTPstring(), // last_name
MTPstring(), // username
MTP_string(phone),
MTPUserProfilePhoto(),
MTPUserStatus(),
MTPint(), // bot_info_version
MTPstring(), // restriction_reason
MTPstring(), // bot_inline_placeholder
MTPstring())); // lang_code
Local::readSelf(
base::take(_private->authSessionUserSerialized),
base::take(_private->authSessionUserStreamVersion));
}
if (_private->storedAuthSession) {
if (activeAccount().sessionExists()) {
activeAccount().session().moveSettingsFrom(
std::move(*_private->storedAuthSession));
}
_private->storedAuthSession.reset();
}
_langCloudManager = std::make_unique<Lang::CloudManager>(
langpack(),
mtp());
if (!UpdaterDisabled()) {
UpdateChecker().setMtproto(mtp());
}
if (activeAccount().sessionExists()) {
// Skip all pending self updates so that we won't Local::writeSelf.
Notify::peerUpdatedSendDelayed();
}
}
void Application::destroyMtpKeys(MTP::AuthKeysList &&keys) {
if (keys.empty()) {
return;
}
if (_mtprotoForKeysDestroy) {
_mtprotoForKeysDestroy->addKeysForDestroy(std::move(keys));
Local::writeMtpData();
return;
}
auto destroyConfig = MTP::Instance::Config();
destroyConfig.mainDcId = MTP::Instance::Config::kNoneMainDc;
destroyConfig.keys = std::move(keys);
destroyConfig.deviceModel = _launcher->deviceModel();
destroyConfig.systemVersion = _launcher->systemVersion();
_mtprotoForKeysDestroy = std::make_unique<MTP::Instance>(
_dcOptions.get(),
MTP::Instance::Mode::KeysDestroyer,
std::move(destroyConfig));
connect(
_mtprotoForKeysDestroy.get(),
&MTP::Instance::allKeysDestroyed,
[=] { allKeysDestroyed(); });
}
void Application::allKeysDestroyed() {
LOG(("MTP Info: all keys scheduled for destroy are destroyed."));
crl::on_main(this, [=] {
_mtprotoForKeysDestroy = nullptr;
Local::writeMtpData();
});
}
void Application::suggestMainDcId(MTP::DcId mainDcId) {
Expects(_mtproto != nullptr);
_mtproto->suggestMainDcId(mainDcId);
if (_private->mtpConfig.mainDcId != MTP::Instance::Config::kNotSetMainDc) {
_private->mtpConfig.mainDcId = mainDcId;
}
}
void Application::destroyStaleAuthorizationKeys() {
Expects(_mtproto != nullptr);
for (const auto &key : _mtproto->getKeysForWrite()) {
// Disable this for now.
if (key->type() == MTP::AuthKey::Type::ReadFromFile) {
_private->mtpKeysToDestroy = _mtproto->getKeysForWrite();
LOG(("MTP Info: destroying stale keys, count: %1"
).arg(_private->mtpKeysToDestroy.size()));
resetAuthorizationKeys();
return;
}
}
}
void Application::configUpdated() {
_configUpdates.fire({});
}
rpl::producer<> Application::configUpdates() const {
return _configUpdates.events();
}
void Application::resetAuthorizationKeys() {
_mtproto = nullptr;
startMtp();
Local::writeMtpData();
}
void Application::startLocalStorage() {
_dcOptions = std::make_unique<MTP::DcOptions>();
_dcOptions->constructFromBuiltIn();
Local::start();
subscribe(_dcOptions->changed(), [this](const MTP::DcOptions::Ids &ids) {
Local::writeSettings();
if (auto instance = mtp()) {
for (auto id : ids) {
if (const auto instance = activeAccount().mtp()) {
for (const auto id : ids) {
instance->restart(id);
}
}
});
activeAccount().sessionChanges(
) | rpl::start_with_next([=] {
crl::on_main(this, [=] {
const auto phone = activeAccount().sessionExists()
? activeAccount().session().user()->phone()
: QString();
const auto support = activeAccount().sessionExists()
&& activeAccount().session().supportMode();
if (cLoggedPhoneNumber() != phone) {
cSetLoggedPhoneNumber(phone);
if (_mtproto) {
_mtproto->setUserPhone(phone);
}
Local::writeSettings();
}
if (_mtproto) {
_mtproto->requestConfig();
}
Platform::SetApplicationIcon(
Window::CreateIcon(&activeAccount()));
Shortcuts::ToggleSupportShortcuts(support);
});
}, _lifetime);
}
void Application::forceLogOut(const TextWithEntities &explanation) {
@@ -681,10 +391,7 @@ void Application::forceLogOut(const TextWithEntities &explanation) {
box->setCloseByOutsideClick(false);
connect(box, &QObject::destroyed, [=] {
crl::on_main(this, [=] {
if (AuthSession::Exists()) {
resetAuthorizationKeys();
loggedOut();
}
activeAccount().forcedLogOut();
});
});
}
@@ -773,41 +480,6 @@ void Application::writeInstallBetaVersionsSetting() {
_launcher->writeInstallBetaVersionsSetting();
}
void Application::authSessionCreate(const MTPUser &user) {
Expects(_mtproto != nullptr);
_mtproto->setUpdatesHandler(::rpcDone([](
const mtpPrime *from,
const mtpPrime *end) {
if (const auto main = App::main()) {
return main->updateReceived(from, end);
}
return true;
}));
_mtproto->setGlobalFailHandler(::rpcFail([=](const RPCError &error) {
if (activeAccount().sessionExists()) {
crl::on_main(&activeAccount().session(), [=] { logOut(); });
}
return true;
}));
activeAccount().createSession(user);
}
void Application::authSessionDestroy() {
_private->storedAuthSession.reset();
_private->authSessionUserId = 0;
_private->authSessionUserSerialized = {};
if (activeAccount().sessionExists()) {
unlockTerms();
_mtproto->clearGlobalHandlers();
activeAccount().destroySession();
Notify::unreadCounterUpdated();
}
}
int Application::unreadBadge() const {
return activeAccount().sessionExists()
? activeAccount().session().data().unreadBadge()
@@ -897,7 +569,9 @@ void Application::lockByPasscode() {
void Application::unlockPasscode() {
clearPasscodeLock();
_window->clearPasscodeLock();
if (_window) {
_window->clearPasscodeLock();
}
}
void Application::clearPasscodeLock() {
@@ -1011,48 +685,6 @@ void Application::checkMediaViewActivation() {
}
}
void Application::logOut() {
if (_mtproto) {
_mtproto->logout(::rpcDone([=] {
loggedOut();
}), ::rpcFail([=] {
loggedOut();
return true;
}));
} else {
// We log out because we've forgotten passcode.
// So we just start mtproto from scratch.
startMtp();
loggedOut();
}
}
void Application::loggedOut() {
if (Global::LocalPasscode()) {
Global::SetLocalPasscode(false);
Global::RefLocalPasscodeChanged().notify();
}
clearPasscodeLock();
Media::Player::mixer()->stopAndClear();
Global::SetVoiceMsgPlaybackDoubled(false);
if (const auto window = activeWindow()) {
window->tempDirDelete(Local::ClearManagerAll);
window->setupIntro();
}
if (activeAccount().sessionExists()) {
activeAccount().session().data().clearLocalStorage();
authSessionDestroy();
}
if (_mediaView) {
hideMediaView();
_mediaView->clearData();
}
Local::reset();
cSetOtherOnline(0);
Images::ClearRemote();
}
QPoint Application::getPointForCallPanelCenter() const {
if (const auto window = activeWindow()) {
return window->getPointForCallPanelCenter();