mirror of https://github.com/procxx/kepka.git
MTP global state moved to MTP::Instance class.
Now there will be ability to start multiple mtproto instances.
This commit is contained in:
parent
c3b3819d9f
commit
dd933cf61c
|
@ -226,11 +226,11 @@ namespace {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void logOut() {
|
void logOut() {
|
||||||
if (MTP::started()) {
|
if (auto mtproto = Messenger::Instance().mtp()) {
|
||||||
MTP::logoutKeys(rpcDone(&loggedOut), rpcFail(&loggedOut));
|
mtproto->logout(rpcDone(&loggedOut), rpcFail(&loggedOut));
|
||||||
} else {
|
} else {
|
||||||
loggedOut();
|
loggedOut();
|
||||||
MTP::start();
|
Messenger::Instance().startMtp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ void unixtimeSet(int32 serverTime, bool force) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeId unixtime() {
|
TimeId unixtime() {
|
||||||
TimeId result = myunixtime();
|
auto result = myunixtime();
|
||||||
|
|
||||||
QReadLocker locker(&unixtimeLock);
|
QReadLocker locker(&unixtimeLock);
|
||||||
return result + unixtimeDelta;
|
return result + unixtimeDelta;
|
||||||
|
|
|
@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "core/basic_types.h"
|
#include "core/basic_types.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
|
@ -89,6 +90,50 @@ inline bool contains(const Container &container, const T &value) {
|
||||||
return std::find(std::begin(container), end, value) != end;
|
return std::find(std::begin(container), end, value) != end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need a custom comparator for std::set<std::unique_ptr<T>>::find to work with pointers.
|
||||||
|
// thanks to http://stackoverflow.com/questions/18939882/raw-pointer-lookup-for-sets-of-unique-ptrs
|
||||||
|
template <typename T>
|
||||||
|
struct pointer_comparator {
|
||||||
|
using is_transparent = std::true_type;
|
||||||
|
|
||||||
|
// helper does some magic in order to reduce the number of
|
||||||
|
// pairs of types we need to know how to compare: it turns
|
||||||
|
// everything into a pointer, and then uses `std::less<T*>`
|
||||||
|
// to do the comparison:
|
||||||
|
struct helper {
|
||||||
|
T *ptr = nullptr;
|
||||||
|
helper() = default;
|
||||||
|
helper(const helper &other) = default;
|
||||||
|
helper(T *p) : ptr(p) {
|
||||||
|
}
|
||||||
|
template <typename ...Ts>
|
||||||
|
helper(const std::shared_ptr<Ts...> &other) : ptr(other.get()) {
|
||||||
|
}
|
||||||
|
template <typename ...Ts>
|
||||||
|
helper(const std::unique_ptr<Ts...> &other) : ptr(other.get()) {
|
||||||
|
}
|
||||||
|
bool operator<(helper other) const {
|
||||||
|
return std::less<T*>()(ptr, other.ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// without helper, we'd need 2^n different overloads, where
|
||||||
|
// n is the number of types we want to support (so, 8 with
|
||||||
|
// raw pointers, unique pointers, and shared pointers). That
|
||||||
|
// seems silly.
|
||||||
|
// && helps enforce rvalue use only
|
||||||
|
bool operator()(const helper &&lhs, const helper &&rhs) const {
|
||||||
|
return lhs < rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using set_of_unique_ptr = std::set<std::unique_ptr<T>, base::pointer_comparator<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using set_of_shared_ptr = std::set<std::shared_ptr<T>, base::pointer_comparator<T>>;
|
||||||
|
|
||||||
} // namespace base
|
} // namespace base
|
||||||
|
|
||||||
// using for_const instead of plain range-based for loop to ensure usage of const_iterator
|
// using for_const instead of plain range-based for loop to ensure usage of const_iterator
|
||||||
|
@ -162,7 +207,6 @@ inline void t_assert_fail(const char *message, const char *file, int32 line) {
|
||||||
|
|
||||||
class Exception : public std::exception {
|
class Exception : public std::exception {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Exception(const QString &msg, bool isFatal = true) : _fatal(isFatal), _msg(msg.toUtf8()) {
|
Exception(const QString &msg, bool isFatal = true) : _fatal(isFatal), _msg(msg.toUtf8()) {
|
||||||
LOG(("Exception: %1").arg(msg));
|
LOG(("Exception: %1").arg(msg));
|
||||||
}
|
}
|
||||||
|
@ -179,6 +223,7 @@ public:
|
||||||
private:
|
private:
|
||||||
bool _fatal;
|
bool _fatal;
|
||||||
QByteArray _msg;
|
QByteArray _msg;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MTPint;
|
class MTPint;
|
||||||
|
|
|
@ -265,7 +265,7 @@ bool Widget::resetFail(const RPCError &error) {
|
||||||
void Widget::gotNearestDC(const MTPNearestDc &result) {
|
void Widget::gotNearestDC(const MTPNearestDc &result) {
|
||||||
auto &nearest = result.c_nearestDc();
|
auto &nearest = result.c_nearestDc();
|
||||||
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(nearest.vcountry.c_string().v.c_str()).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v));
|
DEBUG_LOG(("Got nearest dc, country: %1, nearest: %2, this: %3").arg(nearest.vcountry.c_string().v.c_str()).arg(nearest.vnearest_dc.v).arg(nearest.vthis_dc.v));
|
||||||
MTP::setdc(nearest.vnearest_dc.v, true);
|
Messenger::Instance().mtp()->suggestMainDcId(nearest.vnearest_dc.v);
|
||||||
auto nearestCountry = qs(nearest.vcountry);
|
auto nearestCountry = qs(nearest.vcountry);
|
||||||
if (getData()->country != nearestCountry) {
|
if (getData()->country != nearestCountry) {
|
||||||
getData()->country = nearestCountry;
|
getData()->country = nearestCountry;
|
||||||
|
|
|
@ -504,7 +504,7 @@ enum { // Local Storage Keys
|
||||||
enum {
|
enum {
|
||||||
dbiKey = 0x00,
|
dbiKey = 0x00,
|
||||||
dbiUser = 0x01,
|
dbiUser = 0x01,
|
||||||
dbiDcOptionOld = 0x02,
|
dbiDcOptionOldOld = 0x02,
|
||||||
dbiChatSizeMax = 0x03,
|
dbiChatSizeMax = 0x03,
|
||||||
dbiMutePeer = 0x04,
|
dbiMutePeer = 0x04,
|
||||||
dbiSendKey = 0x05,
|
dbiSendKey = 0x05,
|
||||||
|
@ -541,7 +541,7 @@ enum {
|
||||||
dbiRecentEmojiOld = 0x24,
|
dbiRecentEmojiOld = 0x24,
|
||||||
dbiEmojiVariantsOld = 0x25,
|
dbiEmojiVariantsOld = 0x25,
|
||||||
dbiRecentStickers = 0x26,
|
dbiRecentStickers = 0x26,
|
||||||
dbiDcOption = 0x27,
|
dbiDcOptionOld = 0x27,
|
||||||
dbiTryIPv6 = 0x28,
|
dbiTryIPv6 = 0x28,
|
||||||
dbiSongVolume = 0x29,
|
dbiSongVolume = 0x29,
|
||||||
dbiWindowsNotificationsOld = 0x30,
|
dbiWindowsNotificationsOld = 0x30,
|
||||||
|
@ -567,6 +567,7 @@ enum {
|
||||||
dbiDialogsWidthRatio = 0x48,
|
dbiDialogsWidthRatio = 0x48,
|
||||||
dbiUseExternalVideoPlayer = 0x49,
|
dbiUseExternalVideoPlayer = 0x49,
|
||||||
dbiDcOptions = 0x4a,
|
dbiDcOptions = 0x4a,
|
||||||
|
dbiMtpAuthorization = 0x4b,
|
||||||
|
|
||||||
dbiEncryptedWithSalt = 333,
|
dbiEncryptedWithSalt = 333,
|
||||||
dbiEncrypted = 444,
|
dbiEncrypted = 444,
|
||||||
|
@ -843,7 +844,7 @@ void applyReadContext(const ReadSettingsContext &context) {
|
||||||
|
|
||||||
bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSettingsContext &context) {
|
bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSettingsContext &context) {
|
||||||
switch (blockId) {
|
switch (blockId) {
|
||||||
case dbiDcOptionOld: {
|
case dbiDcOptionOldOld: {
|
||||||
quint32 dcId, port;
|
quint32 dcId, port;
|
||||||
QString host, ip;
|
QString host, ip;
|
||||||
stream >> dcId >> host >> ip >> port;
|
stream >> dcId >> host >> ip >> port;
|
||||||
|
@ -852,7 +853,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
||||||
context.dcOptions.constructAddOne(dcId, 0, ip.toStdString(), port);
|
context.dcOptions.constructAddOne(dcId, 0, ip.toStdString(), port);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case dbiDcOption: {
|
case dbiDcOptionOld: {
|
||||||
quint32 dcIdWithShift, port;
|
quint32 dcIdWithShift, port;
|
||||||
qint32 flags;
|
qint32 flags;
|
||||||
QString ip;
|
QString ip;
|
||||||
|
@ -863,7 +864,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case dbiDcOptions: {
|
case dbiDcOptions: {
|
||||||
QByteArray serialized;
|
auto serialized = QByteArray();
|
||||||
stream >> serialized;
|
stream >> serialized;
|
||||||
if (!_checkStreamStatus(stream)) return false;
|
if (!_checkStreamStatus(stream)) return false;
|
||||||
|
|
||||||
|
@ -909,8 +910,7 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
||||||
if (!_checkStreamStatus(stream)) return false;
|
if (!_checkStreamStatus(stream)) return false;
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: user found, dc %1, uid %2").arg(dcId).arg(userId));
|
DEBUG_LOG(("MTP Info: user found, dc %1, uid %2").arg(dcId).arg(userId));
|
||||||
MTP::configure(dcId);
|
Messenger::Instance().setMtpMainDcId(dcId);
|
||||||
|
|
||||||
if (userId) {
|
if (userId) {
|
||||||
Messenger::Instance().authSessionCreate(UserId(userId));
|
Messenger::Instance().authSessionCreate(UserId(userId));
|
||||||
}
|
}
|
||||||
|
@ -923,7 +923,15 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting
|
||||||
stream.readRawData(key.data(), key.size());
|
stream.readRawData(key.data(), key.size());
|
||||||
if (!_checkStreamStatus(stream)) return false;
|
if (!_checkStreamStatus(stream)) return false;
|
||||||
|
|
||||||
MTP::setKey(dcId, key);
|
Messenger::Instance().setMtpKey(dcId, key);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case dbiMtpAuthorization: {
|
||||||
|
auto serialized = QByteArray();
|
||||||
|
stream >> serialized;
|
||||||
|
if (!_checkStreamStatus(stream)) return false;
|
||||||
|
|
||||||
|
Messenger::Instance().setMtpAuthorization(serialized);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case dbiAutoStart: {
|
case dbiAutoStart: {
|
||||||
|
@ -1777,18 +1785,12 @@ void _writeMtpData() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto keys = MTP::getKeys();
|
auto mtpAuthorizationSerialized = Messenger::Instance().serializeMtpAuthorization();
|
||||||
|
|
||||||
quint32 size = sizeof(quint32) + sizeof(qint32) + sizeof(quint32);
|
quint32 size = sizeof(quint32) + Serialize::bytearraySize(mtpAuthorizationSerialized);
|
||||||
size += keys.size() * (sizeof(quint32) + sizeof(quint32) + MTP::AuthKey::kSize);
|
|
||||||
|
|
||||||
EncryptedDescriptor data(size);
|
EncryptedDescriptor data(size);
|
||||||
data.stream << quint32(dbiUser) << qint32(AuthSession::CurrentUserId()) << quint32(MTP::maindc());
|
data.stream << quint32(dbiMtpAuthorization) << mtpAuthorizationSerialized;
|
||||||
for_const (auto &key, keys) {
|
|
||||||
data.stream << quint32(dbiKey) << quint32(key->getDC());
|
|
||||||
key->write(data.stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
mtp.writeEncrypted(data);
|
mtp.writeEncrypted(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include "pspecific.h"
|
#include "pspecific.h"
|
||||||
|
#include "mtproto/connection.h"
|
||||||
|
|
||||||
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
#ifndef TDESKTOP_DISABLE_CRASH_REPORTS
|
||||||
|
|
||||||
|
@ -87,9 +88,8 @@ QString _logsEntryStart() {
|
||||||
static int32 index = 0;
|
static int32 index = 0;
|
||||||
QDateTime tm(QDateTime::currentDateTime());
|
QDateTime tm(QDateTime::currentDateTime());
|
||||||
|
|
||||||
QThread *thread = QThread::currentThread();
|
auto thread = qobject_cast<MTP::internal::Thread*>(QThread::currentThread());
|
||||||
MTP::internal::Thread *mtpThread = qobject_cast<MTP::internal::Thread*>(thread);
|
auto threadId = thread ? thread->getThreadIndex() : 0;
|
||||||
uint threadId = mtpThread ? mtpThread->getThreadId() : 0;
|
|
||||||
|
|
||||||
return QString("[%1 %2-%3]").arg(tm.toString("hh:mm:ss.zzz")).arg(QString("%1").arg(threadId, 2, 10, QChar('0'))).arg(++index, 7, 10, QChar('0'));
|
return QString("[%1 %2-%3]").arg(tm.toString("hh:mm:ss.zzz")).arg(QString("%1").arg(threadId, 2, 10, QChar('0'))).arg(++index, 7, 10, QChar('0'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,9 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
|
||||||
, _playerPanel(this, Media::Player::Panel::Layout::Full)
|
, _playerPanel(this, Media::Player::Panel::Layout::Full)
|
||||||
, _mediaType(this, st::defaultDropdownMenu)
|
, _mediaType(this, st::defaultDropdownMenu)
|
||||||
, _api(new ApiWrap(this)) {
|
, _api(new ApiWrap(this)) {
|
||||||
MTP::setGlobalDoneHandler(rpcDone(&MainWidget::updateReceived));
|
Messenger::Instance().mtp()->setUpdatesHandler(rpcDone(&MainWidget::updateReceived));
|
||||||
|
Messenger::Instance().mtp()->setGlobalFailHandler(rpcFail(&MainWidget::updateFail));
|
||||||
|
|
||||||
_ptsWaiter.setRequesting(true);
|
_ptsWaiter.setRequesting(true);
|
||||||
updateScrollColors();
|
updateScrollColors();
|
||||||
|
|
||||||
|
@ -174,8 +176,6 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent)
|
||||||
|
|
||||||
orderWidgets();
|
orderWidgets();
|
||||||
|
|
||||||
MTP::setGlobalFailHandler(rpcFail(&MainWidget::updateFail));
|
|
||||||
|
|
||||||
_mediaType->hide();
|
_mediaType->hide();
|
||||||
_mediaType->setOrigin(Ui::PanelAnimation::Origin::TopRight);
|
_mediaType->setOrigin(Ui::PanelAnimation::Origin::TopRight);
|
||||||
_topBar->mediaTypeButton()->installEventFilter(_mediaType);
|
_topBar->mediaTypeButton()->installEventFilter(_mediaType);
|
||||||
|
@ -4279,7 +4279,7 @@ MainWidget::~MainWidget() {
|
||||||
_hider = nullptr;
|
_hider = nullptr;
|
||||||
delete hider;
|
delete hider;
|
||||||
}
|
}
|
||||||
MTP::clearGlobalHandlers();
|
Messenger::Instance().mtp()->clearGlobalHandlers();
|
||||||
|
|
||||||
if (App::wnd()) App::wnd()->noMain(this);
|
if (App::wnd()) App::wnd()->noMain(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "fileuploader.h"
|
#include "fileuploader.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mtproto/dc_options.h"
|
#include "mtproto/dc_options.h"
|
||||||
|
#include "mtproto/mtp_instance.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
|
@ -43,25 +44,18 @@ namespace {
|
||||||
|
|
||||||
Messenger *SingleInstance = nullptr;
|
Messenger *SingleInstance = nullptr;
|
||||||
|
|
||||||
void mtpStateChanged(int32 dc, int32 state) {
|
|
||||||
if (App::wnd()) {
|
|
||||||
App::wnd()->mtpStateChanged(dc, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mtpSessionReset(int32 dc) {
|
|
||||||
if (App::main() && dc == MTP::maindc()) {
|
|
||||||
App::main()->getDifference();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Messenger *Messenger::InstancePointer() {
|
Messenger *Messenger::InstancePointer() {
|
||||||
return SingleInstance;
|
return SingleInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
Messenger::Messenger() : QObject() {
|
struct Messenger::Private {
|
||||||
|
MTP::Instance::Config mtpConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
Messenger::Messenger() : QObject()
|
||||||
|
, _private(std::make_unique<Private>()) {
|
||||||
t_assert(SingleInstance == nullptr);
|
t_assert(SingleInstance == nullptr);
|
||||||
SingleInstance = this;
|
SingleInstance = this;
|
||||||
|
|
||||||
|
@ -126,12 +120,9 @@ Messenger::Messenger() : QObject() {
|
||||||
DEBUG_LOG(("Application Info: passcode needed..."));
|
DEBUG_LOG(("Application Info: passcode needed..."));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_LOG(("Application Info: local map read..."));
|
DEBUG_LOG(("Application Info: local map read..."));
|
||||||
MTP::start();
|
startMtp();
|
||||||
}
|
}
|
||||||
|
|
||||||
MTP::setStateChangedHandler(mtpStateChanged);
|
|
||||||
MTP::setSessionResetHandler(mtpSessionReset);
|
|
||||||
|
|
||||||
DEBUG_LOG(("Application Info: MTP started..."));
|
DEBUG_LOG(("Application Info: MTP started..."));
|
||||||
|
|
||||||
DEBUG_LOG(("Application Info: showing."));
|
DEBUG_LOG(("Application Info: showing."));
|
||||||
|
@ -168,6 +159,107 @@ Messenger::Messenger() : QObject() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Messenger::setMtpMainDcId(MTP::DcId mainDcId) {
|
||||||
|
t_assert(!_mtproto);
|
||||||
|
_private->mtpConfig.mainDcId = mainDcId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Messenger::setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData) {
|
||||||
|
t_assert(!_mtproto);
|
||||||
|
_private->mtpConfig.keys.insert(std::make_pair(dcId, keyData));
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray Messenger::serializeMtpAuthorization() const {
|
||||||
|
auto serialize = [this](auto keysCount, auto mainDcId, auto writeKeys) {
|
||||||
|
auto result = QByteArray();
|
||||||
|
auto size = sizeof(qint32) + sizeof(qint32) + sizeof(qint32); // userId + mainDcId + keys count
|
||||||
|
size += keysCount * (sizeof(qint32) + MTP::AuthKey::Data().size());
|
||||||
|
result.reserve(size);
|
||||||
|
{
|
||||||
|
QBuffer buffer(&result);
|
||||||
|
if (!buffer.open(QIODevice::WriteOnly)) {
|
||||||
|
LOG(("MTP Error: could not open buffer to serialize mtp authorization."));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
QDataStream stream(&buffer);
|
||||||
|
stream.setVersion(QDataStream::Qt_5_1);
|
||||||
|
|
||||||
|
stream << qint32(AuthSession::CurrentUserId()) << qint32(mainDcId) << qint32(keysCount);
|
||||||
|
writeKeys(stream);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
if (_mtproto) {
|
||||||
|
auto keys = _mtproto->getKeysForWrite();
|
||||||
|
return serialize(keys.size(), _mtproto->mainDcId(), [&keys](QDataStream &stream) {
|
||||||
|
for (auto &key : keys) {
|
||||||
|
stream << qint32(key->getDC());
|
||||||
|
key->write(stream);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
auto &keys = _private->mtpConfig.keys;
|
||||||
|
return serialize(keys.size(), _private->mtpConfig.mainDcId, [&keys](QDataStream &stream) {
|
||||||
|
for (auto &key : keys) {
|
||||||
|
stream << qint32(key.first);
|
||||||
|
stream.writeRawData(key.second.data(), key.second.size());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Messenger::setMtpAuthorization(const QByteArray &serialized) {
|
||||||
|
t_assert(!_mtproto);
|
||||||
|
t_assert(!authSession());
|
||||||
|
|
||||||
|
auto readonly = serialized;
|
||||||
|
QBuffer buffer(&readonly);
|
||||||
|
if (!buffer.open(QIODevice::ReadOnly)) {
|
||||||
|
LOG(("MTP Error: could not open serialized mtp authorization for reading."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QDataStream stream(&buffer);
|
||||||
|
stream.setVersion(QDataStream::Qt_5_1);
|
||||||
|
|
||||||
|
qint32 userId = 0, mainDcId = 0, count = 0;
|
||||||
|
stream >> userId >> mainDcId >> count;
|
||||||
|
if (stream.status() != QDataStream::Ok) {
|
||||||
|
LOG(("MTP Error: could not read main fields from serialized mtp authorization."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userId) {
|
||||||
|
authSessionCreate(userId);
|
||||||
|
}
|
||||||
|
_private->mtpConfig.mainDcId = mainDcId;
|
||||||
|
for (auto i = 0; i != count; ++i) {
|
||||||
|
qint32 dcId = 0;
|
||||||
|
MTP::AuthKey::Data keyData;
|
||||||
|
stream >> dcId;
|
||||||
|
stream.readRawData(keyData.data(), keyData.size());
|
||||||
|
if (stream.status() != QDataStream::Ok) {
|
||||||
|
LOG(("MTP Error: could not read key from serialized mtp authorization."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_private->mtpConfig.keys.insert(std::make_pair(dcId, keyData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Messenger::startMtp() {
|
||||||
|
t_assert(!_mtproto);
|
||||||
|
_mtproto = std::make_unique<MTP::Instance>(_dcOptions.get(), std::move(_private->mtpConfig));
|
||||||
|
|
||||||
|
_mtproto->setStateChangedHandler([](MTP::ShiftedDcId shiftedDcId, int32 state) {
|
||||||
|
if (App::wnd()) {
|
||||||
|
App::wnd()->mtpStateChanged(shiftedDcId, state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_mtproto->setSessionResetHandler([](MTP::ShiftedDcId shiftedDcId) {
|
||||||
|
if (App::main() && shiftedDcId == MTP::maindc()) {
|
||||||
|
App::main()->getDifference();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Messenger::loadLanguage() {
|
void Messenger::loadLanguage() {
|
||||||
if (cLang() < languageTest) {
|
if (cLang() < languageTest) {
|
||||||
cSetLang(Sandbox::LangSystem());
|
cSetLang(Sandbox::LangSystem());
|
||||||
|
@ -199,10 +291,12 @@ void Messenger::startLocalStorage() {
|
||||||
_dcOptions = std::make_unique<MTP::DcOptions>();
|
_dcOptions = std::make_unique<MTP::DcOptions>();
|
||||||
_dcOptions->constructFromBuiltIn();
|
_dcOptions->constructFromBuiltIn();
|
||||||
Local::start();
|
Local::start();
|
||||||
subscribe(_dcOptions->changed(), [](const MTP::DcOptions::Ids &ids) {
|
subscribe(_dcOptions->changed(), [this](const MTP::DcOptions::Ids &ids) {
|
||||||
Local::writeSettings();
|
Local::writeSettings();
|
||||||
|
if (auto instance = mtp()) {
|
||||||
for (auto id : ids) {
|
for (auto id : ids) {
|
||||||
MTP::restart(id);
|
instance->restart(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -499,7 +593,7 @@ void Messenger::checkMapVersion() {
|
||||||
|
|
||||||
void Messenger::prepareToDestroy() {
|
void Messenger::prepareToDestroy() {
|
||||||
_window.reset();
|
_window.reset();
|
||||||
MTP::finish();
|
_mtproto.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Messenger::~Messenger() {
|
Messenger::~Messenger() {
|
||||||
|
|
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
class DcOptions;
|
class DcOptions;
|
||||||
|
class Instance;
|
||||||
} // namespace MTP
|
} // namespace MTP
|
||||||
|
|
||||||
class AuthSession;
|
class AuthSession;
|
||||||
|
@ -55,6 +56,16 @@ public:
|
||||||
MTP::DcOptions *dcOptions() {
|
MTP::DcOptions *dcOptions() {
|
||||||
return _dcOptions.get();
|
return _dcOptions.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMtpMainDcId(MTP::DcId mainDcId);
|
||||||
|
void setMtpKey(MTP::DcId dcId, const MTP::AuthKey::Data &keyData);
|
||||||
|
QByteArray serializeMtpAuthorization() const;
|
||||||
|
void setMtpAuthorization(const QByteArray &serialized);
|
||||||
|
void startMtp();
|
||||||
|
MTP::Instance *mtp() {
|
||||||
|
return _mtproto.get();
|
||||||
|
}
|
||||||
|
|
||||||
AuthSession *authSession() {
|
AuthSession *authSession() {
|
||||||
return _authSession.get();
|
return _authSession.get();
|
||||||
}
|
}
|
||||||
|
@ -114,13 +125,16 @@ private:
|
||||||
QMap<int32, TimeMs> killDownloadSessionTimes;
|
QMap<int32, TimeMs> killDownloadSessionTimes;
|
||||||
SingleTimer killDownloadSessionsTimer;
|
SingleTimer killDownloadSessionsTimer;
|
||||||
|
|
||||||
TimeMs _lastActionTime = 0;
|
// Some fields are just moved from the declaration.
|
||||||
|
struct Private;
|
||||||
|
const std::unique_ptr<Private> _private;
|
||||||
|
|
||||||
std::unique_ptr<MainWindow> _window;
|
std::unique_ptr<MainWindow> _window;
|
||||||
FileUploader *_uploader = nullptr;
|
FileUploader *_uploader = nullptr;
|
||||||
Translator *_translator = nullptr;
|
Translator *_translator = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<MTP::DcOptions> _dcOptions;
|
std::unique_ptr<MTP::DcOptions> _dcOptions;
|
||||||
|
std::unique_ptr<MTP::Instance> _mtproto;
|
||||||
std::unique_ptr<AuthSession> _authSession;
|
std::unique_ptr<AuthSession> _authSession;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,9 +40,31 @@ using std::string;
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest = 0) {
|
||||||
|
mtpMsgId afterId(*(mtpMsgId*)(from->after->data() + 4));
|
||||||
|
mtpRequestMap::const_iterator i = afterId ? haveSent.constFind(afterId) : haveSent.cend();
|
||||||
|
int32 size = to->size(), lenInInts = (from.innerLength() >> 2), headlen = 4, fulllen = headlen + lenInInts;
|
||||||
|
if (i == haveSent.constEnd()) { // no invoke after or such msg was not sent or was completed recently
|
||||||
|
to->resize(size + fulllen + skipBeforeRequest);
|
||||||
|
if (skipBeforeRequest) {
|
||||||
|
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
|
||||||
|
memcpy(to->data() + size + headlen + skipBeforeRequest, from->constData() + 4 + headlen, lenInInts * sizeof(mtpPrime));
|
||||||
|
} else {
|
||||||
|
memcpy(to->data() + size, from->constData() + 4, fulllen * sizeof(mtpPrime));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
to->resize(size + fulllen + skipBeforeRequest + 3);
|
||||||
|
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
|
||||||
|
(*to)[size + 3] += 3 * sizeof(mtpPrime);
|
||||||
|
*((mtpTypeId*)&((*to)[size + headlen + skipBeforeRequest])) = mtpc_invokeAfterMsg;
|
||||||
|
memcpy(to->data() + size + headlen + skipBeforeRequest + 1, &afterId, 2 * sizeof(mtpPrime));
|
||||||
|
memcpy(to->data() + size + headlen + skipBeforeRequest + 3, from->constData() + 4 + headlen, lenInInts * sizeof(mtpPrime));
|
||||||
|
if (size + 3 != 7) (*to)[7] += 3 * sizeof(mtpPrime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool parsePQ(const string &pqStr, string &pStr, string &qStr) {
|
bool parsePQ(const string &pqStr, string &pStr, string &qStr) {
|
||||||
if (pqStr.length() > 8) return false; // more than 64 bit pq
|
if (pqStr.length() > 8) return false; // more than 64 bit pq
|
||||||
|
|
||||||
|
@ -321,35 +343,20 @@ RSAPublicKeys InitRSAPublicKeys() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
uint32 ThreadIdIncrement = 0;
|
Connection::Connection(Instance *instance) : _instance(instance) {
|
||||||
|
|
||||||
Thread::Thread() : QThread(nullptr)
|
|
||||||
, _threadId(++ThreadIdIncrement) {
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 Thread::getThreadId() const {
|
|
||||||
return _threadId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::~Thread() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Connection::Connection() : thread(nullptr), data(nullptr) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Connection::prepare(SessionData *sessionData, int32 dc) {
|
int32 Connection::prepare(SessionData *sessionData, int32 dc) {
|
||||||
t_assert(thread == nullptr && data == nullptr);
|
t_assert(thread == nullptr && data == nullptr);
|
||||||
|
|
||||||
thread = new Thread();
|
thread = std::make_unique<Thread>();
|
||||||
data = new ConnectionPrivate(thread, this, sessionData, dc);
|
auto newData = std::make_unique<ConnectionPrivate>(_instance, thread.get(), this, sessionData, dc);
|
||||||
|
dc = newData->getDC();
|
||||||
dc = data->getDC();
|
if (dc) {
|
||||||
if (!dc) {
|
// will be deleted in the thread::finished signal
|
||||||
delete data;
|
data = newData.release();
|
||||||
data = nullptr;
|
} else {
|
||||||
delete thread;
|
thread.reset();
|
||||||
thread = nullptr;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return dc;
|
return dc;
|
||||||
}
|
}
|
||||||
|
@ -361,9 +368,8 @@ void Connection::start() {
|
||||||
void Connection::kill() {
|
void Connection::kill() {
|
||||||
t_assert(data != nullptr && thread != nullptr);
|
t_assert(data != nullptr && thread != nullptr);
|
||||||
data->stop();
|
data->stop();
|
||||||
data = nullptr; // will be deleted in thread::finished signal
|
data = nullptr;
|
||||||
thread->quit();
|
thread->quit();
|
||||||
queueQuittingConnection(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::waitTillFinish() {
|
void Connection::waitTillFinish() {
|
||||||
|
@ -371,8 +377,7 @@ void Connection::waitTillFinish() {
|
||||||
|
|
||||||
DEBUG_LOG(("Waiting for connectionThread to finish"));
|
DEBUG_LOG(("Waiting for connectionThread to finish"));
|
||||||
thread->wait();
|
thread->wait();
|
||||||
delete thread;
|
thread.reset();
|
||||||
thread = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Connection::state() const {
|
int32 Connection::state() const {
|
||||||
|
@ -388,7 +393,10 @@ QString Connection::transport() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection::~Connection() {
|
Connection::~Connection() {
|
||||||
t_assert(data == nullptr && thread == nullptr);
|
t_assert(data == nullptr);
|
||||||
|
if (thread) {
|
||||||
|
waitTillFinish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionPrivate::createConn(bool createIPv4, bool createIPv6) {
|
void ConnectionPrivate::createConn(bool createIPv4, bool createIPv6) {
|
||||||
|
@ -440,7 +448,8 @@ void ConnectionPrivate::destroyConn(AbstractConnection **conn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionPrivate::ConnectionPrivate(QThread *thread, Connection *owner, SessionData *data, uint32 _dc) : QObject(nullptr)
|
ConnectionPrivate::ConnectionPrivate(Instance *instance, QThread *thread, Connection *owner, SessionData *data, uint32 _dc) : QObject()
|
||||||
|
, _instance(instance)
|
||||||
, _state(DisconnectedState)
|
, _state(DisconnectedState)
|
||||||
, dc(_dc)
|
, dc(_dc)
|
||||||
, _owner(owner)
|
, _owner(owner)
|
||||||
|
@ -463,7 +472,7 @@ ConnectionPrivate::ConnectionPrivate(QThread *thread, Connection *owner, Session
|
||||||
|
|
||||||
connect(thread, SIGNAL(started()), this, SLOT(socketStart()));
|
connect(thread, SIGNAL(started()), this, SLOT(socketStart()));
|
||||||
connect(thread, SIGNAL(finished()), this, SLOT(doFinish()));
|
connect(thread, SIGNAL(finished()), this, SLOT(doFinish()));
|
||||||
connect(this, SIGNAL(finished(Connection*)), globalSlotCarrier(), SLOT(connectionFinished(Connection*)), Qt::QueuedConnection);
|
connect(this, SIGNAL(finished(internal::Connection*)), _instance, SLOT(connectionFinished(internal::Connection*)), Qt::QueuedConnection);
|
||||||
|
|
||||||
connect(&retryTimer, SIGNAL(timeout()), this, SLOT(retryByTimer()));
|
connect(&retryTimer, SIGNAL(timeout()), this, SLOT(retryByTimer()));
|
||||||
connect(&_waitForConnectedTimer, SIGNAL(timeout()), this, SLOT(onWaitConnectedFailed()));
|
connect(&_waitForConnectedTimer, SIGNAL(timeout()), this, SLOT(onWaitConnectedFailed()));
|
||||||
|
@ -1104,8 +1113,8 @@ void ConnectionPrivate::socketStart(bool afterConfig) {
|
||||||
}
|
}
|
||||||
if (noIPv4) DEBUG_LOG(("MTP Info: DC %1 options for IPv4 over HTTP not found, waiting for config").arg(dc));
|
if (noIPv4) DEBUG_LOG(("MTP Info: DC %1 options for IPv4 over HTTP not found, waiting for config").arg(dc));
|
||||||
if (Global::TryIPv6() && noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 over HTTP not found, waiting for config").arg(dc));
|
if (Global::TryIPv6() && noIPv6) DEBUG_LOG(("MTP Info: DC %1 options for IPv6 over HTTP not found, waiting for config").arg(dc));
|
||||||
connect(configLoader(), SIGNAL(loaded()), this, SLOT(onConfigLoaded()));
|
connect(_instance, SIGNAL(configLoaded()), this, SLOT(onConfigLoaded()), Qt::UniqueConnection);
|
||||||
configLoader()->load();
|
QMetaObject::invokeMethod(_instance, "configLoadRequest", Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1635,7 +1644,7 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr
|
||||||
mtpRequestId requestId = wasSent(resendId);
|
mtpRequestId requestId = wasSent(resendId);
|
||||||
if (requestId) {
|
if (requestId) {
|
||||||
LOG(("Message Error: bad message notification received, msgId %1, error_code %2, fatal: clearing callbacks").arg(data.vbad_msg_id.v).arg(errorCode));
|
LOG(("Message Error: bad message notification received, msgId %1, error_code %2, fatal: clearing callbacks").arg(data.vbad_msg_id.v).arg(errorCode));
|
||||||
clearCallbacksDelayed(RPCCallbackClears(1, RPCCallbackClear(requestId, -errorCode)));
|
_instance->clearCallbacksDelayed(RPCCallbackClears(1, RPCCallbackClear(requestId, -errorCode)));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId));
|
DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId));
|
||||||
}
|
}
|
||||||
|
@ -2101,7 +2110,7 @@ void ConnectionPrivate::requestsAcked(const QVector<MTPlong> &ids, bool byRespon
|
||||||
mtpRequestId reqId = req.value()->requestId;
|
mtpRequestId reqId = req.value()->requestId;
|
||||||
bool moveToAcked = byResponse;
|
bool moveToAcked = byResponse;
|
||||||
if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler)
|
if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler)
|
||||||
moveToAcked = !hasCallbacks(reqId);
|
moveToAcked = !_instance->hasCallbacks(reqId);
|
||||||
}
|
}
|
||||||
if (moveToAcked) {
|
if (moveToAcked) {
|
||||||
wereAcked.insert(msgId, reqId);
|
wereAcked.insert(msgId, reqId);
|
||||||
|
@ -2119,7 +2128,7 @@ void ConnectionPrivate::requestsAcked(const QVector<MTPlong> &ids, bool byRespon
|
||||||
mtpRequestId reqId = reqIt.value();
|
mtpRequestId reqId = reqIt.value();
|
||||||
bool moveToAcked = byResponse;
|
bool moveToAcked = byResponse;
|
||||||
if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler)
|
if (!moveToAcked) { // ignore ACK, if we need a response (if we have a handler)
|
||||||
moveToAcked = !hasCallbacks(reqId);
|
moveToAcked = !_instance->hasCallbacks(reqId);
|
||||||
}
|
}
|
||||||
if (moveToAcked) {
|
if (moveToAcked) {
|
||||||
QWriteLocker locker4(sessionData->toSendMutex());
|
QWriteLocker locker4(sessionData->toSendMutex());
|
||||||
|
@ -2160,7 +2169,7 @@ void ConnectionPrivate::requestsAcked(const QVector<MTPlong> &ids, bool byRespon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clearedAcked.size()) {
|
if (clearedAcked.size()) {
|
||||||
clearCallbacksDelayed(clearedAcked);
|
_instance->clearCallbacksDelayed(clearedAcked);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toAckMore.size()) {
|
if (toAckMore.size()) {
|
||||||
|
@ -2681,8 +2690,8 @@ void ConnectionPrivate::dhClientParamsAnswered() {
|
||||||
|
|
||||||
DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2").arg(authKey->keyId()).arg(serverSalt));
|
DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2").arg(authKey->keyId()).arg(serverSalt));
|
||||||
|
|
||||||
sessionData->owner()->notifyKeyCreated(authKey); // slot will call authKeyCreated()
|
sessionData->owner()->notifyKeyCreated(std::move(authKey)); // slot will call authKeyCreated()
|
||||||
sessionData->clear();
|
sessionData->clear(_instance);
|
||||||
unlockKey();
|
unlockKey();
|
||||||
} return;
|
} return;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "core/single_timer.h"
|
#include "core/single_timer.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
|
|
||||||
|
class Instance;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
class AbstractConnection;
|
class AbstractConnection;
|
||||||
|
@ -35,24 +38,27 @@ class Thread : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Thread();
|
Thread() {
|
||||||
uint32 getThreadId() const;
|
static int ThreadCounter = 0;
|
||||||
~Thread();
|
_threadIndex = ++ThreadCounter;
|
||||||
|
}
|
||||||
|
int getThreadIndex() const {
|
||||||
|
return _threadIndex;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32 _threadId;
|
int _threadIndex = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Connection {
|
class Connection {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum ConnectionType {
|
enum ConnectionType {
|
||||||
TcpConnection,
|
TcpConnection,
|
||||||
HttpConnection
|
HttpConnection
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection();
|
Connection(Instance *instance);
|
||||||
|
|
||||||
int32 prepare(SessionData *data, int32 dc = 0); // return dc
|
int32 prepare(SessionData *data, int32 dc = 0); // return dc
|
||||||
void start();
|
void start();
|
||||||
|
@ -67,9 +73,9 @@ public:
|
||||||
QString transport() const;
|
QString transport() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Instance *_instance = nullptr;
|
||||||
QThread *thread;
|
std::unique_ptr<QThread> thread;
|
||||||
ConnectionPrivate *data;
|
ConnectionPrivate *data = nullptr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,7 +83,7 @@ class ConnectionPrivate : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConnectionPrivate(QThread *thread, Connection *owner, SessionData *data, uint32 dc);
|
ConnectionPrivate(Instance *instance, QThread *thread, Connection *owner, SessionData *data, uint32 dc);
|
||||||
~ConnectionPrivate();
|
~ConnectionPrivate();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
@ -102,10 +108,9 @@ signals:
|
||||||
void resendManyAsync(QVector<quint64> msgIds, qint64 msCanWait, bool forceContainer, bool sendMsgStateInfo);
|
void resendManyAsync(QVector<quint64> msgIds, qint64 msCanWait, bool forceContainer, bool sendMsgStateInfo);
|
||||||
void resendAllAsync();
|
void resendAllAsync();
|
||||||
|
|
||||||
void finished(Connection *connection);
|
void finished(internal::Connection *connection);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void retryByTimer();
|
void retryByTimer();
|
||||||
void restartNow();
|
void restartNow();
|
||||||
void restart(bool mayBeBadKey = false);
|
void restart(bool mayBeBadKey = false);
|
||||||
|
@ -149,7 +154,6 @@ public slots:
|
||||||
void onConfigLoaded();
|
void onConfigLoaded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void doDisconnect();
|
void doDisconnect();
|
||||||
|
|
||||||
void createConn(bool createIPv4, bool createIPv6);
|
void createConn(bool createIPv4, bool createIPv6);
|
||||||
|
@ -175,8 +179,11 @@ private:
|
||||||
void clearMessages();
|
void clearMessages();
|
||||||
|
|
||||||
bool setState(int32 state, int32 ifState = Connection::UpdateAlways);
|
bool setState(int32 state, int32 ifState = Connection::UpdateAlways);
|
||||||
|
|
||||||
|
Instance *_instance = nullptr;
|
||||||
|
|
||||||
mutable QReadWriteLock stateConnMutex;
|
mutable QReadWriteLock stateConnMutex;
|
||||||
int32 _state;
|
int32 _state = DisconnectedState;
|
||||||
|
|
||||||
bool _needSessionReset = false;
|
bool _needSessionReset = false;
|
||||||
void resetSession();
|
void resetSession();
|
||||||
|
|
|
@ -200,6 +200,7 @@ void DcOptions::constructFromSerialized(const QByteArray &serialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QDataStream stream(&buffer);
|
QDataStream stream(&buffer);
|
||||||
|
stream.setVersion(QDataStream::Qt_5_1);
|
||||||
qint32 count = 0;
|
qint32 count = 0;
|
||||||
stream >> count;
|
stream >> count;
|
||||||
if (stream.status() != QDataStream::Ok) {
|
if (stream.status() != QDataStream::Ok) {
|
||||||
|
@ -243,10 +244,6 @@ DcId DcOptions::getDefaultDcId() const {
|
||||||
auto result = sortedDcIds();
|
auto result = sortedDcIds();
|
||||||
t_assert(!result.empty());
|
t_assert(!result.empty());
|
||||||
|
|
||||||
auto main = internal::mainDC();
|
|
||||||
if (base::contains(result, main)) {
|
|
||||||
return main;
|
|
||||||
}
|
|
||||||
return result[0];
|
return result[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,82 +23,22 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "mtproto/facade.h"
|
#include "mtproto/facade.h"
|
||||||
#include "mtproto/dc_options.h"
|
#include "mtproto/dc_options.h"
|
||||||
#include "messenger.h"
|
#include "mtproto/mtp_instance.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
DcenterMap gDCs;
|
|
||||||
bool configLoadedOnce = false;
|
|
||||||
bool mainDCChanged = false;
|
|
||||||
int32 _mainDC = 2;
|
|
||||||
|
|
||||||
typedef QMap<int32, AuthKeyPtr> _KeysMapForWrite;
|
|
||||||
_KeysMapForWrite _keysMapForWrite;
|
|
||||||
QMutex _keysMapForWriteMutex;
|
|
||||||
|
|
||||||
constexpr auto kEnumerateDcTimeout = 8000; // 8 seconds timeout for help_getConfig to work (then move to other dc)
|
constexpr auto kEnumerateDcTimeout = 8000; // 8 seconds timeout for help_getConfig to work (then move to other dc)
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
DcenterMap &DCMap() {
|
Dcenter::Dcenter(Instance *instance, DcId dcId, AuthKeyPtr &&key)
|
||||||
return gDCs;
|
: _instance(instance)
|
||||||
}
|
, _id(dcId)
|
||||||
|
, _key(std::move(key)) {
|
||||||
bool configNeeded() {
|
|
||||||
return !configLoadedOnce;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 mainDC() {
|
|
||||||
return _mainDC;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
QMap<int32, mtpRequestId> logoutGuestMap; // dcWithShift to logout request id
|
|
||||||
bool logoutDone(mtpRequestId req) {
|
|
||||||
for (QMap<int32, mtpRequestId>::iterator i = logoutGuestMap.begin(); i != logoutGuestMap.end(); ++i) {
|
|
||||||
if (i.value() == req) {
|
|
||||||
MTP::killSession(i.key());
|
|
||||||
logoutGuestMap.erase(i);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void logoutOtherDCs() {
|
|
||||||
QList<int32> dcs;
|
|
||||||
{
|
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
|
||||||
dcs = _keysMapForWrite.keys();
|
|
||||||
}
|
|
||||||
for (int32 i = 0, cnt = dcs.size(); i != cnt; ++i) {
|
|
||||||
if (dcs[i] != MTP::maindc()) {
|
|
||||||
logoutGuestMap.insert(MTP::lgtDcId(dcs[i]), MTP::send(MTPauth_LogOut(), rpcDone(&logoutDone), rpcFail(&logoutDone), MTP::lgtDcId(dcs[i])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDC(int32 dc, bool firstOnly) {
|
|
||||||
if (!dc || (firstOnly && mainDCChanged)) return;
|
|
||||||
mainDCChanged = true;
|
|
||||||
if (dc != _mainDC) {
|
|
||||||
_mainDC = dc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Dcenter::Dcenter(int32 id, const AuthKeyPtr &key) : _id(id), _key(key), _connectionInited(false) {
|
|
||||||
connect(this, SIGNAL(authKeyCreated()), this, SLOT(authKeyWrite()), Qt::QueuedConnection);
|
connect(this, SIGNAL(authKeyCreated()), this, SLOT(authKeyWrite()), Qt::QueuedConnection);
|
||||||
|
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
|
||||||
if (_key) {
|
|
||||||
_keysMapForWrite[_id] = _key;
|
|
||||||
} else {
|
|
||||||
_keysMapForWrite.remove(_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dcenter::authKeyWrite() {
|
void Dcenter::authKeyWrite() {
|
||||||
|
@ -108,18 +48,13 @@ void Dcenter::authKeyWrite() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dcenter::setKey(const AuthKeyPtr &key) {
|
void Dcenter::setKey(AuthKeyPtr &&key) {
|
||||||
DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id));
|
DEBUG_LOG(("AuthKey Info: MTProtoDC::setKey(%1), emitting authKeyCreated, dc %2").arg(key ? key->keyId() : 0).arg(_id));
|
||||||
_key = key;
|
_key = std::move(key);
|
||||||
_connectionInited = false;
|
_connectionInited = false;
|
||||||
emit authKeyCreated();
|
emit authKeyCreated();
|
||||||
|
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
_instance->setKeyForWrite(_id, _key);
|
||||||
if (_key) {
|
|
||||||
_keysMapForWrite[_id] = _key;
|
|
||||||
} else {
|
|
||||||
_keysMapForWrite.remove(_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QReadWriteLock *Dcenter::keyMutex() const {
|
QReadWriteLock *Dcenter::keyMutex() const {
|
||||||
|
@ -132,99 +67,45 @@ const AuthKeyPtr &Dcenter::getKey() const {
|
||||||
|
|
||||||
void Dcenter::destroyKey() {
|
void Dcenter::destroyKey() {
|
||||||
setKey(AuthKeyPtr());
|
setKey(AuthKeyPtr());
|
||||||
|
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
|
||||||
_keysMapForWrite.remove(_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
ConfigLoader::ConfigLoader(Instance *instance, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) : _instance(instance)
|
||||||
|
, _doneHandler(onDone)
|
||||||
ConfigLoader *_configLoader = nullptr;
|
, _failHandler(onFail) {
|
||||||
auto loadingConfig = false;
|
|
||||||
|
|
||||||
void configLoaded(const MTPConfig &result) {
|
|
||||||
loadingConfig = false;
|
|
||||||
|
|
||||||
auto &data = result.c_config();
|
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: got config, chat_size_max: %1, date: %2, test_mode: %3, this_dc: %4, dc_options.length: %5").arg(data.vchat_size_max.v).arg(data.vdate.v).arg(mtpIsTrue(data.vtest_mode)).arg(data.vthis_dc.v).arg(data.vdc_options.c_vector().v.size()));
|
|
||||||
|
|
||||||
if (data.vdc_options.c_vector().v.empty()) {
|
|
||||||
LOG(("MTP Error: config with empty dc_options received!"));
|
|
||||||
} else {
|
|
||||||
Messenger::Instance().dcOptions()->setFromList(data.vdc_options);
|
|
||||||
}
|
|
||||||
|
|
||||||
Global::SetChatSizeMax(data.vchat_size_max.v);
|
|
||||||
Global::SetMegagroupSizeMax(data.vmegagroup_size_max.v);
|
|
||||||
Global::SetForwardedCountMax(data.vforwarded_count_max.v);
|
|
||||||
Global::SetOnlineUpdatePeriod(data.vonline_update_period_ms.v);
|
|
||||||
Global::SetOfflineBlurTimeout(data.voffline_blur_timeout_ms.v);
|
|
||||||
Global::SetOfflineIdleTimeout(data.voffline_idle_timeout_ms.v);
|
|
||||||
Global::SetOnlineCloudTimeout(data.vonline_cloud_timeout_ms.v);
|
|
||||||
Global::SetNotifyCloudDelay(data.vnotify_cloud_delay_ms.v);
|
|
||||||
Global::SetNotifyDefaultDelay(data.vnotify_default_delay_ms.v);
|
|
||||||
Global::SetChatBigSize(data.vchat_big_size.v); // ?
|
|
||||||
Global::SetPushChatPeriod(data.vpush_chat_period_ms.v); // ?
|
|
||||||
Global::SetPushChatLimit(data.vpush_chat_limit.v); // ?
|
|
||||||
Global::SetSavedGifsLimit(data.vsaved_gifs_limit.v);
|
|
||||||
Global::SetEditTimeLimit(data.vedit_time_limit.v); // ?
|
|
||||||
Global::SetStickersRecentLimit(data.vstickers_recent_limit.v);
|
|
||||||
Global::SetPinnedDialogsCountMax(data.vpinned_dialogs_count_max.v);
|
|
||||||
|
|
||||||
configLoadedOnce = true;
|
|
||||||
Local::writeSettings();
|
|
||||||
|
|
||||||
configLoader()->done();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool configFailed(const RPCError &error) {
|
|
||||||
if (MTP::isDefaultHandledError(error)) return false;
|
|
||||||
|
|
||||||
loadingConfig = false;
|
|
||||||
LOG(("MTP Error: failed to get config!"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
ConfigLoader::ConfigLoader() {
|
|
||||||
connect(&_enumDCTimer, SIGNAL(timeout()), this, SLOT(enumDC()));
|
connect(&_enumDCTimer, SIGNAL(timeout()), this, SLOT(enumDC()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigLoader::load() {
|
void ConfigLoader::load() {
|
||||||
if (loadingConfig) return;
|
sendRequest(_instance->mainDcId());
|
||||||
loadingConfig = true;
|
|
||||||
|
|
||||||
MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed));
|
|
||||||
|
|
||||||
_enumDCTimer.start(kEnumerateDcTimeout);
|
_enumDCTimer.start(kEnumerateDcTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigLoader::done() {
|
mtpRequestId ConfigLoader::sendRequest(ShiftedDcId shiftedDcId) {
|
||||||
|
return _instance->send(MTPhelp_GetConfig(), _doneHandler, _failHandler, shiftedDcId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigLoader::~ConfigLoader() {
|
||||||
_enumDCTimer.stop();
|
_enumDCTimer.stop();
|
||||||
if (_enumRequest) {
|
if (_enumRequest) {
|
||||||
MTP::cancel(_enumRequest);
|
_instance->cancel(_enumRequest);
|
||||||
_enumRequest = 0;
|
|
||||||
}
|
}
|
||||||
if (_enumCurrent) {
|
if (_enumCurrent) {
|
||||||
MTP::killSession(MTP::cfgDcId(_enumCurrent));
|
_instance->killSession(MTP::cfgDcId(_enumCurrent));
|
||||||
_enumCurrent = 0;
|
|
||||||
}
|
}
|
||||||
emit loaded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigLoader::enumDC() {
|
void ConfigLoader::enumDC() {
|
||||||
if (!loadingConfig) return;
|
if (_enumRequest) {
|
||||||
|
_instance->cancel(_enumRequest);
|
||||||
if (_enumRequest) MTP::cancel(_enumRequest);
|
}
|
||||||
|
|
||||||
if (!_enumCurrent) {
|
if (!_enumCurrent) {
|
||||||
_enumCurrent = _mainDC;
|
_enumCurrent = _instance->mainDcId();
|
||||||
} else {
|
} else {
|
||||||
MTP::killSession(MTP::cfgDcId(_enumCurrent));
|
_instance->killSession(MTP::cfgDcId(_enumCurrent));
|
||||||
}
|
}
|
||||||
auto ids = Messenger::Instance().dcOptions()->sortedDcIds();
|
auto ids = _instance->dcOptions()->sortedDcIds();
|
||||||
t_assert(!ids.empty());
|
t_assert(!ids.empty());
|
||||||
|
|
||||||
auto i = std::find(ids.cbegin(), ids.cend(), _enumCurrent);
|
auto i = std::find(ids.cbegin(), ids.cend(), _enumCurrent);
|
||||||
|
@ -233,34 +114,10 @@ void ConfigLoader::enumDC() {
|
||||||
} else {
|
} else {
|
||||||
_enumCurrent = *i;
|
_enumCurrent = *i;
|
||||||
}
|
}
|
||||||
_enumRequest = MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed), MTP::cfgDcId(_enumCurrent));
|
_enumRequest = sendRequest(MTP::cfgDcId(_enumCurrent));
|
||||||
|
|
||||||
_enumDCTimer.start(kEnumerateDcTimeout);
|
_enumDCTimer.start(kEnumerateDcTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigLoader *configLoader() {
|
|
||||||
if (!_configLoader) _configLoader = new ConfigLoader();
|
|
||||||
return _configLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroyConfigLoader() {
|
|
||||||
delete _configLoader;
|
|
||||||
_configLoader = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthKeysMap getAuthKeys() {
|
|
||||||
AuthKeysMap result;
|
|
||||||
QMutexLocker lock(&_keysMapForWriteMutex);
|
|
||||||
for_const (const AuthKeyPtr &key, _keysMapForWrite) {
|
|
||||||
result.push_back(key);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAuthKey(int32 dcId, AuthKeyPtr key) {
|
|
||||||
DcenterPtr dc(new Dcenter(dcId, key));
|
|
||||||
gDCs.insert(dcId, dc);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace MTP
|
} // namespace MTP
|
||||||
|
|
|
@ -21,19 +21,24 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/single_timer.h"
|
#include "core/single_timer.h"
|
||||||
|
#include "mtproto/rpc_sender.h"
|
||||||
|
#include "mtproto/auth_key.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
|
|
||||||
|
class Instance;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
class Dcenter : public QObject {
|
class Dcenter : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Dcenter(int32 id, const AuthKeyPtr &key);
|
Dcenter(Instance *instance, DcId dcId, AuthKeyPtr &&key);
|
||||||
|
|
||||||
QReadWriteLock *keyMutex() const;
|
QReadWriteLock *keyMutex() const;
|
||||||
const AuthKeyPtr &getKey() const;
|
const AuthKeyPtr &getKey() const;
|
||||||
void setKey(const AuthKeyPtr &key);
|
void setKey(AuthKeyPtr &&key);
|
||||||
void destroyKey();
|
void destroyKey();
|
||||||
|
|
||||||
bool connectionInited() const {
|
bool connectionInited() const {
|
||||||
|
@ -56,47 +61,40 @@ private slots:
|
||||||
private:
|
private:
|
||||||
mutable QReadWriteLock keyLock;
|
mutable QReadWriteLock keyLock;
|
||||||
mutable QMutex initLock;
|
mutable QMutex initLock;
|
||||||
int32 _id;
|
Instance *_instance = nullptr;
|
||||||
|
DcId _id = 0;
|
||||||
AuthKeyPtr _key;
|
AuthKeyPtr _key;
|
||||||
bool _connectionInited;
|
bool _connectionInited = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QSharedPointer<Dcenter> DcenterPtr;
|
using DcenterPtr = std::shared_ptr<Dcenter>;
|
||||||
typedef QMap<uint32, DcenterPtr> DcenterMap;
|
using DcenterMap = std::map<DcId, DcenterPtr>;
|
||||||
|
|
||||||
class ConfigLoader : public QObject {
|
class ConfigLoader : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConfigLoader();
|
ConfigLoader(Instance *instance, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail);
|
||||||
|
~ConfigLoader();
|
||||||
|
|
||||||
void load();
|
void load();
|
||||||
void done();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void enumDC();
|
void enumDC();
|
||||||
|
|
||||||
signals:
|
|
||||||
void loaded();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
mtpRequestId sendRequest(ShiftedDcId shiftedDcId);
|
||||||
|
|
||||||
|
Instance *_instance = nullptr;
|
||||||
SingleTimer _enumDCTimer;
|
SingleTimer _enumDCTimer;
|
||||||
DcId _enumCurrent = 0;
|
DcId _enumCurrent = 0;
|
||||||
mtpRequestId _enumRequest = 0;
|
mtpRequestId _enumRequest = 0;
|
||||||
|
|
||||||
|
RPCDoneHandlerPtr _doneHandler;
|
||||||
|
RPCFailHandlerPtr _failHandler;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigLoader *configLoader();
|
|
||||||
void destroyConfigLoader();
|
|
||||||
|
|
||||||
DcenterMap &DCMap();
|
|
||||||
bool configNeeded();
|
|
||||||
int32 mainDC();
|
|
||||||
void logoutOtherDCs();
|
|
||||||
void setDC(int32 dc, bool firstOnly = false);
|
|
||||||
|
|
||||||
AuthKeysMap getAuthKeys();
|
|
||||||
void setAuthKey(int32 dc, AuthKeyPtr key);
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace MTP
|
} // namespace MTP
|
||||||
|
|
|
@ -22,366 +22,16 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mtproto/facade.h"
|
#include "mtproto/facade.h"
|
||||||
|
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "auth_session.h"
|
#include "messenger.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
|
namespace internal {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef QMap<int32, internal::Session*> Sessions;
|
|
||||||
Sessions sessions;
|
|
||||||
internal::Session *mainSession;
|
|
||||||
|
|
||||||
typedef QMap<mtpRequestId, int32> RequestsByDC; // holds dcWithShift for request to this dc or -dc for request to main dc
|
|
||||||
RequestsByDC requestsByDC;
|
|
||||||
QMutex requestByDCLock;
|
|
||||||
|
|
||||||
typedef QMap<mtpRequestId, int32> AuthExportRequests; // holds target dcWithShift for auth export request
|
|
||||||
AuthExportRequests authExportRequests;
|
|
||||||
|
|
||||||
bool _started = false;
|
|
||||||
|
|
||||||
uint32 layer;
|
|
||||||
|
|
||||||
typedef QMap<mtpRequestId, RPCResponseHandler> ParserMap;
|
|
||||||
ParserMap parserMap;
|
|
||||||
QMutex parserMapLock;
|
|
||||||
|
|
||||||
typedef QMap<mtpRequestId, mtpRequest> RequestMap;
|
|
||||||
RequestMap requestMap;
|
|
||||||
QReadWriteLock requestMapLock;
|
|
||||||
|
|
||||||
typedef QPair<mtpRequestId, TimeMs> DelayedRequest;
|
|
||||||
typedef QList<DelayedRequest> DelayedRequestsList;
|
|
||||||
DelayedRequestsList delayedRequests;
|
|
||||||
|
|
||||||
typedef QMap<mtpRequestId, int32> RequestsDelays;
|
|
||||||
RequestsDelays requestsDelays;
|
|
||||||
|
|
||||||
typedef QSet<mtpRequestId> BadGuestDCRequests;
|
|
||||||
BadGuestDCRequests badGuestDCRequests;
|
|
||||||
|
|
||||||
typedef QVector<mtpRequestId> DCAuthWaiters;
|
|
||||||
typedef QMap<int32, DCAuthWaiters> AuthWaiters; // holds request ids waiting for auth import to specific dc
|
|
||||||
AuthWaiters authWaiters;
|
|
||||||
|
|
||||||
typedef OrderedSet<internal::Connection*> MTPQuittingConnections;
|
|
||||||
MTPQuittingConnections quittingConnections;
|
|
||||||
|
|
||||||
QMutex toClearLock;
|
|
||||||
RPCCallbackClears toClear;
|
|
||||||
|
|
||||||
RPCResponseHandler globalHandler;
|
|
||||||
MTPStateChangedHandler stateChangedHandler = 0;
|
|
||||||
MTPSessionResetHandler sessionResetHandler = 0;
|
|
||||||
internal::GlobalSlotCarrier *_globalSlotCarrier = 0;
|
|
||||||
|
|
||||||
bool hasAuthorization() {
|
|
||||||
return (AuthSession::Current() != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void importDone(const MTPauth_Authorization &result, mtpRequestId req) {
|
|
||||||
QMutexLocker locker1(&requestByDCLock);
|
|
||||||
|
|
||||||
RequestsByDC::iterator i = requestsByDC.find(req);
|
|
||||||
if (i == requestsByDC.end()) {
|
|
||||||
LOG(("MTP Error: auth import request not found in requestsByDC, requestId: %1").arg(req));
|
|
||||||
RPCError error(internal::rpcClientError("AUTH_IMPORT_FAIL", QString("did not find import request in requestsByDC, request %1").arg(req)));
|
|
||||||
if (globalHandler.onFail && hasAuthorization()) (*globalHandler.onFail)(req, error); // auth failed in main dc
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DcId newdc = bareDcId(i.value());
|
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: auth import to dc %1 succeeded").arg(newdc));
|
|
||||||
|
|
||||||
DCAuthWaiters &waiters(authWaiters[newdc]);
|
|
||||||
if (waiters.size()) {
|
|
||||||
QReadLocker locker(&requestMapLock);
|
|
||||||
for (DCAuthWaiters::iterator i = waiters.begin(), e = waiters.end(); i != e; ++i) {
|
|
||||||
mtpRequestId requestId = *i;
|
|
||||||
RequestMap::const_iterator j = requestMap.constFind(requestId);
|
|
||||||
if (j == requestMap.cend()) {
|
|
||||||
LOG(("MTP Error: could not find request %1 for resending").arg(requestId));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ShiftedDcId dcWithShift = newdc;
|
|
||||||
{
|
|
||||||
RequestsByDC::iterator k = requestsByDC.find(requestId);
|
|
||||||
if (k == requestsByDC.cend()) {
|
|
||||||
LOG(("MTP Error: could not find request %1 by dc for resending").arg(requestId));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (k.value() < 0) {
|
|
||||||
setdc(newdc);
|
|
||||||
k.value() = -newdc;
|
|
||||||
} else {
|
|
||||||
dcWithShift = shiftDcId(newdc, getDcIdShift(k.value()));
|
|
||||||
k.value() = dcWithShift;
|
|
||||||
}
|
|
||||||
DEBUG_LOG(("MTP Info: resending request %1 to dc %2 after import auth").arg(requestId).arg(k.value()));
|
|
||||||
}
|
|
||||||
if (internal::Session *session = internal::getSession(dcWithShift)) {
|
|
||||||
session->sendPrepared(j.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
waiters.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool importFail(const RPCError &error, mtpRequestId req) {
|
|
||||||
if (isDefaultHandledError(error)) return false;
|
|
||||||
|
|
||||||
if (globalHandler.onFail && hasAuthorization()) (*globalHandler.onFail)(req, error); // auth import failed
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void exportDone(const MTPauth_ExportedAuthorization &result, mtpRequestId req) {
|
|
||||||
AuthExportRequests::const_iterator i = authExportRequests.constFind(req);
|
|
||||||
if (i == authExportRequests.cend()) {
|
|
||||||
LOG(("MTP Error: auth export request target dcWithShift not found, requestId: %1").arg(req));
|
|
||||||
RPCError error(internal::rpcClientError("AUTH_IMPORT_FAIL", QString("did not find target dcWithShift, request %1").arg(req)));
|
|
||||||
if (globalHandler.onFail && hasAuthorization()) (*globalHandler.onFail)(req, error); // auth failed in main dc
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto &data(result.c_auth_exportedAuthorization());
|
|
||||||
send(MTPauth_ImportAuthorization(data.vid, data.vbytes), rpcDone(importDone), rpcFail(importFail), i.value());
|
|
||||||
authExportRequests.remove(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool exportFail(const RPCError &error, mtpRequestId req) {
|
|
||||||
if (isDefaultHandledError(error)) return false;
|
|
||||||
|
|
||||||
AuthExportRequests::const_iterator i = authExportRequests.constFind(req);
|
|
||||||
if (i != authExportRequests.cend()) {
|
|
||||||
authWaiters[bareDcId(i.value())].clear();
|
|
||||||
}
|
|
||||||
if (globalHandler.onFail && hasAuthorization()) (*globalHandler.onFail)(req, error); // auth failed in main dc
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool onErrorDefault(mtpRequestId requestId, const RPCError &error) {
|
|
||||||
const QString &err(error.type());
|
|
||||||
int32 code = error.code();
|
|
||||||
if (!isFloodError(error) && err != qstr("AUTH_KEY_UNREGISTERED")) {
|
|
||||||
int breakpoint = 0;
|
|
||||||
}
|
|
||||||
bool badGuestDC = (code == 400) && (err == qsl("FILE_ID_INVALID"));
|
|
||||||
QRegularExpressionMatch m;
|
|
||||||
if ((m = QRegularExpression("^(FILE|PHONE|NETWORK|USER)_MIGRATE_(\\d+)$").match(err)).hasMatch()) {
|
|
||||||
if (!requestId) return false;
|
|
||||||
|
|
||||||
ShiftedDcId dcWithShift = 0, newdcWithShift = m.captured(2).toInt();
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
|
||||||
if (i == requestsByDC.end()) {
|
|
||||||
LOG(("MTP Error: could not find request %1 for migrating to %2").arg(requestId).arg(newdcWithShift));
|
|
||||||
} else {
|
|
||||||
dcWithShift = i.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!dcWithShift || !newdcWithShift) return false;
|
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: changing request %1 from dcWithShift%2 to dc%3").arg(requestId).arg(dcWithShift).arg(newdcWithShift));
|
|
||||||
if (dcWithShift < 0) { // newdc shift = 0
|
|
||||||
if (false && hasAuthorization() && !authExportRequests.contains(requestId)) { // migrate not supported at this moment
|
|
||||||
DEBUG_LOG(("MTP Info: importing auth to dc %1").arg(newdcWithShift));
|
|
||||||
DCAuthWaiters &waiters(authWaiters[newdcWithShift]);
|
|
||||||
if (!waiters.size()) {
|
|
||||||
authExportRequests.insert(send(MTPauth_ExportAuthorization(MTP_int(newdcWithShift)), rpcDone(exportDone), rpcFail(exportFail)), newdcWithShift);
|
|
||||||
}
|
|
||||||
waiters.push_back(requestId);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
MTP::setdc(newdcWithShift);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newdcWithShift = shiftDcId(newdcWithShift, getDcIdShift(dcWithShift));
|
|
||||||
}
|
|
||||||
|
|
||||||
mtpRequest req;
|
|
||||||
{
|
|
||||||
QReadLocker locker(&requestMapLock);
|
|
||||||
RequestMap::const_iterator i = requestMap.constFind(requestId);
|
|
||||||
if (i == requestMap.cend()) {
|
|
||||||
LOG(("MTP Error: could not find request %1").arg(requestId));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
req = i.value();
|
|
||||||
}
|
|
||||||
if (auto session = internal::getSession(newdcWithShift)) {
|
|
||||||
internal::registerRequest(requestId, (dcWithShift < 0) ? -newdcWithShift : newdcWithShift);
|
|
||||||
session->sendPrepared(req);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if (code < 0 || code >= 500 || (m = QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err)).hasMatch()) {
|
|
||||||
if (!requestId) return false;
|
|
||||||
|
|
||||||
int32 secs = 1;
|
|
||||||
if (code < 0 || code >= 500) {
|
|
||||||
RequestsDelays::iterator i = requestsDelays.find(requestId);
|
|
||||||
if (i != requestsDelays.cend()) {
|
|
||||||
secs = (i.value() > 60) ? i.value() : (i.value() *= 2);
|
|
||||||
} else {
|
|
||||||
requestsDelays.insert(requestId, secs);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
secs = m.captured(1).toInt();
|
|
||||||
// if (secs >= 60) return false;
|
|
||||||
}
|
|
||||||
auto sendAt = getms(true) + secs * 1000 + 10;
|
|
||||||
DelayedRequestsList::iterator i = delayedRequests.begin(), e = delayedRequests.end();
|
|
||||||
for (; i != e; ++i) {
|
|
||||||
if (i->first == requestId) return true;
|
|
||||||
if (i->second > sendAt) break;
|
|
||||||
}
|
|
||||||
delayedRequests.insert(i, DelayedRequest(requestId, sendAt));
|
|
||||||
|
|
||||||
if (_globalSlotCarrier) _globalSlotCarrier->checkDelayed();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else if (code == 401 || (badGuestDC && badGuestDCRequests.constFind(requestId) == badGuestDCRequests.cend())) {
|
|
||||||
int32 dcWithShift = 0;
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
|
||||||
if (i != requestsByDC.end()) {
|
|
||||||
dcWithShift = i.value();
|
|
||||||
} else {
|
|
||||||
LOG(("MTP Error: unauthorized request without dc info, requestId %1").arg(requestId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int32 newdc = bareDcId(qAbs(dcWithShift));
|
|
||||||
if (!newdc || newdc == internal::mainDC() || !hasAuthorization()) {
|
|
||||||
if (!badGuestDC && globalHandler.onFail) (*globalHandler.onFail)(requestId, error); // auth failed in main dc
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_LOG(("MTP Info: importing auth to dcWithShift %1").arg(dcWithShift));
|
|
||||||
DCAuthWaiters &waiters(authWaiters[newdc]);
|
|
||||||
if (!waiters.size()) {
|
|
||||||
authExportRequests.insert(send(MTPauth_ExportAuthorization(MTP_int(newdc)), rpcDone(exportDone), rpcFail(exportFail)), abs(dcWithShift));
|
|
||||||
}
|
|
||||||
waiters.push_back(requestId);
|
|
||||||
if (badGuestDC) badGuestDCRequests.insert(requestId);
|
|
||||||
return true;
|
|
||||||
} else if (err == qstr("CONNECTION_NOT_INITED") || err == qstr("CONNECTION_LAYER_INVALID")) {
|
|
||||||
mtpRequest req;
|
|
||||||
{
|
|
||||||
QReadLocker locker(&requestMapLock);
|
|
||||||
RequestMap::const_iterator i = requestMap.constFind(requestId);
|
|
||||||
if (i == requestMap.cend()) {
|
|
||||||
LOG(("MTP Error: could not find request %1").arg(requestId));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
req = i.value();
|
|
||||||
}
|
|
||||||
int32 dcWithShift = 0;
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
|
||||||
if (i == requestsByDC.end()) {
|
|
||||||
LOG(("MTP Error: could not find request %1 for resending with init connection").arg(requestId));
|
|
||||||
} else {
|
|
||||||
dcWithShift = i.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!dcWithShift) return false;
|
|
||||||
|
|
||||||
if (internal::Session *session = internal::getSession(qAbs(dcWithShift))) {
|
|
||||||
req->needsLayer = true;
|
|
||||||
session->sendPrepared(req);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if (err == qstr("MSG_WAIT_FAILED")) {
|
|
||||||
mtpRequest req;
|
|
||||||
{
|
|
||||||
QReadLocker locker(&requestMapLock);
|
|
||||||
RequestMap::const_iterator i = requestMap.constFind(requestId);
|
|
||||||
if (i == requestMap.cend()) {
|
|
||||||
LOG(("MTP Error: could not find request %1").arg(requestId));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
req = i.value();
|
|
||||||
}
|
|
||||||
if (!req->after) {
|
|
||||||
LOG(("MTP Error: wait failed for not dependent request %1").arg(requestId));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int32 dcWithShift = 0;
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
RequestsByDC::iterator i = requestsByDC.find(requestId), j = requestsByDC.find(req->after->requestId);
|
|
||||||
if (i == requestsByDC.end()) {
|
|
||||||
LOG(("MTP Error: could not find request %1 by dc").arg(requestId));
|
|
||||||
} else if (j == requestsByDC.end()) {
|
|
||||||
LOG(("MTP Error: could not find dependent request %1 by dc").arg(req->after->requestId));
|
|
||||||
} else {
|
|
||||||
dcWithShift = i.value();
|
|
||||||
if (i.value() != j.value()) {
|
|
||||||
req->after = mtpRequest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!dcWithShift) return false;
|
|
||||||
|
|
||||||
if (!req->after) {
|
|
||||||
if (internal::Session *session = internal::getSession(qAbs(dcWithShift))) {
|
|
||||||
req->needsLayer = true;
|
|
||||||
session->sendPrepared(req);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int32 newdc = bareDcId(qAbs(dcWithShift));
|
|
||||||
DCAuthWaiters &waiters(authWaiters[newdc]);
|
|
||||||
if (waiters.indexOf(req->after->requestId) >= 0) {
|
|
||||||
if (waiters.indexOf(requestId) < 0) {
|
|
||||||
waiters.push_back(requestId);
|
|
||||||
}
|
|
||||||
if (badGuestDCRequests.constFind(req->after->requestId) != badGuestDCRequests.cend()) {
|
|
||||||
if (badGuestDCRequests.constFind(requestId) == badGuestDCRequests.cend()) {
|
|
||||||
badGuestDCRequests.insert(requestId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DelayedRequestsList::iterator i = delayedRequests.begin(), e = delayedRequests.end();
|
|
||||||
for (; i != e; ++i) {
|
|
||||||
if (i->first == requestId) return true;
|
|
||||||
if (i->first == req->after->requestId) break;
|
|
||||||
}
|
|
||||||
if (i != e) {
|
|
||||||
delayedRequests.insert(i, DelayedRequest(requestId, i->second));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_globalSlotCarrier) _globalSlotCarrier->checkDelayed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (badGuestDC) badGuestDCRequests.remove(requestId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PauseLevel = 0;
|
int PauseLevel = 0;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
Session *getSession(ShiftedDcId shiftedDcId) {
|
|
||||||
if (!_started) return nullptr;
|
|
||||||
if (!shiftedDcId) return mainSession;
|
|
||||||
if (!bareDcId(shiftedDcId)) {
|
|
||||||
shiftedDcId += bareDcId(mainSession->getDcWithShift());
|
|
||||||
}
|
|
||||||
|
|
||||||
Sessions::const_iterator i = sessions.constFind(shiftedDcId);
|
|
||||||
if (i == sessions.cend()) {
|
|
||||||
i = sessions.insert(shiftedDcId, new Session(shiftedDcId));
|
|
||||||
}
|
|
||||||
return i.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool paused() {
|
bool paused() {
|
||||||
return PauseLevel > 0;
|
return PauseLevel > 0;
|
||||||
}
|
}
|
||||||
|
@ -392,504 +42,17 @@ void pause() {
|
||||||
|
|
||||||
void unpause() {
|
void unpause() {
|
||||||
--PauseLevel;
|
--PauseLevel;
|
||||||
if (_started) {
|
if (!PauseLevel) {
|
||||||
for_const (auto session, sessions) {
|
if (auto instance = MainInstance()) {
|
||||||
session->unpaused();
|
instance->unpaused();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerRequest(mtpRequestId requestId, int32 dcWithShift) {
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
requestsByDC.insert(requestId, dcWithShift);
|
|
||||||
}
|
|
||||||
internal::performDelayedClear(); // need to do it somewhere...
|
|
||||||
}
|
|
||||||
|
|
||||||
void unregisterRequest(mtpRequestId requestId) {
|
|
||||||
requestsDelays.remove(requestId);
|
|
||||||
|
|
||||||
{
|
|
||||||
QWriteLocker locker(&requestMapLock);
|
|
||||||
requestMap.remove(requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
requestsByDC.remove(requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser) {
|
|
||||||
mtpRequestId res = reqid();
|
|
||||||
request->requestId = res;
|
|
||||||
if (parser.onDone || parser.onFail) {
|
|
||||||
QMutexLocker locker(&parserMapLock);
|
|
||||||
parserMap.insert(res, parser);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
QWriteLocker locker(&requestMapLock);
|
|
||||||
requestMap.insert(res, request);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
mtpRequest getRequest(mtpRequestId reqId) {
|
|
||||||
static mtpRequest zero;
|
|
||||||
mtpRequest req;
|
|
||||||
{
|
|
||||||
QReadLocker locker(&requestMapLock);
|
|
||||||
RequestMap::const_iterator i = requestMap.constFind(reqId);
|
|
||||||
req = (i == requestMap.cend()) ? zero : i.value();
|
|
||||||
}
|
|
||||||
return req;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest) {
|
|
||||||
mtpMsgId afterId(*(mtpMsgId*)(from->after->data() + 4));
|
|
||||||
mtpRequestMap::const_iterator i = afterId ? haveSent.constFind(afterId) : haveSent.cend();
|
|
||||||
int32 size = to->size(), lenInInts = (from.innerLength() >> 2), headlen = 4, fulllen = headlen + lenInInts;
|
|
||||||
if (i == haveSent.constEnd()) { // no invoke after or such msg was not sent or was completed recently
|
|
||||||
to->resize(size + fulllen + skipBeforeRequest);
|
|
||||||
if (skipBeforeRequest) {
|
|
||||||
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
|
|
||||||
memcpy(to->data() + size + headlen + skipBeforeRequest, from->constData() + 4 + headlen, lenInInts * sizeof(mtpPrime));
|
|
||||||
} else {
|
|
||||||
memcpy(to->data() + size, from->constData() + 4, fulllen * sizeof(mtpPrime));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
to->resize(size + fulllen + skipBeforeRequest + 3);
|
|
||||||
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
|
|
||||||
(*to)[size + 3] += 3 * sizeof(mtpPrime);
|
|
||||||
*((mtpTypeId*)&((*to)[size + headlen + skipBeforeRequest])) = mtpc_invokeAfterMsg;
|
|
||||||
memcpy(to->data() + size + headlen + skipBeforeRequest + 1, &afterId, 2 * sizeof(mtpPrime));
|
|
||||||
memcpy(to->data() + size + headlen + skipBeforeRequest + 3, from->constData() + 4 + headlen, lenInInts * sizeof(mtpPrime));
|
|
||||||
if (size + 3 != 7) (*to)[7] += 3 * sizeof(mtpPrime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearCallbacks(mtpRequestId requestId, int32 errorCode) {
|
|
||||||
RPCResponseHandler h;
|
|
||||||
bool found = false;
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&parserMapLock);
|
|
||||||
ParserMap::iterator i = parserMap.find(requestId);
|
|
||||||
if (i != parserMap.end()) {
|
|
||||||
h = i.value();
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
parserMap.erase(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (errorCode && found) {
|
|
||||||
rpcErrorOccured(requestId, h, rpcClientError("CLEAR_CALLBACK", QString("did not handle request %1, error code %2").arg(requestId).arg(errorCode)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearCallbacksDelayed(const RPCCallbackClears &requestIds) {
|
|
||||||
uint32 idsCount = requestIds.size();
|
|
||||||
if (!idsCount) return;
|
|
||||||
|
|
||||||
if (cDebug()) {
|
|
||||||
QString idsStr = QString("%1").arg(requestIds[0].requestId);
|
|
||||||
for (uint32 i = 1; i < idsCount; ++i) {
|
|
||||||
idsStr += QString(", %1").arg(requestIds[i].requestId);
|
|
||||||
}
|
|
||||||
DEBUG_LOG(("RPC Info: clear callbacks delayed, msgIds: %1").arg(idsStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
QMutexLocker lock(&toClearLock);
|
|
||||||
uint32 toClearNow = toClear.size();
|
|
||||||
if (toClearNow) {
|
|
||||||
toClear.resize(toClearNow + idsCount);
|
|
||||||
memcpy(toClear.data() + toClearNow, requestIds.constData(), idsCount * sizeof(RPCCallbackClear));
|
|
||||||
} else {
|
|
||||||
toClear = requestIds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void performDelayedClear() {
|
|
||||||
QMutexLocker lock(&toClearLock);
|
|
||||||
if (!toClear.isEmpty()) {
|
|
||||||
for (RPCCallbackClears::iterator i = toClear.begin(), e = toClear.end(); i != e; ++i) {
|
|
||||||
if (cDebug()) {
|
|
||||||
QMutexLocker locker(&parserMapLock);
|
|
||||||
if (parserMap.find(i->requestId) != parserMap.end()) {
|
|
||||||
DEBUG_LOG(("RPC Info: clearing delayed callback %1, error code %2").arg(i->requestId).arg(i->errorCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clearCallbacks(i->requestId, i->errorCode);
|
|
||||||
internal::unregisterRequest(i->requestId);
|
|
||||||
}
|
|
||||||
toClear.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end) {
|
|
||||||
RPCResponseHandler h;
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&parserMapLock);
|
|
||||||
ParserMap::iterator i = parserMap.find(requestId);
|
|
||||||
if (i != parserMap.cend()) {
|
|
||||||
h = i.value();
|
|
||||||
parserMap.erase(i);
|
|
||||||
|
|
||||||
DEBUG_LOG(("RPC Info: found parser for request %1, trying to parse response...").arg(requestId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (h.onDone || h.onFail) {
|
|
||||||
try {
|
|
||||||
if (from >= end) throw mtpErrorInsufficient();
|
|
||||||
|
|
||||||
if (*from == mtpc_rpc_error) {
|
|
||||||
RPCError err(MTPRpcError(from, end));
|
|
||||||
DEBUG_LOG(("RPC Info: error received, code %1, type %2, description: %3").arg(err.code()).arg(err.type()).arg(err.description()));
|
|
||||||
if (!rpcErrorOccured(requestId, h, err)) {
|
|
||||||
QMutexLocker locker(&parserMapLock);
|
|
||||||
parserMap.insert(requestId, h);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (h.onDone) {
|
|
||||||
// t_assert(App::app() != 0);
|
|
||||||
(*h.onDone)(requestId, from, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception &e) {
|
|
||||||
if (!rpcErrorOccured(requestId, h, rpcClientError("RESPONSE_PARSE_FAILED", QString("exception text: ") + e.what()))) {
|
|
||||||
QMutexLocker locker(&parserMapLock);
|
|
||||||
parserMap.insert(requestId, h);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUG_LOG(("RPC Info: parser not found for %1").arg(requestId));
|
|
||||||
}
|
|
||||||
unregisterRequest(requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasCallbacks(mtpRequestId requestId) {
|
|
||||||
QMutexLocker locker(&parserMapLock);
|
|
||||||
ParserMap::iterator i = parserMap.find(requestId);
|
|
||||||
return (i != parserMap.cend());
|
|
||||||
}
|
|
||||||
|
|
||||||
void globalCallback(const mtpPrime *from, const mtpPrime *end) {
|
|
||||||
if (globalHandler.onDone) (*globalHandler.onDone)(0, from, end); // some updates were received
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStateChange(int32 dcWithShift, int32 state) {
|
|
||||||
if (stateChangedHandler) stateChangedHandler(dcWithShift, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onSessionReset(int32 dcWithShift) {
|
|
||||||
if (sessionResetHandler) sessionResetHandler(dcWithShift);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err) { // return true if need to clean request data
|
|
||||||
if (isDefaultHandledError(err)) {
|
|
||||||
if (onFail && (*onFail)(requestId, err)) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onErrorDefault(requestId, err)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LOG(("RPC Error: request %1 got fail with code %2, error %3%4").arg(requestId).arg(err.code()).arg(err.type()).arg(err.description().isEmpty() ? QString() : QString(": %1").arg(err.description())));
|
|
||||||
onFail && (*onFail)(requestId, err);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalSlotCarrier::GlobalSlotCarrier() {
|
|
||||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(checkDelayed()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalSlotCarrier::checkDelayed() {
|
|
||||||
auto now = getms(true);
|
|
||||||
while (!delayedRequests.isEmpty() && now >= delayedRequests.front().second) {
|
|
||||||
mtpRequestId requestId = delayedRequests.front().first;
|
|
||||||
delayedRequests.pop_front();
|
|
||||||
|
|
||||||
int32 dcWithShift = 0;
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
RequestsByDC::const_iterator i = requestsByDC.constFind(requestId);
|
|
||||||
if (i != requestsByDC.cend()) {
|
|
||||||
dcWithShift = i.value();
|
|
||||||
} else {
|
|
||||||
LOG(("MTP Error: could not find request dc for delayed resend, requestId %1").arg(requestId));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mtpRequest req;
|
|
||||||
{
|
|
||||||
QReadLocker locker(&requestMapLock);
|
|
||||||
RequestMap::const_iterator j = requestMap.constFind(requestId);
|
|
||||||
if (j == requestMap.cend()) {
|
|
||||||
DEBUG_LOG(("MTP Error: could not find request %1").arg(requestId));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
req = j.value();
|
|
||||||
}
|
|
||||||
if (Session *session = getSession(qAbs(dcWithShift))) {
|
|
||||||
session->sendPrepared(req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!delayedRequests.isEmpty()) {
|
|
||||||
_timer.start(delayedRequests.front().second - now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalSlotCarrier::connectionFinished(Connection *connection) {
|
|
||||||
MTPQuittingConnections::iterator i = quittingConnections.find(connection);
|
|
||||||
if (i != quittingConnections.cend()) {
|
|
||||||
quittingConnections.erase(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
connection->waitTillFinish();
|
|
||||||
delete connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalSlotCarrier *globalSlotCarrier() {
|
|
||||||
return _globalSlotCarrier;
|
|
||||||
}
|
|
||||||
|
|
||||||
void queueQuittingConnection(Connection *connection) {
|
|
||||||
quittingConnections.insert(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
void start() {
|
Instance *MainInstance() {
|
||||||
if (started()) return;
|
return Messenger::Instance().mtp();
|
||||||
|
|
||||||
unixtimeInit();
|
|
||||||
|
|
||||||
internal::DcenterMap &dcs(internal::DCMap());
|
|
||||||
|
|
||||||
_globalSlotCarrier = new internal::GlobalSlotCarrier();
|
|
||||||
|
|
||||||
mainSession = new internal::Session(internal::mainDC());
|
|
||||||
sessions.insert(mainSession->getDcWithShift(), mainSession);
|
|
||||||
|
|
||||||
_started = true;
|
|
||||||
|
|
||||||
if (internal::configNeeded()) {
|
|
||||||
internal::configLoader()->load();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool started() {
|
|
||||||
return _started;
|
|
||||||
}
|
|
||||||
|
|
||||||
void restart() {
|
|
||||||
if (!_started) return;
|
|
||||||
|
|
||||||
for (auto i = sessions.cbegin(), e = sessions.cend(); i != e; ++i) {
|
|
||||||
i.value()->restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void restart(int32 dcMask) {
|
|
||||||
if (!_started) return;
|
|
||||||
|
|
||||||
dcMask = bareDcId(dcMask);
|
|
||||||
for (Sessions::const_iterator i = sessions.cbegin(), e = sessions.cend(); i != e; ++i) {
|
|
||||||
if (bareDcId(i.value()->getDcWithShift()) == dcMask) {
|
|
||||||
i.value()->restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure(int32 dc) {
|
|
||||||
if (_started) return;
|
|
||||||
internal::setDC(dc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setdc(int32 dc, bool fromZeroOnly) {
|
|
||||||
if (!dc || !_started) return;
|
|
||||||
internal::setDC(dc, fromZeroOnly);
|
|
||||||
int32 oldMainDc = mainSession->getDcWithShift();
|
|
||||||
if (maindc() != oldMainDc) {
|
|
||||||
killSession(oldMainDc);
|
|
||||||
}
|
|
||||||
Local::writeMtpData();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 maindc() {
|
|
||||||
return internal::mainDC();
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 dcstate(int32 dc) {
|
|
||||||
if (!_started) return 0;
|
|
||||||
|
|
||||||
if (!dc) return mainSession->getState();
|
|
||||||
if (!bareDcId(dc)) {
|
|
||||||
dc += bareDcId(mainSession->getDcWithShift());
|
|
||||||
}
|
|
||||||
|
|
||||||
Sessions::const_iterator i = sessions.constFind(dc);
|
|
||||||
if (i != sessions.cend()) return i.value()->getState();
|
|
||||||
|
|
||||||
return DisconnectedState;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString dctransport(int32 dc) {
|
|
||||||
if (!_started) return QString();
|
|
||||||
|
|
||||||
if (!dc) return mainSession->transport();
|
|
||||||
if (!bareDcId(dc)) {
|
|
||||||
dc += bareDcId(mainSession->getDcWithShift());
|
|
||||||
}
|
|
||||||
|
|
||||||
Sessions::const_iterator i = sessions.constFind(dc);
|
|
||||||
if (i != sessions.cend()) return i.value()->transport();
|
|
||||||
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ping() {
|
|
||||||
if (internal::Session *session = internal::getSession(0)) {
|
|
||||||
session->ping();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cancel(mtpRequestId requestId) {
|
|
||||||
if (!_started || !requestId) return;
|
|
||||||
|
|
||||||
mtpMsgId msgId = 0;
|
|
||||||
requestsDelays.remove(requestId);
|
|
||||||
{
|
|
||||||
QWriteLocker locker(&requestMapLock);
|
|
||||||
RequestMap::iterator i = requestMap.find(requestId);
|
|
||||||
if (i != requestMap.end()) {
|
|
||||||
msgId = *(mtpMsgId*)(i.value()->constData() + 4);
|
|
||||||
requestMap.erase(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
|
||||||
if (i != requestsByDC.end()) {
|
|
||||||
if (internal::Session *session = internal::getSession(qAbs(i.value()))) {
|
|
||||||
session->cancel(requestId, msgId);
|
|
||||||
}
|
|
||||||
requestsByDC.erase(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal::clearCallbacks(requestId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void killSession(int32 dc) {
|
|
||||||
Sessions::iterator i = sessions.find(dc);
|
|
||||||
if (i != sessions.cend()) {
|
|
||||||
bool wasMain = (i.value() == mainSession);
|
|
||||||
|
|
||||||
i.value()->kill();
|
|
||||||
i.value()->deleteLater();
|
|
||||||
sessions.erase(i);
|
|
||||||
|
|
||||||
if (wasMain) {
|
|
||||||
mainSession = new internal::Session(internal::mainDC());
|
|
||||||
int32 newdc = mainSession->getDcWithShift();
|
|
||||||
i = sessions.find(newdc);
|
|
||||||
if (i != sessions.cend()) {
|
|
||||||
i.value()->kill();
|
|
||||||
i.value()->deleteLater();
|
|
||||||
sessions.erase(i);
|
|
||||||
}
|
|
||||||
sessions.insert(newdc, mainSession);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void stopSession(int32 dc) {
|
|
||||||
Sessions::iterator i = sessions.find(dc);
|
|
||||||
if (i != sessions.end()) {
|
|
||||||
if (i.value() != mainSession) { // don't stop main session
|
|
||||||
i.value()->stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 state(mtpRequestId requestId) {
|
|
||||||
if (requestId > 0) {
|
|
||||||
QMutexLocker locker(&requestByDCLock);
|
|
||||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
|
||||||
if (i != requestsByDC.end()) {
|
|
||||||
if (internal::Session *session = internal::getSession(qAbs(i.value()))) {
|
|
||||||
return session->requestState(requestId);
|
|
||||||
}
|
|
||||||
return MTP::RequestConnecting;
|
|
||||||
}
|
|
||||||
return MTP::RequestSent;
|
|
||||||
}
|
|
||||||
if (internal::Session *session = internal::getSession(-requestId)) {
|
|
||||||
return session->requestState(0);
|
|
||||||
}
|
|
||||||
return MTP::RequestConnecting;
|
|
||||||
}
|
|
||||||
|
|
||||||
void finish() {
|
|
||||||
mainSession = nullptr;
|
|
||||||
for (auto session : base::take(sessions)) {
|
|
||||||
session->kill();
|
|
||||||
delete session;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_const (auto connection, quittingConnections) {
|
|
||||||
connection->waitTillFinish();
|
|
||||||
delete connection;
|
|
||||||
}
|
|
||||||
quittingConnections.clear();
|
|
||||||
|
|
||||||
delete _globalSlotCarrier;
|
|
||||||
_globalSlotCarrier = nullptr;
|
|
||||||
|
|
||||||
internal::destroyConfigLoader();
|
|
||||||
|
|
||||||
_started = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void logoutKeys(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail) {
|
|
||||||
mtpRequestId req = MTP::send(MTPauth_LogOut(), onDone, onFail);
|
|
||||||
internal::logoutOtherDCs();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setGlobalDoneHandler(RPCDoneHandlerPtr handler) {
|
|
||||||
globalHandler.onDone = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setGlobalFailHandler(RPCFailHandlerPtr handler) {
|
|
||||||
globalHandler.onFail = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setStateChangedHandler(MTPStateChangedHandler handler) {
|
|
||||||
stateChangedHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSessionResetHandler(MTPSessionResetHandler handler) {
|
|
||||||
sessionResetHandler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearGlobalHandlers() {
|
|
||||||
setGlobalDoneHandler(RPCDoneHandlerPtr());
|
|
||||||
setGlobalFailHandler(RPCFailHandlerPtr());
|
|
||||||
setStateChangedHandler(0);
|
|
||||||
setSessionResetHandler(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthKeysMap getKeys() {
|
|
||||||
return internal::getAuthKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setKey(int dc, const AuthKey::Data &key) {
|
|
||||||
auto dcId = MTP::bareDcId(dc);
|
|
||||||
auto keyPtr = std::make_shared<MTP::AuthKey>();
|
|
||||||
keyPtr->setDC(dcId);
|
|
||||||
keyPtr->setKey(key);
|
|
||||||
return internal::setAuthKey(dc, std::move(keyPtr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace MTP
|
} // namespace MTP
|
||||||
|
|
|
@ -23,58 +23,41 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mtproto/core_types.h"
|
#include "mtproto/core_types.h"
|
||||||
#include "mtproto/session.h"
|
#include "mtproto/session.h"
|
||||||
#include "core/single_timer.h"
|
#include "core/single_timer.h"
|
||||||
|
#include "mtproto/mtp_instance.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
Session *getSession(ShiftedDcId shiftedDcId); // 0 - current set dc
|
|
||||||
|
|
||||||
bool paused();
|
bool paused();
|
||||||
void pause();
|
void pause();
|
||||||
void unpause();
|
void unpause();
|
||||||
|
|
||||||
void registerRequest(mtpRequestId requestId, int32 dc);
|
} // namespace internal
|
||||||
void unregisterRequest(mtpRequestId requestId);
|
|
||||||
|
|
||||||
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser);
|
class PauseHolder {
|
||||||
mtpRequest getRequest(mtpRequestId req);
|
public:
|
||||||
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent, int32 skipBeforeRequest = 0);
|
PauseHolder() {
|
||||||
void clearCallbacks(mtpRequestId requestId, int32 errorCode = RPCError::NoError); // 0 - do not toggle onError callback
|
restart();
|
||||||
void clearCallbacksDelayed(const RPCCallbackClears &requestIds);
|
}
|
||||||
void performDelayedClear();
|
void restart() {
|
||||||
void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end);
|
if (!base::take(_paused, true)) {
|
||||||
bool hasCallbacks(mtpRequestId requestId);
|
internal::pause();
|
||||||
void globalCallback(const mtpPrime *from, const mtpPrime *end);
|
}
|
||||||
void onStateChange(int32 dcWithShift, int32 state);
|
}
|
||||||
void onSessionReset(int32 dcWithShift);
|
void release() {
|
||||||
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err); // return true if need to clean request data
|
if (base::take(_paused)) {
|
||||||
inline bool rpcErrorOccured(mtpRequestId requestId, const RPCResponseHandler &handler, const RPCError &err) {
|
internal::unpause();
|
||||||
return rpcErrorOccured(requestId, handler.onFail, err);
|
}
|
||||||
|
}
|
||||||
|
~PauseHolder() {
|
||||||
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// used for:
|
|
||||||
// - resending requests by timer which were postponed by flood delay
|
|
||||||
// - destroying MTProtoConnections whose thread has finished
|
|
||||||
class GlobalSlotCarrier : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
GlobalSlotCarrier();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void checkDelayed();
|
|
||||||
void connectionFinished(Connection *connection);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SingleTimer _timer;
|
bool _paused = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GlobalSlotCarrier *globalSlotCarrier();
|
|
||||||
void queueQuittingConnection(Connection *connection);
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
constexpr ShiftedDcId DCShift = 10000;
|
constexpr ShiftedDcId DCShift = 10000;
|
||||||
constexpr DcId bareDcId(ShiftedDcId shiftedDcId) {
|
constexpr DcId bareDcId(ShiftedDcId shiftedDcId) {
|
||||||
return (shiftedDcId % DCShift);
|
return (shiftedDcId % DCShift);
|
||||||
|
@ -135,88 +118,79 @@ constexpr bool isUplDcId(ShiftedDcId shiftedDcId) {
|
||||||
return (shiftedDcId >= internal::uploadDcId(0, 0)) && (shiftedDcId < internal::uploadDcId(0, MTPUploadSessionsCount - 1) + DCShift);
|
return (shiftedDcId >= internal::uploadDcId(0, 0)) && (shiftedDcId < internal::uploadDcId(0, MTPUploadSessionsCount - 1) + DCShift);
|
||||||
}
|
}
|
||||||
|
|
||||||
void start();
|
|
||||||
bool started();
|
|
||||||
void restart();
|
|
||||||
void restart(int32 dcMask);
|
|
||||||
|
|
||||||
class PauseHolder {
|
|
||||||
public:
|
|
||||||
PauseHolder() {
|
|
||||||
restart();
|
|
||||||
}
|
|
||||||
void restart() {
|
|
||||||
if (!base::take(_paused, true)) {
|
|
||||||
internal::pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void release() {
|
|
||||||
if (base::take(_paused)) {
|
|
||||||
internal::unpause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~PauseHolder() {
|
|
||||||
release();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool _paused = false;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
void configure(int32 dc);
|
|
||||||
|
|
||||||
void setdc(int32 dc, bool fromZeroOnly = false);
|
|
||||||
int32 maindc();
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DisconnectedState = 0,
|
DisconnectedState = 0,
|
||||||
ConnectingState = 1,
|
ConnectingState = 1,
|
||||||
ConnectedState = 2,
|
ConnectedState = 2,
|
||||||
};
|
};
|
||||||
int32 dcstate(int32 dc = 0);
|
|
||||||
QString dctransport(int32 dc = 0);
|
|
||||||
|
|
||||||
template <typename TRequest>
|
|
||||||
inline mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), int32 dc = 0, TimeMs msCanWait = 0, mtpRequestId after = 0) {
|
|
||||||
if (internal::Session *session = internal::getSession(dc)) {
|
|
||||||
return session->send(request, callbacks, msCanWait, true, !dc, after);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
template <typename TRequest>
|
|
||||||
inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, TimeMs msCanWait = 0, mtpRequestId after = 0) {
|
|
||||||
return send(request, RPCResponseHandler(onDone, onFail), dc, msCanWait, after);
|
|
||||||
}
|
|
||||||
inline void sendAnything(int32 dc = 0, TimeMs msCanWait = 0) {
|
|
||||||
if (auto session = internal::getSession(dc)) {
|
|
||||||
return session->sendAnything(msCanWait);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void ping();
|
|
||||||
void cancel(mtpRequestId req);
|
|
||||||
void killSession(int32 dc);
|
|
||||||
void stopSession(int32 dc);
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RequestSent = 0,
|
RequestSent = 0,
|
||||||
RequestConnecting = 1,
|
RequestConnecting = 1,
|
||||||
RequestSending = 2
|
RequestSending = 2
|
||||||
};
|
};
|
||||||
int32 state(mtpRequestId req); // < 0 means waiting for such count of ms
|
|
||||||
|
|
||||||
void finish();
|
Instance *MainInstance();
|
||||||
|
|
||||||
void logoutKeys(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail);
|
inline void restart() {
|
||||||
|
return MainInstance()->restart();
|
||||||
|
}
|
||||||
|
|
||||||
void setGlobalDoneHandler(RPCDoneHandlerPtr handler);
|
inline void restart(ShiftedDcId shiftedDcId) {
|
||||||
void setGlobalFailHandler(RPCFailHandlerPtr handler);
|
return MainInstance()->restart(shiftedDcId);
|
||||||
void setStateChangedHandler(MTPStateChangedHandler handler);
|
}
|
||||||
void setSessionResetHandler(MTPSessionResetHandler handler);
|
|
||||||
void clearGlobalHandlers();
|
|
||||||
|
|
||||||
AuthKeysMap getKeys();
|
inline DcId maindc() {
|
||||||
void setKey(int dc, const AuthKey::Data &key);
|
return MainInstance()->mainDcId();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int32 dcstate(ShiftedDcId shiftedDcId = 0) {
|
||||||
|
if (auto instance = MainInstance()) {
|
||||||
|
return instance->dcstate(shiftedDcId);
|
||||||
|
}
|
||||||
|
return DisconnectedState;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QString dctransport(ShiftedDcId shiftedDcId = 0) {
|
||||||
|
if (auto instance = MainInstance()) {
|
||||||
|
return instance->dctransport(shiftedDcId);
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TRequest>
|
||||||
|
inline mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), ShiftedDcId dcId = 0, TimeMs msCanWait = 0, mtpRequestId after = 0) {
|
||||||
|
return MainInstance()->send(request, std::move(callbacks), dcId, msCanWait, after);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TRequest>
|
||||||
|
inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), ShiftedDcId dcId = 0, TimeMs msCanWait = 0, mtpRequestId after = 0) {
|
||||||
|
return MainInstance()->send(request, std::move(onDone), std::move(onFail), dcId, msCanWait, after);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sendAnything(ShiftedDcId shiftedDcId = 0, TimeMs msCanWait = 0) {
|
||||||
|
return MainInstance()->sendAnything(shiftedDcId, msCanWait);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void cancel(mtpRequestId requestId) {
|
||||||
|
return MainInstance()->cancel(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ping() {
|
||||||
|
return MainInstance()->ping();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void killSession(ShiftedDcId shiftedDcId) {
|
||||||
|
return MainInstance()->killSession(shiftedDcId);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void stopSession(ShiftedDcId shiftedDcId) {
|
||||||
|
return MainInstance()->stopSession(shiftedDcId);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int32 state(mtpRequestId requestId) { // < 0 means waiting for such count of ms
|
||||||
|
return MainInstance()->state(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
@ -232,18 +206,17 @@ namespace internal {
|
||||||
|
|
||||||
reqSerialized->msDate = getms(true); // > 0 - can send without container
|
reqSerialized->msDate = getms(true); // > 0 - can send without container
|
||||||
reqSerialized->needsLayer = needsLayer;
|
reqSerialized->needsLayer = needsLayer;
|
||||||
if (after) reqSerialized->after = MTP::internal::getRequest(after);
|
if (after) reqSerialized->after = getRequest(after);
|
||||||
requestId = MTP::internal::storeRequest(reqSerialized, callbacks);
|
requestId = storeRequest(reqSerialized, callbacks);
|
||||||
|
|
||||||
sendPrepared(reqSerialized, msCanWait);
|
sendPrepared(reqSerialized, msCanWait);
|
||||||
} catch (Exception &e) {
|
} catch (Exception &e) {
|
||||||
requestId = 0;
|
requestId = 0;
|
||||||
MTP::internal::rpcErrorOccured(requestId, callbacks, rpcClientError("NO_REQUEST_ID", QString("send() failed to queue request, exception: %1").arg(e.what())));
|
rpcErrorOccured(requestId, callbacks.onFail, rpcClientError("NO_REQUEST_ID", QString("send() failed to queue request, exception: %1").arg(e.what())));
|
||||||
}
|
}
|
||||||
if (requestId) MTP::internal::registerRequest(requestId, toMainDC ? -getDcWithShift() : getDcWithShift());
|
if (requestId) registerRequest(requestId, toMainDC ? -getDcWithShift() : getDcWithShift());
|
||||||
return requestId;
|
return requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
} // namespace MTP
|
} // namespace MTP
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mtproto/dcenter.h"
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace MTP {
|
||||||
|
|
||||||
|
class DcOptions;
|
||||||
|
class Session;
|
||||||
|
|
||||||
|
class Instance : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Config {
|
||||||
|
static constexpr auto kNoneMainDc = -1;
|
||||||
|
static constexpr auto kNotSetMainDc = 0;
|
||||||
|
static constexpr auto kDefaultMainDc = 2;
|
||||||
|
|
||||||
|
DcId mainDcId = kNotSetMainDc;
|
||||||
|
std::map<DcId, AuthKey::Data> keys;
|
||||||
|
};
|
||||||
|
Instance(DcOptions *options, Config &&config);
|
||||||
|
|
||||||
|
Instance(const Instance &other) = delete;
|
||||||
|
Instance &operator=(const Instance &other) = delete;
|
||||||
|
|
||||||
|
void suggestMainDcId(DcId mainDcId);
|
||||||
|
void setMainDcId(DcId mainDcId);
|
||||||
|
DcId mainDcId() const;
|
||||||
|
|
||||||
|
void Instance::setKeyForWrite(DcId dcId, const AuthKeyPtr &key);
|
||||||
|
AuthKeysMap Instance::getKeysForWrite() const;
|
||||||
|
|
||||||
|
DcOptions *dcOptions();
|
||||||
|
|
||||||
|
template <typename TRequest>
|
||||||
|
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), ShiftedDcId dcId = 0, TimeMs msCanWait = 0, mtpRequestId after = 0) {
|
||||||
|
if (auto session = getSession(dcId)) {
|
||||||
|
return session->send(request, callbacks, msCanWait, true, !dcId, after);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TRequest>
|
||||||
|
mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, TimeMs msCanWait = 0, mtpRequestId after = 0) {
|
||||||
|
return send(request, RPCResponseHandler(onDone, onFail), dc, msCanWait, after);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendAnything(ShiftedDcId dcId = 0, TimeMs msCanWait = 0) {
|
||||||
|
if (auto session = getSession(dcId)) {
|
||||||
|
session->sendAnything(msCanWait);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restart();
|
||||||
|
void restart(ShiftedDcId shiftedDcId);
|
||||||
|
int32 dcstate(ShiftedDcId shiftedDcId = 0);
|
||||||
|
QString dctransport(ShiftedDcId shiftedDcId = 0);
|
||||||
|
void ping();
|
||||||
|
void cancel(mtpRequestId requestId);
|
||||||
|
int32 state(mtpRequestId requestId); // < 0 means waiting for such count of ms
|
||||||
|
void killSession(ShiftedDcId shiftedDcId);
|
||||||
|
void stopSession(ShiftedDcId shiftedDcId);
|
||||||
|
void logout(RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail);
|
||||||
|
|
||||||
|
internal::DcenterPtr getDcById(DcId dcId);
|
||||||
|
void unpaused();
|
||||||
|
|
||||||
|
void queueQuittingConnection(std::unique_ptr<internal::Connection> connection);
|
||||||
|
|
||||||
|
void setUpdatesHandler(RPCDoneHandlerPtr onDone);
|
||||||
|
void setGlobalFailHandler(RPCFailHandlerPtr onFail);
|
||||||
|
void setStateChangedHandler(base::lambda<void(ShiftedDcId shiftedDcId, int32 state)> &&handler);
|
||||||
|
void setSessionResetHandler(base::lambda<void(ShiftedDcId shiftedDcId)> &&handler);
|
||||||
|
void clearGlobalHandlers();
|
||||||
|
|
||||||
|
void onStateChange(ShiftedDcId dcWithShift, int32 state);
|
||||||
|
void onSessionReset(ShiftedDcId dcWithShift);
|
||||||
|
|
||||||
|
void registerRequest(mtpRequestId requestId, ShiftedDcId dcWithShift);
|
||||||
|
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser);
|
||||||
|
mtpRequest getRequest(mtpRequestId requestId);
|
||||||
|
void clearCallbacksDelayed(const RPCCallbackClears &requestIds);
|
||||||
|
|
||||||
|
void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end);
|
||||||
|
bool hasCallbacks(mtpRequestId requestId);
|
||||||
|
void globalCallback(const mtpPrime *from, const mtpPrime *end);
|
||||||
|
|
||||||
|
// return true if need to clean request data
|
||||||
|
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err);
|
||||||
|
|
||||||
|
~Instance();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void configLoadRequest();
|
||||||
|
void connectionFinished(internal::Connection *connection);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void configLoaded();
|
||||||
|
|
||||||
|
private:
|
||||||
|
internal::Session *getSession(ShiftedDcId shiftedDcId);
|
||||||
|
|
||||||
|
class Private;
|
||||||
|
const std::unique_ptr<Private> _private;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace MTP
|
|
@ -19,13 +19,14 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
|
||||||
#include "mtproto/session.h"
|
#include "mtproto/session.h"
|
||||||
|
|
||||||
|
#include "mtproto/connection.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
void SessionData::clear() {
|
void SessionData::clear(Instance *instance) {
|
||||||
RPCCallbackClears clearCallbacks;
|
RPCCallbackClears clearCallbacks;
|
||||||
{
|
{
|
||||||
QReadLocker locker1(haveSentMutex()), locker2(toResendMutex()), locker3(haveReceivedMutex()), locker4(wereAckedMutex());
|
QReadLocker locker1(haveSentMutex()), locker2(toResendMutex()), locker3(haveReceivedMutex()), locker4(wereAckedMutex());
|
||||||
|
@ -66,42 +67,23 @@ void SessionData::clear() {
|
||||||
QWriteLocker locker(receivedIdsMutex());
|
QWriteLocker locker(receivedIdsMutex());
|
||||||
receivedIds.clear();
|
receivedIds.clear();
|
||||||
}
|
}
|
||||||
clearCallbacksDelayed(clearCallbacks);
|
instance->clearCallbacksDelayed(clearCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Session::Session(int32 requestedDcId) : QObject()
|
Session::Session(Instance *instance, ShiftedDcId requestedShiftedDcId) : QObject()
|
||||||
, _connection(0)
|
, _instance(instance)
|
||||||
, _killed(false)
|
, data(this) {
|
||||||
, _needToReceive(false)
|
|
||||||
, data(this)
|
|
||||||
, dcWithShift(0)
|
|
||||||
, dc(0)
|
|
||||||
, msSendCall(0)
|
|
||||||
, msWait(0)
|
|
||||||
, _ping(false) {
|
|
||||||
if (_killed) {
|
|
||||||
DEBUG_LOG(("Session Error: can't start a killed session"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (dcWithShift) {
|
|
||||||
DEBUG_LOG(("Session Info: Session::start called on already started session"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
msSendCall = msWait = 0;
|
|
||||||
|
|
||||||
connect(&timeouter, SIGNAL(timeout()), this, SLOT(checkRequestsByTimer()));
|
connect(&timeouter, SIGNAL(timeout()), this, SLOT(checkRequestsByTimer()));
|
||||||
timeouter.start(1000);
|
timeouter.start(1000);
|
||||||
|
|
||||||
connect(&sender, SIGNAL(timeout()), this, SLOT(needToResumeAndSend()));
|
connect(&sender, SIGNAL(timeout()), this, SLOT(needToResumeAndSend()));
|
||||||
|
|
||||||
_connection = new Connection();
|
_connection = std::make_unique<Connection>(_instance);
|
||||||
dcWithShift = _connection->prepare(&data, requestedDcId);
|
dcWithShift = _connection->prepare(&data, requestedShiftedDcId);
|
||||||
if (!dcWithShift) {
|
if (!dcWithShift) {
|
||||||
delete _connection;
|
_connection.reset();
|
||||||
_connection = 0;
|
DEBUG_LOG(("Session Info: could not start connection to dc %1").arg(requestedShiftedDcId));
|
||||||
DEBUG_LOG(("Session Info: could not start connection to dc %1").arg(requestedDcId));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
createDcData();
|
createDcData();
|
||||||
|
@ -112,24 +94,33 @@ void Session::createDcData() {
|
||||||
if (dc) {
|
if (dc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int32 dcId = bareDcId(dcWithShift);
|
auto dcId = bareDcId(dcWithShift);
|
||||||
|
|
||||||
auto &dcs = DCMap();
|
dc = _instance->getDcById(dcId);
|
||||||
auto dcIndex = dcs.constFind(dcId);
|
|
||||||
if (dcIndex == dcs.cend()) {
|
|
||||||
dc = DcenterPtr(new Dcenter(dcId, AuthKeyPtr()));
|
|
||||||
dcs.insert(dcId, dc);
|
|
||||||
} else {
|
|
||||||
dc = dcIndex.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadLockerAttempt lock(keyMutex());
|
ReadLockerAttempt lock(keyMutex());
|
||||||
data.setKey(lock ? dc->getKey() : AuthKeyPtr());
|
data.setKey(lock ? dc->getKey() : AuthKeyPtr());
|
||||||
if (lock && dc->connectionInited()) {
|
if (lock && dc->connectionInited()) {
|
||||||
data.setLayerWasInited(true);
|
data.setLayerWasInited(true);
|
||||||
}
|
}
|
||||||
connect(dc.data(), SIGNAL(authKeyCreated()), this, SLOT(authKeyCreatedForDC()), Qt::QueuedConnection);
|
connect(dc.get(), SIGNAL(authKeyCreated()), this, SLOT(authKeyCreatedForDC()), Qt::QueuedConnection);
|
||||||
connect(dc.data(), SIGNAL(layerWasInited(bool)), this, SLOT(layerWasInitedForDC(bool)), Qt::QueuedConnection);
|
connect(dc.get(), SIGNAL(layerWasInited(bool)), this, SLOT(layerWasInitedForDC(bool)), Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::registerRequest(mtpRequestId requestId, ShiftedDcId dcWithShift) {
|
||||||
|
return _instance->registerRequest(requestId, dcWithShift);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtpRequestId Session::storeRequest(mtpRequest &request, const RPCResponseHandler &parser) {
|
||||||
|
return _instance->storeRequest(request, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtpRequest Session::getRequest(mtpRequestId requestId) {
|
||||||
|
return _instance->getRequest(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err) { // return true if need to clean request data
|
||||||
|
return _instance->rpcErrorOccured(requestId, onFail, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::restart() {
|
void Session::restart() {
|
||||||
|
@ -148,7 +139,7 @@ void Session::stop() {
|
||||||
DEBUG_LOG(("Session Info: stopping session dcWithShift %1").arg(dcWithShift));
|
DEBUG_LOG(("Session Info: stopping session dcWithShift %1").arg(dcWithShift));
|
||||||
if (_connection) {
|
if (_connection) {
|
||||||
_connection->kill();
|
_connection->kill();
|
||||||
_connection = 0;
|
_instance->queueQuittingConnection(std::move(_connection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,12 +193,9 @@ void Session::needToResumeAndSend() {
|
||||||
}
|
}
|
||||||
if (!_connection) {
|
if (!_connection) {
|
||||||
DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(dcWithShift));
|
DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(dcWithShift));
|
||||||
DcenterMap &dcs(DCMap());
|
_connection = std::make_unique<Connection>(_instance);
|
||||||
|
|
||||||
_connection = new Connection();
|
|
||||||
if (!_connection->prepare(&data, dcWithShift)) {
|
if (!_connection->prepare(&data, dcWithShift)) {
|
||||||
delete _connection;
|
_connection.reset();
|
||||||
_connection = 0;
|
|
||||||
DEBUG_LOG(("Session Info: could not start connection to dcWithShift %1").arg(dcWithShift));
|
DEBUG_LOG(("Session Info: could not start connection to dcWithShift %1").arg(dcWithShift));
|
||||||
dcWithShift = 0;
|
dcWithShift = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -298,16 +286,16 @@ void Session::checkRequestsByTimer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clearCallbacksDelayed(clearCallbacks);
|
_instance->clearCallbacksDelayed(clearCallbacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::onConnectionStateChange(qint32 newState) {
|
void Session::onConnectionStateChange(qint32 newState) {
|
||||||
onStateChange(dcWithShift, newState);
|
_instance->onStateChange(dcWithShift, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::onResetDone() {
|
void Session::onResetDone() {
|
||||||
onSessionReset(dcWithShift);
|
_instance->onSessionReset(dcWithShift);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::cancel(mtpRequestId requestId, mtpMsgId msgId) {
|
void Session::cancel(mtpRequestId requestId, mtpMsgId msgId) {
|
||||||
|
@ -473,9 +461,9 @@ void Session::authKeyCreatedForDC() {
|
||||||
emit authKeyCreated();
|
emit authKeyCreated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::notifyKeyCreated(const AuthKeyPtr &key) {
|
void Session::notifyKeyCreated(AuthKeyPtr &&key) {
|
||||||
DEBUG_LOG(("AuthKey Info: Session::keyCreated(), setting, dcWithShift %1").arg(dcWithShift));
|
DEBUG_LOG(("AuthKey Info: Session::keyCreated(), setting, dcWithShift %1").arg(dcWithShift));
|
||||||
dc->setKey(key);
|
dc->setKey(std::move(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::layerWasInitedForDC(bool wasInited) {
|
void Session::layerWasInitedForDC(bool wasInited) {
|
||||||
|
@ -530,17 +518,17 @@ void Session::tryToReceive() {
|
||||||
}
|
}
|
||||||
if (requestId <= 0) {
|
if (requestId <= 0) {
|
||||||
if (dcWithShift == bareDcId(dcWithShift)) { // call globalCallback only in main session
|
if (dcWithShift == bareDcId(dcWithShift)) { // call globalCallback only in main session
|
||||||
globalCallback(response.constData(), response.constData() + response.size());
|
_instance->globalCallback(response.constData(), response.constData() + response.size());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
execCallback(requestId, response.constData(), response.constData() + response.size());
|
_instance->execCallback(requestId, response.constData(), response.constData() + response.size());
|
||||||
}
|
}
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::~Session() {
|
Session::~Session() {
|
||||||
t_assert(_connection == 0);
|
t_assert(_connection == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPrpcError rpcClientError(const QString &type, const QString &description) {
|
MTPrpcError rpcClientError(const QString &type, const QString &description) {
|
||||||
|
|
|
@ -20,14 +20,17 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "mtproto/connection.h"
|
|
||||||
#include "mtproto/dcenter.h"
|
#include "mtproto/dcenter.h"
|
||||||
#include "mtproto/rpc_sender.h"
|
|
||||||
#include "core/single_timer.h"
|
#include "core/single_timer.h"
|
||||||
|
|
||||||
namespace MTP {
|
namespace MTP {
|
||||||
|
|
||||||
|
class Instance;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
class Connection;
|
||||||
|
|
||||||
class ReceivedMsgIds {
|
class ReceivedMsgIds {
|
||||||
public:
|
public:
|
||||||
bool registerMsgId(mtpMsgId msgId, bool needAck) {
|
bool registerMsgId(mtpMsgId msgId, bool needAck) {
|
||||||
|
@ -236,7 +239,7 @@ public:
|
||||||
return result * 2 + (needAck ? 1 : 0);
|
return result * 2 + (needAck ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear();
|
void clear(Instance *instance);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64 _session = 0;
|
uint64 _session = 0;
|
||||||
|
@ -275,7 +278,7 @@ class Session : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Session(int32 dcenter);
|
Session(Instance *instance, ShiftedDcId requestedShiftedDcId);
|
||||||
|
|
||||||
void restart();
|
void restart();
|
||||||
void stop();
|
void stop();
|
||||||
|
@ -283,10 +286,10 @@ public:
|
||||||
|
|
||||||
void unpaused();
|
void unpaused();
|
||||||
|
|
||||||
int32 getDcWithShift() const;
|
ShiftedDcId getDcWithShift() const;
|
||||||
|
|
||||||
QReadWriteLock *keyMutex() const;
|
QReadWriteLock *keyMutex() const;
|
||||||
void notifyKeyCreated(const AuthKeyPtr &key);
|
void notifyKeyCreated(AuthKeyPtr &&key);
|
||||||
void destroyKey();
|
void destroyKey();
|
||||||
void notifyLayerInited(bool wasInited);
|
void notifyLayerInited(bool wasInited);
|
||||||
|
|
||||||
|
@ -331,19 +334,26 @@ public slots:
|
||||||
private:
|
private:
|
||||||
void createDcData();
|
void createDcData();
|
||||||
|
|
||||||
Connection *_connection;
|
void registerRequest(mtpRequestId requestId, ShiftedDcId dcWithShift);
|
||||||
|
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser);
|
||||||
|
mtpRequest getRequest(mtpRequestId requestId);
|
||||||
|
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err);
|
||||||
|
|
||||||
bool _killed;
|
Instance *_instance;
|
||||||
bool _needToReceive;
|
std::unique_ptr<Connection> _connection;
|
||||||
|
|
||||||
|
bool _killed = false;
|
||||||
|
bool _needToReceive = false;
|
||||||
|
|
||||||
SessionData data;
|
SessionData data;
|
||||||
|
|
||||||
int32 dcWithShift;
|
ShiftedDcId dcWithShift = 0;
|
||||||
DcenterPtr dc;
|
DcenterPtr dc;
|
||||||
|
|
||||||
TimeMs msSendCall, msWait;
|
TimeMs msSendCall = 0;
|
||||||
|
TimeMs msWait = 0;
|
||||||
|
|
||||||
bool _ping;
|
bool _ping = false;
|
||||||
|
|
||||||
QTimer timeouter;
|
QTimer timeouter;
|
||||||
SingleTimer sender;
|
SingleTimer sender;
|
||||||
|
|
|
@ -72,7 +72,7 @@ void PasscodeWidget::onSubmit() {
|
||||||
if (Local::readMap(_passcode->text().toUtf8()) != Local::ReadMapPassNeeded) {
|
if (Local::readMap(_passcode->text().toUtf8()) != Local::ReadMapPassNeeded) {
|
||||||
cSetPasscodeBadTries(0);
|
cSetPasscodeBadTries(0);
|
||||||
|
|
||||||
MTP::start();
|
Messenger::Instance().startMtp();
|
||||||
if (AuthSession::Current()) {
|
if (AuthSession::Current()) {
|
||||||
App::wnd()->setupMain();
|
App::wnd()->setupMain();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -186,9 +186,9 @@ static const NotifySettingsPtr EmptyNotifySettings = NotifySettingsPtr(1);
|
||||||
extern NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats;
|
extern NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats;
|
||||||
extern NotifySettingsPtr globalNotifyAllPtr, globalNotifyUsersPtr, globalNotifyChatsPtr;
|
extern NotifySettingsPtr globalNotifyAllPtr, globalNotifyUsersPtr, globalNotifyChatsPtr;
|
||||||
|
|
||||||
inline bool isNotifyMuted(NotifySettingsPtr settings, TimeId *changeIn = 0) {
|
inline bool isNotifyMuted(NotifySettingsPtr settings, TimeId *changeIn = nullptr) {
|
||||||
if (settings != UnknownNotifySettings && settings != EmptyNotifySettings) {
|
if (settings != UnknownNotifySettings && settings != EmptyNotifySettings) {
|
||||||
TimeId t = unixtime();
|
auto t = unixtime();
|
||||||
if (settings->mute > t) {
|
if (settings->mute > t) {
|
||||||
if (changeIn) *changeIn = settings->mute - t + 1;
|
if (changeIn) *changeIn = settings->mute - t + 1;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -323,8 +323,6 @@
|
||||||
'<(src_loc)/media/media_clip_qtgif.h',
|
'<(src_loc)/media/media_clip_qtgif.h',
|
||||||
'<(src_loc)/media/media_clip_reader.cpp',
|
'<(src_loc)/media/media_clip_reader.cpp',
|
||||||
'<(src_loc)/media/media_clip_reader.h',
|
'<(src_loc)/media/media_clip_reader.h',
|
||||||
'<(src_loc)/mtproto/facade.cpp',
|
|
||||||
'<(src_loc)/mtproto/facade.h',
|
|
||||||
'<(src_loc)/mtproto/auth_key.cpp',
|
'<(src_loc)/mtproto/auth_key.cpp',
|
||||||
'<(src_loc)/mtproto/auth_key.h',
|
'<(src_loc)/mtproto/auth_key.h',
|
||||||
'<(src_loc)/mtproto/connection.cpp',
|
'<(src_loc)/mtproto/connection.cpp',
|
||||||
|
@ -343,8 +341,12 @@
|
||||||
'<(src_loc)/mtproto/dcenter.h',
|
'<(src_loc)/mtproto/dcenter.h',
|
||||||
'<(src_loc)/mtproto/dc_options.cpp',
|
'<(src_loc)/mtproto/dc_options.cpp',
|
||||||
'<(src_loc)/mtproto/dc_options.h',
|
'<(src_loc)/mtproto/dc_options.h',
|
||||||
|
'<(src_loc)/mtproto/facade.cpp',
|
||||||
|
'<(src_loc)/mtproto/facade.h',
|
||||||
'<(src_loc)/mtproto/file_download.cpp',
|
'<(src_loc)/mtproto/file_download.cpp',
|
||||||
'<(src_loc)/mtproto/file_download.h',
|
'<(src_loc)/mtproto/file_download.h',
|
||||||
|
'<(src_loc)/mtproto/mtp_instance.cpp',
|
||||||
|
'<(src_loc)/mtproto/mtp_instance.h',
|
||||||
'<(src_loc)/mtproto/rsa_public_key.cpp',
|
'<(src_loc)/mtproto/rsa_public_key.cpp',
|
||||||
'<(src_loc)/mtproto/rsa_public_key.h',
|
'<(src_loc)/mtproto/rsa_public_key.h',
|
||||||
'<(src_loc)/mtproto/rpc_sender.cpp',
|
'<(src_loc)/mtproto/rpc_sender.cpp',
|
||||||
|
|
Loading…
Reference in New Issue