version 0.6.7: invokeAfter, long messages split, protocol implementation improvements

This commit is contained in:
John Preston 2014-11-05 20:43:32 +03:00
parent cdff62547b
commit e0ef1d434d
40 changed files with 910 additions and 374 deletions

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.6
AppVersion=6006
AppVersionStr=0.6.7
AppVersion=6007
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinuxupd$AppVersion" ]; then
echo "tlinuxupd$AppVersion not found!";

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.6
AppVersion=6006
AppVersionStr=0.6.7
AppVersion=6007
if [ ! -f "./../Linux/Release/deploy/$AppVersionStr/tlinux32upd$AppVersion" ]; then
echo "tlinux32upd$AppVersion not found!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.6
AppVersion=6006
AppVersionStr=0.6.7
AppVersion=6007
if [ ! -f "./../Mac/Release/deploy/$AppVersionStr/tmacupd$AppVersion" ]; then
echo "tmacupd$AppVersion not found!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.6
AppVersion=6006
AppVersionStr=0.6.7
AppVersion=6007
if [ ! -f "./../Win32/Deploy/deploy/$AppVersionStr/tupdate$AppVersion" ]; then
echo "tupdate$AppVersion not found!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.6
AppVersion=6006
AppVersionStr=0.6.7
AppVersion=6007
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
echo "Deploy folder for version $AppVersionStr already exists!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.6
AppVersion=6006
AppVersionStr=0.6.7
AppVersion=6007
if [ -d "./../Linux/Release/deploy/$AppVersionStr" ]; then
echo "Deploy folder for version $AppVersionStr already exists!"

View File

@ -1,5 +1,5 @@
AppVersionStr=0.6.6
AppVersion=6006
AppVersionStr=0.6.7
AppVersion=6007
if [ -d "./../Mac/Release/deploy/$AppVersionStr" ]; then
echo "Deploy folder for version $AppVersionStr already exists!"

View File

@ -1,6 +1,6 @@
cd ..\Win32\Deploy
call ..\..\..\TelegramPrivate\Sign.bat tsetup.0.6.6.exe
call ..\..\..\TelegramPrivate\Sign.bat tsetup.0.6.7.exe
call Prepare.exe -path Telegram.exe -path Updater.exe
mkdir deploy\0.6.6\Telegram
move deploy\0.6.6\Telegram.exe deploy\0.6.6\Telegram\
mkdir deploy\0.6.7\Telegram
move deploy\0.6.7\Telegram.exe deploy\0.6.7\Telegram\
cd ..\..\Telegram

View File

@ -3,9 +3,9 @@
#define MyAppShortName "Telegram"
#define MyAppName "Telegram Desktop"
#define MyAppVersion "0.6.6"
#define MyAppVersionZero "0.6.6"
#define MyAppFullVersion "0.6.6.0"
#define MyAppVersion "0.6.7"
#define MyAppVersionZero "0.6.7"
#define MyAppFullVersion "0.6.7.0"
#define MyAppPublisher "Telegram Messenger LLP"
#define MyAppURL "https://tdesktop.com"
#define MyAppExeName "Telegram.exe"

View File

@ -574,7 +574,7 @@ namespace App {
const QVector<MTPcontacts_Link> &v(links.c_vector().v);
for (QVector<MTPcontacts_Link>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
const MTPDcontacts_link &dv(i->c_contacts_link());
feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, dv.vuser)));
feedUsers(MTP_vector<MTPUser>(1, dv.vuser));
MTPint userId(MTP_int(0));
switch (dv.vuser.type()) {
case mtpc_userEmpty: userId = dv.vuser.c_userEmpty().vid; break;

View File

@ -331,10 +331,10 @@ void Application::writeUserConfigIn(uint64 ms) {
void Application::killDownloadSessionsStart(int32 dc) {
if (killDownloadSessionTimes.constFind(dc) == killDownloadSessionTimes.cend()) {
killDownloadSessionTimes.insert(dc, getms() + MTPKillFileSessionTimeout);
killDownloadSessionTimes.insert(dc, getms() + MTPAckSendWaiting + MTPKillFileSessionTimeout);
}
if (!killDownloadSessionsTimer.isActive()) {
killDownloadSessionsTimer.start(MTPKillFileSessionTimeout + 5);
killDownloadSessionsTimer.start(MTPAckSendWaiting + MTPKillFileSessionTimeout + 5);
}
}
@ -350,7 +350,7 @@ void Application::onWriteUserConfig() {
}
void Application::killDownloadSessions() {
uint64 ms = getms(), left = MTPKillFileSessionTimeout;
uint64 ms = getms(), left = MTPAckSendWaiting + MTPKillFileSessionTimeout;
for (QMap<int32, uint64>::iterator i = killDownloadSessionTimes.begin(); i != killDownloadSessionTimes.end(); ) {
if (i.value() <= ms) {
for (int j = 1; j < MTPDownloadSessionsCount; ++j) {
@ -378,7 +378,8 @@ void Application::photoUpdated(MsgId msgId, const MTPInputFile &file) {
if (peer == App::self()->id) {
MTP::send(MTPphotos_UploadProfilePhoto(file, MTP_string(""), MTP_inputGeoPointEmpty(), MTP_inputPhotoCrop(MTP_double(0), MTP_double(0), MTP_double(100))), rpcDone(&Application::selfPhotoDone), rpcFail(&Application::peerPhotoFail, peer));
} else {
MTP::send(MTPmessages_EditChatPhoto(MTP_int(peer & 0xFFFFFFFF), MTP_inputChatUploadedPhoto(file, MTP_inputPhotoCrop(MTP_double(0), MTP_double(0), MTP_double(100)))), rpcDone(&Application::chatPhotoDone, peer), rpcFail(&Application::peerPhotoFail, peer));
History *hist = App::history(peer);
hist->sendRequestId = MTP::send(MTPmessages_EditChatPhoto(MTP_int(peer & 0xFFFFFFFF), MTP_inputChatUploadedPhoto(file, MTP_inputPhotoCrop(MTP_double(0), MTP_double(0), MTP_double(100)))), rpcDone(&Application::chatPhotoDone, peer), rpcFail(&Application::peerPhotoFail, peer), 0, 0, hist->sendRequestId);
}
}
}

View File

@ -251,7 +251,7 @@ void AddContactBox::onSend() {
}
void AddContactBox::onSaveSelfDone(const MTPUser &user) {
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, user)));
App::feedUsers(MTP_vector<MTPUser>(1, user));
emit closed();
}

View File

@ -201,7 +201,7 @@ void UsernameBox::onChanged() {
}
void UsernameBox::onUpdateDone(const MTPUser &user) {
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, user)));
App::feedUsers(MTP_vector<MTPUser>(1, user));
emit closed();
}

View File

@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
*/
#pragma once
static const int32 AppVersion = 6006;
static const wchar_t *AppVersionStr = L"0.6.6";
static const int32 AppVersion = 6007;
static const wchar_t *AppVersionStr = L"0.6.7";
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop";
@ -34,6 +34,7 @@ enum {
MTPIdsBufferSize = 400, // received msgIds and wereAcked msgIds count stored
MTPCheckResendTimeout = 10000, // how much time passed from send till we resend request or check it's state, in ms
MTPCheckResendWaiting = 1000, // how much time to wait for some more requests, when resending request or checking it's state, in ms
MTPAckSendWaiting = 10000, // how much time to wait for some more requests, when sending msg acks
MTPResendThreshold = 1, // how much ints should message contain for us not to resend, but to check it's state
MTPContainerLives = 600, // container lives 10 minutes in haveSent map
MTPMaxReceiveDelay = 64000, // 64 seconds
@ -97,6 +98,8 @@ enum {
MinUsernameLength = 5,
MaxUsernameLength = 32,
UsernameCheckTimeout = 200,
MaxMessageSize = 4096,
};
#ifdef Q_OS_WIN
@ -232,6 +235,7 @@ enum {
MaxPhotosInMemory = 50, // try to clear some memory after 50 photos are created
NoUpdatesTimeout = 180 * 1000, // if nothing is received in 3 min we reconnect
WaitForSeqTimeout = 1000, // 1s wait for skipped seq in updates
MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory
NotifyWindowsCount = 3, // 3 desktop notifies at the same time

View File

@ -85,7 +85,7 @@ void FileUploader::sendNext() {
bool killing = killSessionsTimer.isActive();
if (queue.isEmpty()) {
if (!killing) {
killSessionsTimer.start(MTPKillFileSessionTimeout);
killSessionsTimer.start(MTPAckSendWaiting + MTPKillFileSessionTimeout);
}
return;
}

View File

@ -101,6 +101,28 @@ namespace {
}
return false;
}
inline bool chIsSentenceEnd(QChar ch) {
switch (ch.unicode()) {
case '.':
case '?':
case '!':
return true;
default:
break;
}
return false;
}
inline bool chIsSentencePartEnd(QChar ch) {
switch (ch.unicode()) {
case ',':
case ':':
case ';':
return true;
default:
break;
}
return false;
}
inline bool chIsParagraphSeparator(QChar ch) {
switch (ch.unicode()) {
case QChar::LineFeed:
@ -3978,6 +4000,74 @@ QString textSearchKey(const QString &text) {
return textAccentFold(text.trimmed().toLower());
}
bool textSplit(QString &sendingText, QString &leftText, int32 limit) {
if (leftText.isEmpty() || !limit) return false;
LinkRanges lnkRanges = textParseLinks(leftText);
int32 currentLink = 0, lnkCount = lnkRanges.size();
int32 s = 0, half = limit / 2, goodLevel = 0;
for (const QChar *start = leftText.constData(), *ch = start, *end = leftText.constEnd(), *good = ch; ch != end; ++ch, ++s) {
while (currentLink < lnkCount && ch >= lnkRanges[currentLink].from + lnkRanges[currentLink].len) {
++currentLink;
}
bool inLink = (currentLink < lnkCount) && (ch > lnkRanges[currentLink].from) && (ch < lnkRanges[currentLink].from + lnkRanges[currentLink].len);
if (s > half) {
if (inLink) {
if (!goodLevel) good = ch;
} else {
if (chIsNewline(*ch)) {
if (ch + 1 < end && chIsNewline(*(ch + 1)) && goodLevel <= 7) {
goodLevel = 7;
good = ch;
} else if (goodLevel <= 6) {
goodLevel = 6;
good = ch;
}
} else if (chIsSpace(*ch)) {
if (chIsSentenceEnd(*(ch - 1)) && goodLevel <= 5) {
goodLevel = 5;
good = ch;
} else if (chIsSentencePartEnd(*(ch - 1)) && goodLevel <= 4) {
goodLevel = 4;
good = ch;
} else if (goodLevel <= 3) {
goodLevel = 3;
good = ch;
}
} else if (chIsWordSeparator(*(ch - 1)) && goodLevel <= 2) {
goodLevel = 2;
good = ch;
} else if (goodLevel <= 1) {
goodLevel = 1;
good = ch;
}
}
}
if (ch->isHighSurrogate()) {
if (ch + 1 < end && (ch + 1)->isLowSurrogate()) {
++ch;
}
} else {
if (ch + 1 < end && ((((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3) || (ch + 1)->unicode() == 0xFE0F)) {
if (getEmoji((ch->unicode() << 16) | (ch + 1)->unicode())) {
++ch;
++s;
}
}
}
if (s >= limit) {
sendingText = leftText.mid(0, good - start);
leftText = leftText.mid(good - start);
return true;
}
}
sendingText = leftText;
leftText = QString();
return true;
}
LinkRanges textParseLinks(const QString &text, bool rich) {
LinkRanges lnkRanges;

View File

@ -23,6 +23,7 @@ QString textRichPrepare(const QString &text);
QString textOneLine(const QString &text, bool trim = true, bool rich = false);
QString textAccentFold(const QString &text);
QString textSearchKey(const QString &text);
bool textSplit(QString &sendingText, QString &leftText, int32 limit);
struct LinkRange {
LinkRange() : from(0), len(0) {

View File

@ -874,6 +874,7 @@ History::History(const PeerId &peerId) : width(0), height(0)
, lastWidth(0)
, lastScrollTop(History::ScrollMax)
, mute(isNotifyMuted(peer->notify))
, sendRequestId(0)
, textCachedFor(0)
, lastItemTextCache(st::dlgRichMinWidth)
, posInDialogs(0)
@ -1337,7 +1338,6 @@ void History::newItemAdded(HistoryItem *item) {
unregTyping(item->from());
}
if (item->out()) {
// inboxRead(false);
if (unreadBar) unreadBar->destroy();
} else if (item->unread()) {
notifies.push_back(item);
@ -1529,13 +1529,13 @@ void History::addToBack(const QVector<MTPMessage> &slice) {
}
}
void History::inboxRead(bool byThisInstance) {
void History::inboxRead(HistoryItem *wasRead) {
if (unreadCount) {
if (!byThisInstance && loadedAtBottom()) App::main()->historyToDown(this);
if (wasRead && loadedAtBottom()) App::main()->historyToDown(this);
setUnreadCount(0);
}
if (!isEmpty()) {
int32 till = back()->back()->id;
int32 till = (wasRead ? wasRead : back()->back())->id;
if (inboxReadTill < till) inboxReadTill = till;
}
if (!dialogs.isEmpty()) {
@ -1545,9 +1545,9 @@ void History::inboxRead(bool byThisInstance) {
clearNotifications();
}
void History::outboxRead() {
void History::outboxRead(HistoryItem *wasRead) {
if (!isEmpty()) {
int32 till = back()->back()->id;
int32 till = wasRead->id;
if (outboxReadTill < till) outboxReadTill = till;
}
}
@ -1978,9 +1978,9 @@ HistoryItem::HistoryItem(History *history, HistoryBlock *block, MsgId msgId, boo
void HistoryItem::markRead() {
if (_unread) {
if (_out) {
_history->outboxRead();
_history->outboxRead(this);
} else {
_history->inboxRead();
_history->inboxRead(this);
}
App::main()->msgUpdated(_history->peer->id, this);
_unread = false;

View File

@ -657,8 +657,8 @@ struct History : public QList<HistoryBlock*> {
void newItemAdded(HistoryItem *item);
void unregTyping(UserData *from);
void inboxRead(bool byThisInstance = false);
void outboxRead();
void inboxRead(HistoryItem *wasRead);
void outboxRead(HistoryItem *wasRead);
void setUnreadCount(int32 newUnreadCount, bool psUpdate = true);
void setMsgCount(int32 newMsgCount);
@ -732,6 +732,8 @@ struct History : public QList<HistoryBlock*> {
int32 lastWidth, lastScrollTop;
bool mute;
mtpRequestId sendRequestId;
// for dialog drawing
Text nameText;
void updateNameText();

View File

@ -1536,7 +1536,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
, titlePeerTextWidth(0)
, bg(st::msgBG)
, hiderOffered(false)
, _scrollDelta(0) {
, _scrollDelta(0)
, _typingRequest(0) {
_scroll.setFocusPolicy(Qt::NoFocus);
setAcceptDrops(true);
@ -1557,9 +1558,12 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
connect(App::wnd()->windowHandle(), SIGNAL(visibleChanged(bool)), this, SLOT(onVisibleChanged()));
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
connect(&_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr)));
connect(&_typingStopTimer, SIGNAL(timeout()), this, SLOT(cancelTyping()));
_scrollTimer.setSingleShot(false);
_typingStopTimer.setSingleShot(true);
_animActiveTimer.setSingleShot(false);
connect(&_animActiveTimer, SIGNAL(timeout()), this, SLOT(onAnimActiveStep()));
@ -1595,12 +1599,29 @@ void HistoryWidget::onTextChange() {
updateTyping();
}
void HistoryWidget::cancelTyping() {
if (_typingRequest) {
MTP::cancel(_typingRequest);
_typingRequest = 0;
}
}
void HistoryWidget::updateTyping(bool typing) {
uint64 ms = getms() + 10000;
if (noTypingUpdate || !hist || (typing && (hist->myTyping + 5000 > ms)) || (!typing && (hist->myTyping + 5000 <= ms))) return;
hist->myTyping = typing ? ms : 0;
if (typing) MTP::send(MTPmessages_SetTyping(histPeer->input, typing ? MTP_sendMessageTypingAction() : MTP_sendMessageCancelAction()));
cancelTyping();
if (typing) {
_typingRequest = MTP::send(MTPmessages_SetTyping(histPeer->input, typing ? MTP_sendMessageTypingAction() : MTP_sendMessageCancelAction()), rpcDone(&HistoryWidget::typingDone));
_typingStopTimer.start(5000);
}
}
void HistoryWidget::typingDone(const MTPBool &result, mtpRequestId req) {
if (_typingRequest == req) {
_typingRequest = 0;
}
}
void HistoryWidget::activate() {
@ -1778,7 +1799,7 @@ void HistoryWidget::showPeer(const PeerId &peer, MsgId msgId, bool force, bool l
App::main()->peerUpdated(histPeer);
noTypingUpdate = true;
_field.setPlainText(hist->draft);
setFieldText(hist->draft);
_field.setFocus();
if (!hist->draft.isEmpty()) {
_field.setTextCursor(hist->draftCur);
@ -2192,26 +2213,15 @@ void HistoryWidget::onSend(bool ctrlShiftEnter) {
QString text = prepareMessage(_field.getText());
if (!text.isEmpty()) {
App::main()->readServerHistory(hist, false);
MsgId newId = clientMsgId();
uint64 randomId = MTP::nonce<uint64>();
App::historyRegRandom(randomId, newId);
hist->loadAround(0);
MTPstring msgText(MTP_string(text));
int32 flags = 0x01 | 0x02; // unread, out
hist->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(histPeer->id), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty()));
App::main()->historyToDown(hist);
App::main()->dialogsToUp();
peerMessagesUpdated();
App::main()->sendPreparedText(hist, prepareMessage(_field.getText()));
MTP::send(MTPmessages_SendMessage(histInputPeer, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId));
_field.setPlainText("");
setFieldText(QString());
if (!_attachType.isHidden()) _attachType.hideStart();
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
}
_field.setFocus();
}
@ -2237,10 +2247,10 @@ mtpRequestId HistoryWidget::onForward(const PeerId &peer, SelectedItemSet toForw
newId = clientMsgId();
hist->addToBackForwarded(newId, msg);
MTP::send(MTPmessages_ForwardMessage(histPeer->input, MTP_int(item->id), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId));
hist->sendRequestId = MTP::send(MTPmessages_ForwardMessage(histPeer->input, MTP_int(item->id), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
} else if (srv || (msg && msg->selectedText(FullItemSel).isEmpty())) {
// newId = clientMsgId();
// MTP::send(MTPmessages_ForwardMessage(histPeer->input, MTP_int(item->id), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId));
// hist->sendRequestId = MTP::send(MTPmessages_ForwardMessage(histPeer->input, MTP_int(item->id), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
} else if (msg) {
App::main()->readServerHistory(hist, false);
@ -2250,7 +2260,7 @@ mtpRequestId HistoryWidget::onForward(const PeerId &peer, SelectedItemSet toForw
int32 flags = 0x01 | 0x02; // unread, out
hist->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(histPeer->id), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty()));
MTP::send(MTPmessages_SendMessage(histPeer->input, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId));
hist->sendRequestId = MTP::send(MTPmessages_SendMessage(histPeer->input, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
if (newId) {
App::historyRegRandom(randomId, newId);
@ -2265,14 +2275,16 @@ mtpRequestId HistoryWidget::onForward(const PeerId &peer, SelectedItemSet toForw
PeerData *toPeer = App::peerLoaded(peer);
if (!toPeer) return 0;
App::main()->readServerHistory(App::history(toPeer->id), false);
History *hist = App::history(peer);
App::main()->readServerHistory(hist, false);
QVector<MTPint> ids;
ids.reserve(toForward.size());
for (SelectedItemSet::const_iterator i = toForward.cbegin(), e = toForward.cend(); i != e; ++i) {
ids.push_back(MTP_int(i.value()->id));
}
return MTP::send(MTPmessages_ForwardMessages(toPeer->input, MTP_vector<MTPint>(ids)), App::main()->rpcDone(&MainWidget::forwardDone, peer));
hist->sendRequestId = MTP::send(MTPmessages_ForwardMessages(toPeer->input, MTP_vector<MTPint>(ids)), App::main()->rpcDone(&MainWidget::forwardDone, peer), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
return hist->sendRequestId;
}
void HistoryWidget::onShareContact(const PeerId &peer, UserData *contact) {
@ -2296,7 +2308,7 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const
int32 flags = 0x01 | 0x02; // unread, out
h->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(peer), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname), MTP_int(userId))));
MTP::send(MTPmessages_SendMedia(App::peer(peer)->input, MTP_inputMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId));
h->sendRequestId = MTP::send(MTPmessages_SendMedia(App::peer(peer)->input, MTP_inputMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
App::historyRegRandom(randomId, newId);
if (hist && histPeer && peer == histPeer->id) {
@ -2838,7 +2850,7 @@ void HistoryWidget::confirmSendImage(const ReadyLocalMedia &img) {
}
void HistoryWidget::cancelSendImage() {
if (confirmImageId && confirmWithText) _field.setPlainText(QString());
if (confirmImageId && confirmWithText) setFieldText(QString());
confirmImageId = 0;
confirmWithText = false;
confirmImage = QImage();
@ -2852,7 +2864,8 @@ void HistoryWidget::onPhotoUploaded(MsgId newId, const MTPInputFile &file) {
uint64 randomId = MTP::nonce<uint64>();
App::historyRegRandom(randomId, newId);
MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedPhoto(file), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId));
History *hist = item->history();
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedPhoto(file), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
}
@ -2867,7 +2880,8 @@ void HistoryWidget::onDocumentUploaded(MsgId newId, const MTPInputFile &file) {
uint64 randomId = MTP::nonce<uint64>();
App::historyRegRandom(randomId, newId);
DocumentData *document = media->document();
MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedDocument(file, MTP_string(document->name), MTP_string(document->mime)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId));
History *hist = item->history();
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedDocument(file, MTP_string(document->name), MTP_string(document->mime)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
}
}
@ -2883,7 +2897,8 @@ void HistoryWidget::onThumbDocumentUploaded(MsgId newId, const MTPInputFile &fil
uint64 randomId = MTP::nonce<uint64>();
App::historyRegRandom(randomId, newId);
DocumentData *document = media->document();
MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedThumbDocument(file, thumb, MTP_string(document->name), MTP_string(document->mime)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId));
History *hist = item->history();
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedThumbDocument(file, thumb, MTP_string(document->name), MTP_string(document->mime)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
}
}
@ -3114,11 +3129,11 @@ void HistoryWidget::onFieldTabbed() {
if (isImg) {
QImage img(cWorkingDir() + fname);
if (!img.isNull()) {
_field.setPlainText(text);
setFieldText(text);
uploadImage(img, !text.isEmpty());
}
} else {
_field.setPlainText(text);
setFieldText(text);
uploadFile(cWorkingDir() + fname, !text.isEmpty());
}
} else if (isContact) {
@ -3130,13 +3145,12 @@ void HistoryWidget::onFieldTabbed() {
}
QStringList data = contact.split(QChar(' '));
if (data.size() > 1) {
_field.setPlainText(text);
setFieldText(text);
QString phone = data.at(0).trimmed(), fname = data.at(1).trimmed(), lname = (data.size() > 2) ? static_cast<QStringList>(data.mid(2)).join(QChar(' ')).trimmed() : QString();
shareContactConfirmation(phone, fname, lname, !text.isEmpty());
}
} else {
_field.setPlainText(t);
setFieldText(t);
QTextCursor c = _field.textCursor();
c.movePosition(QTextCursor::End);
_field.setTextCursor(c);
@ -3144,6 +3158,12 @@ void HistoryWidget::onFieldTabbed() {
}
}
void HistoryWidget::setFieldText(const QString &text) {
noTypingUpdate = true;
_field.setPlainText(text);
noTypingUpdate = false;
}
void HistoryWidget::peerUpdated(PeerData *data) {
if (data && data == histPeer) {
updateListSize();
@ -3203,7 +3223,7 @@ void HistoryWidget::onDeleteContextSure() {
}
if (item->id > 0) {
MTP::send(MTPmessages_DeleteMessages(MTP_vector<MTPint>(QVector<MTPint>(1, MTP_int(item->id)))));
MTP::send(MTPmessages_DeleteMessages(MTP_vector<MTPint>(1, MTP_int(item->id))));
}
item->destroy();
App::wnd()->hideLayer();

View File

@ -283,6 +283,7 @@ public:
QRect historyRect() const;
void updateTyping(bool typing = true);
void typingDone(const MTPBool &result, mtpRequestId req);
void destroyData();
void uploadImage(const QImage &img, bool withText = false);
@ -344,6 +345,8 @@ public slots:
void peerUpdated(PeerData *data);
void cancelTyping();
void onPhotoUploaded(MsgId msgId, const MTPInputFile &file);
void onDocumentUploaded(MsgId msgId, const MTPInputFile &file);
void onThumbDocumentUploaded(MsgId msgId, const MTPInputFile &file, const MTPInputFile &thumb);
@ -396,6 +399,8 @@ private:
void addMessagesToBack(const QVector<MTPMessage> &messages);
void chatLoaded(const MTPmessages_ChatFull &res);
void setFieldText(const QString &text);
QStringList getMediasFromMime(const QMimeData *d);
DragState getDragState(const QMimeData *d);
@ -457,5 +462,8 @@ private:
QTimer _animActiveTimer;
float64 _animActiveStart;
mtpRequestId _typingRequest;
QTimer _typingStopTimer;
};

View File

@ -344,3 +344,12 @@ QString logVectorLong(const QVector<MTPlong> &ids) {
}
return idsStr + "]";
}
QString logVectorLong(const QVector<uint64> &ids) {
if (!ids.size()) return "[void list]";
QString idsStr = QString("[%1").arg(*ids.cbegin());
for (QVector<uint64>::const_iterator i = ids.cbegin() + 1, e = ids.cend(); i != e; ++i) {
idsStr += QString(", %2").arg(*i);
}
return idsStr + "]";
}

View File

@ -72,6 +72,7 @@ inline const char *logBool(bool v) {
class MTPlong;
QString logVectorLong(const QVector<MTPlong> &ids);
QString logVectorLong(const QVector<uint64> &ids);
#define LOG(msg) (logWrite(QString msg))
//usage LOG(("log: %1 %2").arg(1).arg(2))

View File

@ -1,4 +1,4 @@
/*
/*
This file is part of Telegram Desktop,
an unofficial desktop messaging app, see https://telegram.org
@ -275,7 +275,7 @@ MainWidget *TopBarWidget::main() {
MainWidget::MainWidget(Window *window) : QWidget(window), failedObjId(0), _dialogsWidth(st::dlgMinWidth),
dialogs(this), history(this), profile(0), overview(0), _topBar(this), hider(0), _mediaType(this), _mediaTypeMask(0),
updPts(0), updDate(0), updQts(0), updSeq(0), updInited(false), onlineRequest(0) {
updPts(0), updDate(0), updQts(-1), updSeq(0), updInited(false), onlineRequest(0), _failDifferenceTimeout(1) {
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
connect(window, SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &)));
@ -285,6 +285,8 @@ dialogs(this), history(this), profile(0), overview(0), _topBar(this), hider(0),
connect(&noUpdatesTimer, SIGNAL(timeout()), this, SLOT(getDifference()));
connect(&onlineTimer, SIGNAL(timeout()), this, SLOT(setOnline()));
connect(&onlineUpdater, SIGNAL(timeout()), this, SLOT(updateOnlineDisplay()));
connect(&_bySeqTimer, SIGNAL(timeout()), this, SLOT(getDifference()));
connect(&_failDifferenceTimer, SIGNAL(timeout()), this, SLOT(getDifferenceForce()));
connect(this, SIGNAL(peerUpdated(PeerData*)), &history, SLOT(peerUpdated(PeerData*)));
connect(&_topBar, SIGNAL(clicked()), this, SLOT(onTopBarClick()));
connect(&history, SIGNAL(peerShown(PeerData*)), this, SLOT(onPeerShown(PeerData*)));
@ -298,6 +300,8 @@ dialogs(this), history(this), profile(0), overview(0), _topBar(this), hider(0),
onlineTimer.setSingleShot(true);
onlineUpdater.setSingleShot(true);
updateNotifySettingTimer.setSingleShot(true);
_bySeqTimer.setSingleShot(true);
_failDifferenceTimer.setSingleShot(true);
dialogs.show();
history.show();
@ -413,7 +417,7 @@ void MainWidget::deleteHistory(PeerData *peer, const MTPmessages_StatedMessage &
void MainWidget::deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHistory &result) {
const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory());
App::main()->updUpdated(d.vpts.v, 0, 0, d.vseq.v);
App::main()->updUpdated(d.vpts.v, d.vseq.v);
int32 offset = d.voffset.v;
if (!MTP::authedId() || offset <= 0) return;
@ -423,13 +427,13 @@ void MainWidget::deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHis
void MainWidget::deletedContact(UserData *user, const MTPcontacts_Link &result) {
const MTPDcontacts_link &d(result.c_contacts_link());
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, d.vuser)));
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser));
App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link);
}
void MainWidget::deleteHistoryAndContact(UserData *user, const MTPcontacts_Link &result) {
const MTPDcontacts_link &d(result.c_contacts_link());
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, d.vuser)));
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser));
App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link);
if ((profile && profile->peer() == user) || (overview && overview->peer() == user) || _stack.contains(user) || history.peer() == user) {
@ -546,27 +550,30 @@ DialogsIndexed &MainWidget::contactsList() {
return dialogs.contactsList();
}
void MainWidget::sendMessage(History *hist, const QString &text) {
readServerHistory(hist, false);
QString msg = history.prepareMessage(text);
if (!msg.isEmpty()) {
void MainWidget::sendPreparedText(History *hist, const QString &text) {
QString sendingText, leftText = text;
while (textSplit(sendingText, leftText, MaxMessageSize)) {
MsgId newId = clientMsgId();
uint64 randomId = MTP::nonce<uint64>();
App::historyRegRandom(randomId, newId);
hist->loadAround(0);
MTPstring msgText(MTP_string(msg));
App::historyRegRandom(randomId, newId);
MTPstring msgText(MTP_string(sendingText));
int32 flags = 0x01 | 0x02; // unread, out
hist->addToBack(MTP_message(MTP_int(flags), MTP_int(newId), MTP_int(MTP::authedId()), App::peerToMTP(hist->peer->id), MTP_int(unixtime()), msgText, MTP_messageMediaEmpty()));
historyToDown(hist);
if (history.peer() == hist->peer) {
history.peerMessagesUpdated();
}
MTP::send(MTPmessages_SendMessage(hist->peer->input, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId));
}
hist->sendRequestId = MTP::send(MTPmessages_SendMessage(hist->peer->input, msgText, MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
}
historyToDown(hist);
if (history.peer() == hist->peer) {
history.peerMessagesUpdated();
}
}
void MainWidget::sendMessage(History *hist, const QString &text) {
readServerHistory(hist, false);
hist->loadAround(0);
sendPreparedText(hist, history.prepareMessage(text));
}
void MainWidget::readServerHistory(History *hist, bool force) {
@ -574,7 +581,7 @@ void MainWidget::readServerHistory(History *hist, bool force) {
ReadRequests::const_iterator i = _readRequests.constFind(hist->peer);
if (i == _readRequests.cend()) {
hist->inboxRead(true);
hist->inboxRead(0);
_readRequests.insert(hist->peer, MTP::send(MTPmessages_ReadHistory(hist->peer->input, MTP_int(0), MTP_int(0), MTP_bool(true)), rpcDone(&MainWidget::partWasRead, hist->peer)));
}
}
@ -823,7 +830,7 @@ void MainWidget::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpR
void MainWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result) {
const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory());
App::main()->updUpdated(d.vpts.v, 0, 0, d.vseq.v);
App::main()->updUpdated(d.vpts.v, d.vseq.v);
int32 offset = d.voffset.v;
if (!MTP::authedId() || offset <= 0) {
@ -1270,12 +1277,15 @@ void MainWidget::sentDataReceived(uint64 randomId, const MTPmessages_SentMessage
case mtpc_messages_sentMessage: {
const MTPDmessages_sentMessage &d(result.c_messages_sentMessage());
if (randomId) feedUpdate(MTP_updateMessageID(d.vid, MTP_long(randomId))); // ignore real date
if (updInited && d.vseq.v) {
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) return getDifference();
if (d.vseq.v > updSeq + 1) {
_bySeqSentMessage.insert(d.vseq.v, result);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
feedUpdate(MTP_updateMessageID(d.vid, MTP_long(randomId))); // ignore real date
if (updInited) {
updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v);
}
@ -1284,12 +1294,15 @@ void MainWidget::sentDataReceived(uint64 randomId, const MTPmessages_SentMessage
case mtpc_messages_sentMessageLink: {
const MTPDmessages_sentMessageLink &d(result.c_messages_sentMessageLink());
if (randomId) feedUpdate(MTP_updateMessageID(d.vid, MTP_long(randomId))); // ignore real date
if (updInited && d.vseq.v) {
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) return getDifference();
if (d.vseq.v > updSeq + 1) {
_bySeqSentMessage.insert(d.vseq.v, result);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
feedUpdate(MTP_updateMessageID(d.vid, MTP_long(randomId))); // ignore real date
if (updInited) {
updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v);
}
@ -1330,7 +1343,11 @@ void MainWidget::sentFullDataReceived(uint64 randomId, const MTPmessages_StatedM
App::feedMessageMedia(msgId, *msg);
}
if (updInited && d.vseq.v) {
if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference();
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) {
_bySeqStatedMessage.insert(d.vseq.v, result);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
if (!randomId) {
feedUpdate(MTP_updateNewMessage(d.vmessage, d.vpts));
@ -1349,7 +1366,11 @@ void MainWidget::sentFullDataReceived(uint64 randomId, const MTPmessages_StatedM
App::feedMessageMedia(msgId, *msg);
}
if (updInited && d.vseq.v) {
if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference();
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) {
_bySeqStatedMessage.insert(d.vseq.v, result);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
if (!randomId) {
feedUpdate(MTP_updateNewMessage(d.vmessage, d.vpts));
@ -1368,7 +1389,11 @@ void MainWidget::sentFullDatasReceived(const MTPmessages_StatedMessages &result)
case mtpc_messages_statedMessages: {
const MTPDmessages_statedMessages &d(result.c_messages_statedMessages());
if (updInited && d.vseq.v) {
if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference();
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) {
_bySeqStatedMessages.insert(d.vseq.v, result);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
App::feedUsers(d.vusers);
@ -1385,7 +1410,11 @@ void MainWidget::sentFullDatasReceived(const MTPmessages_StatedMessages &result)
const MTPDmessages_statedMessagesLinks &d(result.c_messages_statedMessagesLinks());
if (updInited && d.vseq.v) {
if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference();
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) {
_bySeqStatedMessages.insert(d.vseq.v, result);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
App::feedUsers(d.vusers);
@ -1620,8 +1649,78 @@ bool MainWidget::updateFail(const RPCError &e) {
void MainWidget::updSetState(int32 pts, int32 date, int32 qts, int32 seq) {
if (updPts < pts) updPts = pts;
if (updDate < date) updDate = date;
if (updQts < qts) updQts = qts;
if (seq) updSeq = seq;
if (qts && updQts < qts) {
updQts = qts;
}
if (seq && seq != updSeq) {
updSeq = seq;
if (_bySeqTimer.isActive()) _bySeqTimer.stop();
for (QMap<int32, MTPUpdates>::iterator i = _bySeqUpdates.begin(); i != _bySeqUpdates.end();) {
int32 s = i.key();
if (s <= seq + 1) {
MTPUpdates v = i.value();
i = _bySeqUpdates.erase(i);
if (s == seq + 1) {
return handleUpdates(v);
}
} else {
if (!_bySeqTimer.isActive()) _bySeqTimer.start(WaitForSeqTimeout);
break;
}
}
for (QMap<int32, MTPmessages_SentMessage>::iterator i = _bySeqSentMessage.begin(); i != _bySeqSentMessage.end();) {
int32 s = i.key();
if (s <= seq + 1) {
MTPmessages_SentMessage v = i.value();
i = _bySeqSentMessage.erase(i);
if (s == seq + 1) {
return sentDataReceived(0, v);
}
} else {
if (!_bySeqTimer.isActive()) _bySeqTimer.start(WaitForSeqTimeout);
break;
}
}
for (QMap<int32, MTPmessages_StatedMessage>::iterator i = _bySeqStatedMessage.begin(); i != _bySeqStatedMessage.end();) {
int32 s = i.key();
if (s <= seq + 1) {
MTPmessages_StatedMessage v = i.value();
i = _bySeqStatedMessage.erase(i);
if (s == seq + 1) {
return sentFullDataReceived(0, v);
}
} else {
if (!_bySeqTimer.isActive()) _bySeqTimer.start(WaitForSeqTimeout);
break;
}
}
for (QMap<int32, MTPmessages_StatedMessages>::iterator i = _bySeqStatedMessages.begin(); i != _bySeqStatedMessages.end();) {
int32 s = i.key();
if (s <= seq + 1) {
MTPmessages_StatedMessages v = i.value();
i = _bySeqStatedMessages.erase(i);
if (s == seq + 1) {
return sentFullDatasReceived(v);
}
} else {
if (!_bySeqTimer.isActive()) _bySeqTimer.start(WaitForSeqTimeout);
break;
}
}
for (QMap<int32, int32>::iterator i = _bySeqPart.begin(); i != _bySeqPart.end();) {
int32 s = i.key();
if (s <= seq + 1) {
int32 v = i.value();
i = _bySeqPart.erase(i);
if (s == seq + 1) {
return updUpdated(v, s);
}
} else {
if (!_bySeqTimer.isActive()) _bySeqTimer.start(WaitForSeqTimeout);
break;
}
}
}
}
void MainWidget::gotState(const MTPupdates_State &state) {
@ -1637,6 +1736,8 @@ void MainWidget::gotState(const MTPupdates_State &state) {
}
void MainWidget::gotDifference(const MTPupdates_Difference &diff) {
_failDifferenceTimeout = 1;
switch (diff.type()) {
case mtpc_updates_differenceEmpty: {
const MTPDupdates_differenceEmpty &d(diff.c_updates_differenceEmpty());
@ -1666,10 +1767,13 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) {
};
}
void MainWidget::updUpdated(int32 pts, int32 date, int32 qts, int32 seq) {
void MainWidget::updUpdated(int32 pts, int32 seq) {
if (!updInited) return;
if (seq && (seq < updSeq || seq > updSeq + 1)) return getDifference();
updSetState(pts, date, qts, seq);
if (seq && (seq < updSeq || seq > updSeq + 1)) {
_bySeqPart.insert(seq, pts);
return _bySeqTimer.start();
}
updSetState(pts, 0, 0, seq);
}
void MainWidget::feedDifference(const MTPVector<MTPUser> &users, const MTPVector<MTPChat> &chats, const MTPVector<MTPMessage> &msgs, const MTPVector<MTPUpdate> &other) {
@ -1683,15 +1787,31 @@ void MainWidget::feedDifference(const MTPVector<MTPUser> &users, const MTPVector
bool MainWidget::failDifference(const RPCError &e) {
LOG(("RPC Error: %1 %2: %3").arg(e.code()).arg(e.type()).arg(e.description()));
_failDifferenceTimer.start(_failDifferenceTimeout * 1000);
if (_failDifferenceTimeout < 64) _failDifferenceTimeout *= 2;
return true;
}
void MainWidget::getDifferenceForce() {
if (MTP::authedId()) {
updInited = true;
getDifference();
}
return true;
}
void MainWidget::getDifference() {
if (!updInited) return;
_bySeqUpdates.clear();
_bySeqSentMessage.clear();
_bySeqStatedMessage.clear();
_bySeqStatedMessages.clear();
_bySeqPart.clear();
_bySeqTimer.stop();
noUpdatesTimer.stop();
_failDifferenceTimer.stop();
updInited = false;
MTP::setGlobalDoneHandler(RPCDoneHandlerPtr(0));
MTP::send(MTPupdates_GetDifference(MTP_int(updPts), MTP_int(updDate), MTP_int(updQts)), rpcDone(&MainWidget::gotDifference), rpcFail(&MainWidget::failDifference));
@ -1700,7 +1820,7 @@ void MainWidget::getDifference() {
void MainWidget::start(const MTPUser &user) {
MTP::authed(user.c_userSelf().vid.v);
App::initMedia();
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, user)));
App::feedUsers(MTP_vector<MTPUser>(1, user));
App::app()->startUpdateCheck();
MTP::send(MTPupdates_GetState(), rpcDone(&MainWidget::gotState));
update();
@ -1913,82 +2033,101 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
noUpdatesTimer.start(NoUpdatesTimeout);
switch (updates.type()) {
case mtpc_updates: {
const MTPDupdates &d(updates.c_updates());
if (d.vseq.v) {
if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference();
}
App::feedChats(d.vchats);
App::feedUsers(d.vusers);
feedUpdates(d.vupdates);
updSetState(updPts, d.vdate.v, updQts, d.vseq.v);
} break;
case mtpc_updatesCombined: {
const MTPDupdatesCombined &d(updates.c_updatesCombined());
if (d.vseq.v) {
if (d.vseq_start.v <= updSeq || d.vseq_start.v > updSeq + 1) return getDifference();
}
App::feedChats(d.vchats);
App::feedUsers(d.vusers);
feedUpdates(d.vupdates);
updSetState(updPts, d.vdate.v, updQts, d.vseq.v);
} break;
case mtpc_updateShort: {
const MTPDupdateShort &d(updates.c_updateShort());
feedUpdate(d.vupdate);
updSetState(updPts, d.vdate.v, updQts, updSeq);
} break;
case mtpc_updateShortMessage: {
const MTPDupdateShortMessage &d(updates.c_updateShortMessage());
if (d.vseq.v) {
if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference();
}
if (!App::userLoaded(d.vfrom_id.v)) return getDifference();
int32 flags = 0x01; // unread
HistoryItem *item = App::histories().addToBack(MTP_message(MTP_int(flags), d.vid, d.vfrom_id, MTP_peerUser(MTP_int(MTP::authedId())), d.vdate, d.vmessage, MTP_messageMediaEmpty()));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v);
} break;
case mtpc_updateShortChatMessage: {
const MTPDupdateShortChatMessage &d(updates.c_updateShortChatMessage());
if (d.vseq.v) {
if (d.vseq.v <= updSeq || d.vseq.v > updSeq + 1) return getDifference();
}
if (!App::chatLoaded(d.vchat_id.v) || !App::userLoaded(d.vfrom_id.v)) return getDifference();
int32 flags = 0x01; // unread
HistoryItem *item = App::histories().addToBack(MTP_message(MTP_int(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vdate, d.vmessage, MTP_messageMediaEmpty()));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v);
} break;
case mtpc_updatesTooLong: {
return getDifference();
} break;
}
handleUpdates(updates);
} catch(mtpErrorUnexpected &e) { // just some other type
}
}
update();
/**/
}
void MainWidget::handleUpdates(const MTPUpdates &updates) {
switch (updates.type()) {
case mtpc_updates: {
const MTPDupdates &d(updates.c_updates());
if (d.vseq.v) {
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) {
_bySeqUpdates.insert(d.vseq.v, updates);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
App::feedChats(d.vchats);
App::feedUsers(d.vusers);
feedUpdates(d.vupdates);
updSetState(updPts, d.vdate.v, updQts, d.vseq.v);
} break;
case mtpc_updatesCombined: {
const MTPDupdatesCombined &d(updates.c_updatesCombined());
if (d.vseq_start.v) {
if (d.vseq_start.v <= updSeq) return;
if (d.vseq_start.v > updSeq + 1) {
_bySeqUpdates.insert(d.vseq_start.v, updates);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
App::feedChats(d.vchats);
App::feedUsers(d.vusers);
feedUpdates(d.vupdates);
updSetState(updPts, d.vdate.v, updQts, d.vseq.v);
} break;
case mtpc_updateShort: {
const MTPDupdateShort &d(updates.c_updateShort());
feedUpdate(d.vupdate);
updSetState(updPts, d.vdate.v, updQts, updSeq);
} break;
case mtpc_updateShortMessage: {
const MTPDupdateShortMessage &d(updates.c_updateShortMessage());
if (d.vseq.v) {
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) {
_bySeqUpdates.insert(d.vseq.v, updates);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
if (!App::userLoaded(d.vfrom_id.v)) return getDifference();
int32 flags = 0x01; // unread
HistoryItem *item = App::histories().addToBack(MTP_message(MTP_int(flags), d.vid, d.vfrom_id, MTP_peerUser(MTP_int(MTP::authedId())), d.vdate, d.vmessage, MTP_messageMediaEmpty()));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v);
} break;
case mtpc_updateShortChatMessage: {
const MTPDupdateShortChatMessage &d(updates.c_updateShortChatMessage());
if (d.vseq.v) {
if (d.vseq.v <= updSeq) return;
if (d.vseq.v > updSeq + 1) {
_bySeqUpdates.insert(d.vseq.v, updates);
return _bySeqTimer.start(WaitForSeqTimeout);
}
}
if (!App::chatLoaded(d.vchat_id.v) || !App::userLoaded(d.vfrom_id.v)) return getDifference();
int32 flags = 0x01; // unread
HistoryItem *item = App::histories().addToBack(MTP_message(MTP_int(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vdate, d.vmessage, MTP_messageMediaEmpty()));
if (item) {
history.peerMessagesUpdated(item->history()->peer->id);
}
updSetState(d.vpts.v, d.vdate.v, updQts, d.vseq.v);
} break;
case mtpc_updatesTooLong: {
return getDifference();
} break;
}
}
void MainWidget::feedUpdate(const MTPUpdate &update) {
@ -2176,7 +2315,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateNewEncryptedMessage: {
const MTPDupdateNewEncryptedMessage &d(update.c_updateNewEncryptedMessage());
if (updQts < d.vqts.v) updQts = d.vqts.v;
// if (d.vqts.v && updQts < d.vqts.v) updQts = d.vqts.v;
} break;
case mtpc_updateEncryptedChatTyping: {

View File

@ -197,7 +197,7 @@ public:
void historyToDown(History *hist);
void dialogsToUp();
void newUnreadMsg(History *history, MsgId msgId);
void updUpdated(int32 pts, int32 date, int32 qts, int32 seq);
void updUpdated(int32 pts, int32 seq);
void historyWasRead();
void peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg);
@ -266,6 +266,7 @@ public:
DialogsIndexed &contactsList();
void sendMessage(History *history, const QString &text);
void sendPreparedText(History *hist, const QString &text);
void readServerHistory(History *history, bool force = true);
@ -312,6 +313,7 @@ public slots:
void onParentResize(const QSize &newSize);
void getDifference();
void getDifferenceForce();
void setOnline(int windowState = -1);
void mainStateChanged(Qt::WindowState state);
@ -348,6 +350,7 @@ private:
void feedUpdate(const MTPUpdate &update);
void updateReceived(const mtpPrime *from, const mtpPrime *end);
void handleUpdates(const MTPUpdates &updates);
bool updateFail(const RPCError &e);
void hideAll();
@ -391,4 +394,14 @@ private:
typedef QMap<PeerData*, mtpRequestId> OverviewsPreload;
OverviewsPreload _overviewPreload[OverviewCount], _overviewLoad[OverviewCount];
QMap<int32, MTPUpdates> _bySeqUpdates;
QMap<int32, MTPmessages_SentMessage> _bySeqSentMessage;
QMap<int32, MTPmessages_StatedMessage> _bySeqStatedMessage;
QMap<int32, MTPmessages_StatedMessages> _bySeqStatedMessages;
QMap<int32, int32> _bySeqPart;
QTimer _bySeqTimer;
int32 _failDifferenceTimeout; // growing timeout for getDifference calls, if it fails
QTimer _failDifferenceTimer;
};

View File

@ -40,6 +40,7 @@ namespace {
typedef QMap<mtpRequestId, mtpRequest> RequestMap;
RequestMap requestMap;
QReadWriteLock requestMapLock;
typedef QPair<mtpRequestId, uint64> DelayedRequest;
typedef QList<DelayedRequest> DelayedRequestsList;
@ -63,7 +64,8 @@ namespace {
mtpAuthKey _localKey;
void importDone(const MTPauth_Authorization &result, mtpRequestId req) {
QMutexLocker locker(&requestByDCLock);
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));
@ -78,6 +80,7 @@ namespace {
DCAuthWaiters &waiters(authWaiters[newdc]);
MTProtoSessionPtr session(_mtp_internal::getSession(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);
@ -167,13 +170,18 @@ namespace {
}
}
RequestMap::const_iterator i = requestMap.constFind(requestId);
if (i == requestMap.cend()) {
LOG(("MTP Error: could not find request %1").arg(requestId));
return false;
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();
}
_mtp_internal::registerRequest(requestId, (dc < 0) ? -newdc : newdc);
_mtp_internal::getSession(newdc)->sendPrepared(i.value());
_mtp_internal::getSession(newdc)->sendPrepared(req);
return true;
} else if ((m = QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err)).hasMatch()) {
if (!requestId) return false;
@ -216,10 +224,15 @@ namespace {
if (badGuestDC) badGuestDCRequests.insert(requestId);
return true;
} else if (err == qsl("CONNECTION_NOT_INITED") || err == qsl("CONNECTION_LAYER_INVALID")) {
RequestMap::const_iterator i = requestMap.constFind(requestId);
if (i == requestMap.cend()) {
LOG(("MTP Error: could not find request %1").arg(requestId));
return false;
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 dc = 0;
{
@ -233,7 +246,66 @@ namespace {
}
if (!dc) return false;
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPreparedWithInit(i.value());
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPreparedWithInit(req);
return true;
} else if (err == qsl("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 dc = 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 {
dc = i.value();
if (i.value() != j.value()) {
req->after = mtpRequest();
}
}
}
if (!dc) return false;
if (!req->after) {
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPreparedWithInit(req);
} else {
int32 newdc = abs(dc) % _mtp_internal::dcShift;
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 {
uint64 at = 0;
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));
}
}
}
return true;
}
if (badGuestDC) badGuestDCRequests.remove(requestId);
@ -269,13 +341,13 @@ namespace _mtp_internal {
}
void unregisterRequest(mtpRequestId requestId) {
requestMap.remove(requestId);
{
QWriteLocker locker(&requestMapLock);
requestMap.remove(requestId);
}
QMutexLocker locker(&requestByDCLock);
RequestsByDC::iterator i = requestsByDC.find(requestId);
if (i != requestsByDC.end()) {
requestsByDC.erase(i);
}
requestsByDC.remove(requestId);
}
uint32 getLayer() {
@ -289,15 +361,39 @@ namespace _mtp_internal {
QMutexLocker locker(&parserMapLock);
parserMap.insert(res, parser);
}
requestMap.insert(res, request);
{
QWriteLocker locker(&requestMapLock);
requestMap.insert(res, request);
}
return res;
}
void replaceRequest(mtpRequest &newRequest, const mtpRequest &oldRequest) {
newRequest->requestId = oldRequest->requestId;
RequestMap::iterator i = requestMap.find(oldRequest->requestId);
if (i != requestMap.cend()) {
i.value() = newRequest;
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) {
mtpMsgId afterId(*(mtpMsgId*)(from->after->data() + 4));
mtpRequestMap::const_iterator i = afterId ? haveSent.constFind(afterId) : haveSent.cend();
int32 size = to->size(), len = (*from)[7] >> 2, headlen = 4, fulllen = headlen + len;
if (i == haveSent.constEnd()) { // no invoke after or such msg was not sent or was completed recently
to->resize(size + fulllen);
memcpy(to->data() + size, from->constData() + 4, fulllen * sizeof(mtpPrime));
} else {
to->resize(size + fulllen + 3);
memcpy(to->data() + size, from->constData() + 4, headlen * sizeof(mtpPrime));
(*to)[size + 3] += 3 * sizeof(mtpPrime);
*((mtpTypeId*)&((*to)[size + headlen])) = mtpc_invokeAfterMsg;
memcpy(to->data() + size + headlen + 1, &afterId, 2 * sizeof(mtpPrime));
memcpy(to->data() + size + headlen + 3, from->constData() + 4 + headlen, len * sizeof(mtpPrime));
if (size + 3 != 7) (*to)[7] += 3 * sizeof(mtpPrime);
}
}
@ -317,7 +413,6 @@ namespace _mtp_internal {
if (errorCode && found) {
rpcErrorOccured(requestId, h, rpcClientError("CLEAR_CALLBACK", QString("did not handle request %1, error code %2").arg(requestId).arg(errorCode)));
}
_mtp_internal::unregisterRequest(requestId);
}
void clearCallbacksDelayed(const RPCCallbackClears &requestIds) {
@ -353,6 +448,7 @@ namespace _mtp_internal {
}
}
clearCallbacks(i->requestId, i->errorCode);
_mtp_internal::unregisterRequest(i->requestId);
}
toClear.clear();
}
@ -443,12 +539,17 @@ namespace _mtp_internal {
}
}
RequestMap::const_iterator j = requestMap.constFind(requestId);
if (j == requestMap.cend()) {
DEBUG_LOG(("MTP Error: could not find request %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();
}
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPrepared(j.value(), 0, false);
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPrepared(req, 0, false);
}
if (!delayedRequests.isEmpty()) {
@ -577,11 +678,21 @@ namespace MTP {
}
void cancel(mtpRequestId requestId) {
mtpMsgId msgId = 0;
{
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()) {
_mtp_internal::getSession(abs(i.value()))->cancel(requestId);
_mtp_internal::getSession(abs(i.value()))->cancel(requestId, msgId);
requestsByDC.erase(i);
}
}
_mtp_internal::clearCallbacks(requestId);

View File

@ -31,7 +31,8 @@ namespace _mtp_internal {
static const uint32 dcShift = 10000;
mtpRequestId storeRequest(mtpRequest &request, const RPCResponseHandler &parser);
void replaceRequest(mtpRequest &newRequest, const mtpRequest &oldRequest);
mtpRequest getRequest(mtpRequestId req);
void wrapInvokeAfter(mtpRequest &to, const mtpRequest &from, const mtpRequestMap &haveSent);
void clearCallbacks(mtpRequestId requestId, int32 errorCode = RPCError::NoError); // 0 - do not toggle onError callback
void clearCallbacksDelayed(const RPCCallbackClears &requestIds);
void performDelayedClear();
@ -85,12 +86,12 @@ namespace MTP {
QString dctransport(int32 dc = 0);
void initdc(int32 dc);
template <typename TRequest>
inline mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), int32 dc = 0, uint64 msCanWait = 0) {
return _mtp_internal::getSession(dc)->send(request, callbacks, msCanWait, _mtp_internal::getLayer(), !dc);
inline mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {
return _mtp_internal::getSession(dc)->send(request, callbacks, msCanWait, _mtp_internal::getLayer(), !dc, after);
}
template <typename TRequest>
inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, uint64 msCanWait = 0) {
return send(request, RPCResponseHandler(onDone, onFail), dc, msCanWait);
inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {
return send(request, RPCResponseHandler(onDone, onFail), dc, msCanWait, after);
}
void cancel(mtpRequestId req);
void killSession(int32 dc);

View File

@ -1051,7 +1051,6 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
, oldConnection(true)
, receiveDelay(MinReceiveDelay)
, firstSentAt(-1)
, ackRequest(MTP_msgs_ack(MTPVector<MTPlong>()))
, pingId(0)
, toSendPingId(0)
, pingMsgId(0)
@ -1059,9 +1058,8 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
, keyId(0)
, sessionData(data)
, myKeyLock(false)
, authKeyData(0) {
ackRequestData = &ackRequest._msgs_ack().vmsg_ids._vector().v;
, authKeyData(0)
, authKeyStrings(0) {
oldConnectionTimer.moveToThread(thread);
connCheckTimer.moveToThread(thread);
@ -1258,6 +1256,13 @@ void MTProtoConnectionPrivate::resetSession() { // recreate all msg_id and msg_s
}
}
ackRequestData.clear();
resendRequestData.clear();
{
QWriteLocker locker5(sessionData->stateRequestMutex());
sessionData->stateRequestMap().clear();
}
emit sessionResetDone();
}
@ -1341,31 +1346,36 @@ mtpMsgId MTProtoConnectionPrivate::replaceMsgId(mtpRequest &request, mtpMsgId ne
return newId;
}
mtpMsgId MTProtoConnectionPrivate::placeToContainer(mtpRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, mtpRequest &req) {
mtpMsgId msgId = prepareToSend(req, bigMsgId);
if (msgId > bigMsgId) msgId = replaceMsgId(req, bigMsgId);
if (msgId >= bigMsgId) bigMsgId = msgid();
*(haveSentArr++) = msgId;
uint32 from = toSendRequest->size(), len = mtpRequestData::messageSize(req);
toSendRequest->resize(from + len);
memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime));
return msgId;
}
void MTProtoConnectionPrivate::tryToSend() {
if (!conn) return;
bool prependOnly = false, havePrepend = false;
mtpRequest prepend;
bool prependOnly = false;
mtpRequest pingRequest;
if (toSendPingId) {
/*
MTPPing_delay_disconnect ping;
ping.ping_id = MTP_long(toSendPingId);
ping.disconnect_delay.v = 45;
DEBUG_LOG(("MTP Info: sending ping_delay_disconnect, delay: %1s, ping_id: %2").arg(ping.disconnect_delay.v).arg(ping.ping_id.v));
/**/
MTPPing ping(MTPping(MTP_long(toSendPingId)));
prependOnly = (getState() != MTProtoConnection::Connected);
DEBUG_LOG(("MTP Info: sending ping, ping_id: %1, prepend_only: %2").arg(ping.vping_id.v).arg(prependOnly ? "[TRUE]" : "[FALSE]"));
uint32 pingSize = ping.size() >> 2; // copy from MTProtoSession::send
prepend = mtpRequestData::prepare(pingSize);
ping.write(*prepend);
pingRequest = mtpRequestData::prepare(pingSize);
ping.write(*pingRequest);
prepend->msDate = getms(); // > 0 - can send without container
prepend->requestId = 0; // dont add to haveSent / wereAcked maps
havePrepend = true;
pingRequest->msDate = getms(); // > 0 - can send without container
pingRequest->requestId = 0; // dont add to haveSent / wereAcked maps
pingId = toSendPingId;
toSendPingId = 0;
@ -1377,6 +1387,53 @@ void MTProtoConnectionPrivate::tryToSend() {
}
}
mtpRequest ackRequest, resendRequest, stateRequest;
if (!prependOnly && !ackRequestData.isEmpty()) {
MTPMsgsAck ack(MTP_msgs_ack(MTP_vector<MTPlong>(ackRequestData)));
ackRequest = mtpRequestData::prepare(ack.size() >> 2);
ack.write(*ackRequest);
ackRequest->msDate = getms(); // > 0 - can send without container
ackRequest->requestId = 0; // dont add to haveSent / wereAcked maps
ackRequestData.clear();
}
if (!prependOnly && !resendRequestData.isEmpty()) {
MTPMsgResendReq resend(MTP_msg_resend_req(MTP_vector<MTPlong>(resendRequestData)));
resendRequest = mtpRequestData::prepare(resend.size() >> 2);
resend.write(*resendRequest);
resendRequest->msDate = getms(); // > 0 - can send without container
resendRequest->requestId = 0; // dont add to haveSent / wereAcked maps
resendRequestData.clear();
}
if (!prependOnly) {
QVector<MTPlong> stateReq;
{
QWriteLocker locker(sessionData->stateRequestMutex());
mtpMsgIdsSet &ids(sessionData->stateRequestMap());
if (!ids.isEmpty()) {
stateReq.reserve(ids.size());
for (mtpMsgIdsSet::const_iterator i = ids.cbegin(), e = ids.cend(); i != e; ++i) {
stateReq.push_back(MTP_long(i.key()));
}
}
ids.clear();
}
if (!stateReq.isEmpty()) {
MTPMsgsStateReq req(MTP_msgs_state_req(MTP_vector<MTPlong>(stateReq)));
stateRequest = mtpRequestData::prepare(req.size() >> 2);
req.write(*stateRequest);
stateRequest->msDate = getms(); // > 0 - can send without container
stateRequest->requestId = reqid();// add to haveSent / wereAcked maps, but don't add to requestMap
}
}
bool needAnyResponse = false;
mtpRequest toSendRequest;
{
@ -1386,11 +1443,14 @@ void MTProtoConnectionPrivate::tryToSend() {
if (prependOnly) locker1.unlock();
uint32 toSendCount = toSend.size();
if (havePrepend) ++toSendCount;
if (pingRequest) ++toSendCount;
if (ackRequest) ++toSendCount;
if (resendRequest) ++toSendCount;
if (stateRequest) ++toSendCount;
if (!toSendCount) return; // nothing to send
mtpRequest first = havePrepend ? prepend : toSend.cbegin().value();
mtpRequest first = pingRequest ? pingRequest : (ackRequest ? ackRequest : (resendRequest ? resendRequest : (stateRequest ? stateRequest : toSend.cbegin().value())));
if (toSendCount == 1 && first->msDate > 0) { // if can send without container
toSendRequest = first;
if (!prependOnly) {
@ -1399,14 +1459,28 @@ void MTProtoConnectionPrivate::tryToSend() {
}
mtpMsgId msgId = prepareToSend(toSendRequest, msgid());
if (havePrepend) pingMsgId = msgId;
if (pingRequest) {
pingMsgId = msgId;
needAnyResponse = true;
} else if (resendRequest || stateRequest) {
needAnyResponse = true;
}
if (toSendRequest->requestId) {
if (mtpRequestData::needAck(toSendRequest)) {
toSendRequest->msDate = mtpRequestData::isStateRequest(toSendRequest) ? 0 : getms();
QWriteLocker locker2(sessionData->haveSentMutex());
sessionData->haveSentMap().insert(msgId, toSendRequest);
mtpRequestMap &haveSent(sessionData->haveSentMap());
haveSent.insert(msgId, toSendRequest);
if (toSendRequest->after) {
int32 toSendSize = toSendRequest->at(7) >> 2;
mtpRequest wrappedRequest(mtpRequestData::prepare(toSendSize, toSendSize + 3)); // cons + msg_id
wrappedRequest->resize(4);
memcpy(wrappedRequest->data(), toSendRequest->constData(), 4 * sizeof(mtpPrime));
_mtp_internal::wrapInvokeAfter(wrappedRequest, toSendRequest, haveSent);
toSendRequest = wrappedRequest;
}
needAnyResponse = true;
} else {
@ -1416,11 +1490,14 @@ void MTProtoConnectionPrivate::tryToSend() {
}
} else { // send in container
uint32 containerSize = 1 + 1, idsWrapSize = (toSendCount << 1); // cons + vector size, idsWrapSize - size of "request-like" wrap for msgId vector
if (havePrepend) containerSize += mtpRequestData::messageSize(prepend);
if (pingRequest) containerSize += mtpRequestData::messageSize(pingRequest);
if (ackRequest) containerSize += mtpRequestData::messageSize(ackRequest);
if (resendRequest) containerSize += mtpRequestData::messageSize(resendRequest);
if (stateRequest) containerSize += mtpRequestData::messageSize(stateRequest);
for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) {
containerSize += mtpRequestData::messageSize(i.value());
}
toSendRequest = mtpRequestData::prepare(containerSize); // prepare container
toSendRequest = mtpRequestData::prepare(containerSize, containerSize + 3 * toSend.size()); // prepare container + each in invoke after
toSendRequest->push_back(mtpc_msg_container);
toSendRequest->push_back(toSendCount);
@ -1437,17 +1514,10 @@ void MTProtoConnectionPrivate::tryToSend() {
haveSentIdsWrap->resize(haveSentIdsWrap->size() + idsWrapSize);
mtpMsgId *haveSentArr = (mtpMsgId*)(haveSentIdsWrap->data() + 8);
if (havePrepend) {
mtpMsgId msgId = prepareToSend(prepend, bigMsgId);
if (msgId > bigMsgId) msgId = replaceMsgId(prepend, bigMsgId);
if (msgId >= bigMsgId) bigMsgId = msgid();
*(haveSentArr++) = msgId;
if (havePrepend) pingMsgId = msgId;
uint32 from = toSendRequest->size(), len = mtpRequestData::messageSize(prepend);
toSendRequest->resize(from + len);
memcpy(toSendRequest->data() + from, prepend->constData() + 4, len * sizeof(mtpPrime));
if (pingRequest) {
pingMsgId = placeToContainer(toSendRequest, bigMsgId, haveSentArr, pingRequest);
needAnyResponse = true;
} else if (resendRequest || stateRequest) {
needAnyResponse = true;
}
for (mtpPreRequestMap::iterator i = toSend.begin(), e = toSend.end(); i != e; ++i) {
@ -1456,10 +1526,14 @@ void MTProtoConnectionPrivate::tryToSend() {
if (msgId > bigMsgId) msgId = replaceMsgId(req, bigMsgId);
if (msgId >= bigMsgId) bigMsgId = msgid();
*(haveSentArr++) = msgId;
bool added = false;
if (req->requestId) {
if (mtpRequestData::needAck(req)) {
req->msDate = mtpRequestData::isStateRequest(req) ? 0 : getms();
if (req->after) {
_mtp_internal::wrapInvokeAfter(toSendRequest, req, haveSent);
added = true;
}
haveSent.insert(msgId, req);
needAnyResponse = true;
@ -1467,10 +1541,19 @@ void MTProtoConnectionPrivate::tryToSend() {
wereAcked.insert(msgId, req->requestId);
}
}
uint32 from = toSendRequest->size(), len = mtpRequestData::messageSize(req);
toSendRequest->resize(from + len);
memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime));
if (!added) {
uint32 from = toSendRequest->size(), len = mtpRequestData::messageSize(req);
toSendRequest->resize(from + len);
memcpy(toSendRequest->data() + from, req->constData() + 4, len * sizeof(mtpPrime));
}
}
if (stateRequest) {
mtpMsgId msgId = placeToContainer(toSendRequest, bigMsgId, haveSentArr, stateRequest);
stateRequest->msDate = 0; // 0 for state request, do not request state of it
haveSent.insert(msgId, stateRequest);
}
if (resendRequest) placeToContainer(toSendRequest, bigMsgId, haveSentArr, resendRequest);
if (ackRequest) placeToContainer(toSendRequest, bigMsgId, haveSentArr, ackRequest);
mtpMsgId contMsgId = prepareToSend(toSendRequest, bigMsgId);
*(mtpMsgId*)(haveSentIdsWrap->data() + 4) = contMsgId;
@ -1760,7 +1843,7 @@ void MTProtoConnectionPrivate::handleReceived() {
serverSalt = 0; // dont pass to handle method, so not to lock in setSalt()
}
if (needAck) ackRequestData->push_back(MTP_long(msgId));
if (needAck) ackRequestData.push_back(MTP_long(msgId));
int32 res = 1; // if no need to handle, then succeed
end = data + 8 + (msgLen >> 2);
@ -1770,7 +1853,7 @@ void MTProtoConnectionPrivate::handleReceived() {
bool needToHandle = false;
{
QWriteLocker lock(sessionData->receivedIdsMutex());
mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet());
mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet());
needToHandle = receivedIds.insert(msgId, needAck);
}
if (needToHandle) {
@ -1778,7 +1861,7 @@ void MTProtoConnectionPrivate::handleReceived() {
}
{
QWriteLocker lock(sessionData->receivedIdsMutex());
mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet());
mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet());
uint32 receivedIdsSize = receivedIds.size();
while (receivedIdsSize-- > MTPIdsBufferSize) {
receivedIds.erase(receivedIds.begin());
@ -1786,11 +1869,10 @@ void MTProtoConnectionPrivate::handleReceived() {
}
// send acks
uint32 toAckSize = ackRequestData->size();
uint32 toAckSize = ackRequestData.size();
if (toAckSize) {
DEBUG_LOG(("MTP Info: sending %1 acks, ids: %2").arg(toAckSize).arg(logVectorLong(*ackRequestData)));
sessionData->owner()->send(ackRequest, RPCResponseHandler(), 10000);
ackRequestData->clear();
DEBUG_LOG(("MTP Info: will send %1 acks, ids: %2").arg(toAckSize).arg(logVectorLong(ackRequestData)));
sessionData->owner()->sendAnything(MTPAckSendWaiting);
}
bool emitSignal = false;
@ -1867,7 +1949,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
}
bool needAck = (inSeqNo.v & 0x01);
if (needAck) ackRequestData->push_back(inMsgId);
if (needAck) ackRequestData.push_back(inMsgId);
DEBUG_LOG(("Message Info: message from container, msg_id: %1, needAck: %2").arg(inMsgId.v).arg(logBool(needAck)));
@ -1877,7 +1959,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
bool needToHandle = false;
{
QWriteLocker lock(sessionData->receivedIdsMutex());
mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet());
mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet());
needToHandle = receivedIds.insert(inMsgId.v, needAck);
}
int32 res = 1; // if no need to handle, then succeed
@ -1916,6 +1998,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
const MTPDbad_msg_notification &data(msg.c_bad_msg_notification());
LOG(("Message Info: bad message notification received (error_code %3) for msg_id = %1, seq_no = %2").arg(data.vbad_msg_id.v).arg(data.vbad_msg_seqno.v).arg(data.verror_code.v));
mtpMsgId resendId = data.vbad_msg_id.v;
int32 errorCode = data.verror_code.v;
if (errorCode == 16 || errorCode == 17 || errorCode == 32 || errorCode == 33 || errorCode == 64) { // can handle
bool needResend = (errorCode == 16 || errorCode == 17); // bad msg_id
@ -1927,12 +2010,12 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
QWriteLocker locker(sessionData->haveSentMutex());
mtpRequestMap &haveSent(sessionData->haveSentMap());
mtpRequestMap::iterator i = haveSent.find(msgId);
if (i == haveSent.end()) {
mtpRequestMap::const_iterator i = haveSent.constFind(resendId);
if (i == haveSent.cend()) {
LOG(("Message Error: Container not found!"));
} else {
request = i.value();
}
request = i.value();
}
if (request) {
if (mtpRequestData::isSentContainer(request)) {
@ -1949,7 +2032,6 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
}
}
mtpMsgId resendId = data.vbad_msg_id.v;
if (!wasSent(resendId)) {
DEBUG_LOG(("Message Error: such message was not sent recently %1").arg(resendId));
return (badTime ? 0 : 1);
@ -2029,8 +2111,8 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
{
QReadLocker lock(sessionData->receivedIdsMutex());
const mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet());
mtpMsgIdsSet::const_iterator receivedIdsEnd(receivedIds.cend());
const mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet());
mtpMsgIdsMap::const_iterator receivedIdsEnd(receivedIds.cend());
uint64 minRecv = receivedIds.min(), maxRecv = receivedIds.max();
QReadLocker locker(sessionData->wereAckedMutex());
@ -2045,7 +2127,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
} else if (reqMsgId > maxRecv) {
state |= 0x03;
} else {
mtpMsgIdsSet::const_iterator recv = receivedIds.constFind(reqMsgId);
mtpMsgIdsMap::const_iterator recv = receivedIds.constFind(reqMsgId);
if (recv == receivedIdsEnd) {
state |= 0x02;
} else {
@ -2074,7 +2156,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
uint64 reqMsgId = data.vreq_msg_id.v;
const string &states(data.vinfo.c_string().v);
DEBUG_LOG(("Message Info: msg state received, msgId %1, reqMsgId: %2, states %3").arg(msgId).arg(reqMsgId).arg(mb(states.data(), states.length()).str()));
DEBUG_LOG(("Message Info: msg state received, msgId %1, reqMsgId: %2, HEX states %3").arg(msgId).arg(reqMsgId).arg(mb(states.data(), states.length()).str()));
mtpRequest requestBuffer;
{ // find this request in session-shared sent requests map
QReadLocker locker(sessionData->haveSentMutex());
@ -2158,14 +2240,14 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
MTPlong resMsgId = data.vanswer_msg_id;
{
QReadLocker lock(sessionData->receivedIdsMutex());
const mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet());
const mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet());
received = (receivedIds.find(resMsgId.v) != receivedIds.cend()) && (receivedIds.min() < resMsgId.v);
}
if (!received) {
if (received) {
ackRequestData.push_back(resMsgId);
} else {
DEBUG_LOG(("Message Info: answer message %1 was not received, requesting..").arg(resMsgId.v));
MTPMsgResendReq resendRequest(MTP_msg_resend_req(MTPVector<MTPlong>(1)));
resendRequest._msg_resend_req().vmsg_ids._vector().v.push_back(resMsgId);
sessionData->owner()->send(resendRequest);
resendRequestData.push_back(resMsgId);
}
} return 1;
@ -2183,14 +2265,14 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
MTPlong resMsgId = data.vanswer_msg_id;
{
QReadLocker lock(sessionData->receivedIdsMutex());
const mtpMsgIdsSet &receivedIds(sessionData->receivedIdsSet());
const mtpMsgIdsMap &receivedIds(sessionData->receivedIdsSet());
received = (receivedIds.find(resMsgId.v) != receivedIds.cend()) && (receivedIds.min() < resMsgId.v);
}
if (!received) {
if (received) {
ackRequestData.push_back(resMsgId);
} else {
DEBUG_LOG(("Message Info: answer message %1 was not received, requesting..").arg(resMsgId.v));
MTPMsgResendReq resendRequest(MTP_msg_resend_req(MTPVector<MTPlong>(1)));
resendRequest._msg_resend_req().vmsg_ids._vector().v.push_back(resMsgId);
sessionData->owner()->send(resendRequest);
resendRequestData.push_back(resMsgId);
}
} return 1;
@ -2577,6 +2659,7 @@ void MTProtoConnectionPrivate::onConnected() {
}
authKeyData = new MTProtoConnectionPrivate::AuthKeyCreateData();
authKeyStrings = new MTProtoConnectionPrivate::AuthKeyCreateStrings();
authKeyData->req_num = 0;
authKeyData->nonce = MTP::nonce<MTPint128>();
@ -2815,9 +2898,9 @@ void MTProtoConnectionPrivate::dhParamsAnswered() {
return restart();
}
authKeyData->dh_prime = dhPrime;
authKeyStrings->dh_prime = QByteArray(dhPrime.data(), dhPrime.size());
authKeyData->g = dh_inner_data.vg.v;
authKeyData->g_a = g_a;
authKeyStrings->g_a = QByteArray(g_a.data(), g_a.size());
authKeyData->retry_id = MTP_long(0);
authKeyData->retries = 0;
} return dhClientParamsSend();
@ -2867,7 +2950,7 @@ void MTProtoConnectionPrivate::dhClientParamsSend() {
// count g_b and auth_key using openssl BIGNUM methods
_BigNumCounter bnCounter;
if (!bnCounter.count(b, &authKeyData->dh_prime[0], authKeyData->g, g_b, &authKeyData->g_a[0], authKeyData->auth_key)) {
if (!bnCounter.count(b, authKeyStrings->dh_prime.constData(), authKeyData->g, g_b, authKeyStrings->g_a.constData(), authKeyData->auth_key)) {
return dhClientParamsSend();
}
@ -3027,17 +3110,23 @@ void MTProtoConnectionPrivate::authKeyCreated() {
void MTProtoConnectionPrivate::clearAuthKeyData() {
if (authKeyData) {
#ifdef Q_OS_WIN // TODO
// SecureZeroMemory(authKeyData, sizeof(AuthKeyCreateData));
SecureZeroMemory(authKeyData, sizeof(AuthKeyCreateData));
if (!authKeyStrings->dh_prime.isEmpty()) SecureZeroMemory(authKeyStrings->dh_prime.data(), authKeyStrings->dh_prime.size());
if (!authKeyStrings->g_a.isEmpty()) SecureZeroMemory(authKeyStrings->g_a.data(), authKeyStrings->g_a.size());
#else
// memset(authKeyData, 0, sizeof(AuthKeyCreateData));
memset(authKeyData, 0, sizeof(AuthKeyCreateData));
if (!authKeyStrings->dh_prime.isEmpty()) memset(authKeyStrings->dh_prime.data(), 0, authKeyStrings->dh_prime.size());
if (!authKeyStrings->g_a.isEmpty()) memset(authKeyStrings->g_a.data(), 0, authKeyStrings->g_a.size());
#endif
delete authKeyData;
authKeyData = 0;
delete authKeyStrings;
authKeyStrings = 0;
}
}
void MTProtoConnectionPrivate::sendPing() {
sessionData->owner()->send(MTPPing(MTPping(MTP::nonce<MTPlong>())));
sessionData->owner()->send(MTPPing(MTP::nonce<MTPlong>()));
}
void MTProtoConnectionPrivate::onError(bool mayBeBadKey) {

View File

@ -333,6 +333,7 @@ private:
void createConn();
mtpMsgId placeToContainer(mtpRequest &toSendRequest, mtpMsgId &bigMsgId, mtpMsgId *&haveSentArr, mtpRequest &req);
mtpMsgId prepareToSend(mtpRequest &request, mtpMsgId currentLastId);
mtpMsgId replaceMsgId(mtpRequest &request, mtpMsgId newId);
@ -367,8 +368,7 @@ private:
uint32 receiveDelay;
int64 firstSentAt;
MTPMsgsAck ackRequest;
QVector<MTPlong> *ackRequestData;
QVector<MTPlong> ackRequestData, resendRequestData;
// if badTime received - search for ids in sessionData->haveSent and sessionData->wereAcked and sync time/salt, return true if found
bool requestsFixTimeSalt(const QVector<MTPlong> &ids, int32 serverTime, uint64 serverSalt);
@ -417,10 +417,8 @@ private:
uint32 retries;
MTPlong retry_id;
string dh_prime;
int32 g;
string g_a;
uchar aesKey[32], aesIV[32];
uint32 auth_key[64];
MTPlong auth_key_hash;
@ -428,7 +426,13 @@ private:
uint32 req_num; // sent not encrypted request number
uint32 msgs_sent;
};
struct AuthKeyCreateStrings {
QByteArray dh_prime;
QByteArray g_a;
};
AuthKeyCreateData *authKeyData;
AuthKeyCreateStrings *authKeyStrings;
void dhClientParamsSend();
void authKeyCreated();
void clearAuthKeyData();

View File

@ -75,13 +75,15 @@ public:
// in haveSent: = 0 - container with msgIds, > 0 - when was sent
uint64 msDate;
mtpRequestId requestId;
mtpRequest after;
mtpRequestData(bool/* sure*/) : msDate(0) {
mtpRequestData(bool/* sure*/) : msDate(0), requestId(0) {
}
static mtpRequest prepare(uint32 requestSize) {
static mtpRequest prepare(uint32 requestSize, uint32 maxSize = 0) {
if (!maxSize) maxSize = requestSize;
mtpRequest result(new mtpRequestData(true));
result->reserve(8 + requestSize + _padding(requestSize)); // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length
result->reserve(8 + maxSize + _padding(maxSize)); // 2: salt, 2: session_id, 2: msg_id, 1: seq_no, 1: message_length
result->resize(7);
result->push_back(requestSize << 2);
return result;
@ -150,8 +152,8 @@ public:
typedef QMap<mtpRequestId, mtpRequest> mtpPreRequestMap;
typedef QMap<mtpMsgId, mtpRequest> mtpRequestMap;
class mtpMsgIdsSet : public QMap<mtpMsgId, bool> {
typedef QMap<mtpMsgId, bool> mtpMsgIdsSet;
class mtpMsgIdsMap : public QMap<mtpMsgId, bool> {
public:
typedef QMap<mtpMsgId, bool> ParentType;
@ -172,12 +174,12 @@ public:
}
mtpMsgId min() const {
return size() ? cbegin().key() : 0;
return isEmpty() ? 0 : cbegin().key();
}
mtpMsgId max() const {
ParentType::const_iterator e(cend());
return size() ? (--e).key() : 0;
return isEmpty() ? 0 : (--e).key();
}
};
@ -815,6 +817,8 @@ public:
}
MTPDvector(uint32 count) : v(count) {
}
MTPDvector(uint32 count, const T &value) : v(count, value) {
}
MTPDvector(const QVector<T> &vec) : v(vec) {
}
@ -829,6 +833,9 @@ class MTPvector;
template <typename T>
MTPvector<T> MTP_vector(uint32 count);
template <typename T>
MTPvector<T> MTP_vector(uint32 count, const T &value);
template <typename T>
MTPvector<T> MTP_vector(const QVector<T> &v);
@ -886,6 +893,7 @@ private:
}
friend MTPvector<T> MTP_vector<T>(uint32 count);
friend MTPvector<T> MTP_vector<T>(uint32 count, const T &value);
friend MTPvector<T> MTP_vector<T>(const QVector<T> &v);
typedef typename MTPDvector<T>::VType VType;
};
@ -894,6 +902,10 @@ inline MTPvector<T> MTP_vector(uint32 count) {
return MTPvector<T>(new MTPDvector<T>(count));
}
template <typename T>
inline MTPvector<T> MTP_vector(uint32 count, const T &value) {
return MTPvector<T>(new MTPDvector<T>(count, value));
}
template <typename T>
inline MTPvector<T> MTP_vector(const QVector<T> &v) {
return MTPvector<T>(new MTPDvector<T>(v));
}
@ -904,6 +916,8 @@ public:
}
MTPVector(uint32 count) : MTPBoxed<MTPvector<T> >(MTP_vector<T>(count)) {
}
MTPVector(uint32 count, const T &value) : MTPBoxed<MTPvector<T> >(MTP_vector<T>(count, value)) {
}
MTPVector(const MTPvector<T> &v) : MTPBoxed<MTPvector<T> >(v) {
}
MTPVector(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPvector<T> >(from, end, cons) {

View File

@ -133,12 +133,35 @@ void MTProtoSession::stop() {
}
}
void MTProtoSession::checkRequestsByTimer() {
MTPMsgsStateReq stateRequest(MTP_msgs_state_req(MTP_vector<MTPlong>(0)));
QVector<MTPlong> &stateRequestIds(stateRequest._msgs_state_req().vmsg_ids._vector().v);
void MTProtoSession::sendAnything(uint64 msCanWait) {
uint64 ms = getms();
if (msSendCall) {
if (ms > msSendCall + msWait) {
msWait = 0;
} else {
msWait = (msSendCall + msWait) - ms;
if (msWait > msCanWait) {
msWait = msCanWait;
}
}
} else {
msWait = msCanWait;
}
if (msWait) {
msSendCall = ms;
emit startSendTimer(msWait);
DEBUG_LOG(("MTP Info: can wait for %1ms from current %2").arg(msWait).arg(msSendCall));
} else {
emit stopSendTimer();
msSendCall = 0;
emit needToSendAsync();
}
}
void MTProtoSession::checkRequestsByTimer() {
QVector<mtpMsgId> resendingIds;
QVector<mtpMsgId> removingIds; // remove very old (10 minutes) containers and resend requests
QVector<mtpMsgId> stateRequestIds;
{
QReadLocker locker(data.haveSentMutex());
@ -155,7 +178,7 @@ void MTProtoSession::checkRequestsByTimer() {
} else {
req->msDate = ms;
stateRequestIds.reserve(haveSentCount);
stateRequestIds.push_back(MTP_long(i.key()));
stateRequestIds.push_back(i.key());
}
}
} else if (unixtime() > (int32)(i.key() >> 32) + MTPContainerLives) {
@ -167,19 +190,26 @@ void MTProtoSession::checkRequestsByTimer() {
if (stateRequestIds.size()) {
DEBUG_LOG(("MTP Info: requesting state of msgs: %1").arg(logVectorLong(stateRequestIds)));
send(stateRequest, RPCResponseHandler(), MTPCheckResendWaiting);
{
QWriteLocker locker(data.stateRequestMutex());
for (uint32 i = 0, l = stateRequestIds.size(); i < l; ++i) {
data.stateRequestMap().insert(stateRequestIds[i], true);
}
}
sendAnything(MTPCheckResendWaiting);
}
for (uint32 i = 0, l = resendingIds.size(); i < l; ++i) {
DEBUG_LOG(("MTP Info: resending request %1").arg(resendingIds[i]));
resend(resendingIds[i], MTPCheckResendWaiting);
if (!resendingIds.isEmpty()) {
for (uint32 i = 0, l = resendingIds.size(); i < l; ++i) {
DEBUG_LOG(("MTP Info: resending request %1").arg(resendingIds[i]));
resend(resendingIds[i], MTPCheckResendWaiting);
}
}
uint32 removingIdsCount = removingIds.size();
if (removingIdsCount) {
if (!removingIds.isEmpty()) {
RPCCallbackClears clearCallbacks;
{
QWriteLocker locker(data.haveSentMutex());
mtpRequestMap &haveSent(data.haveSentMap());
for (uint32 i = 0; i < removingIdsCount; ++i) {
for (uint32 i = 0, l = removingIds.size(); i < l; ++i) {
mtpRequestMap::iterator j = haveSent.find(removingIds[i]);
if (j != haveSent.cend()) {
if (j.value()->requestId) {
@ -201,11 +231,15 @@ void MTProtoSession::onResetDone() {
_mtp_internal::onSessionReset(dcId);
}
void MTProtoSession::cancel(mtpRequestId requestId) {
QWriteLocker locker(data.toSendMutex());
mtpPreRequestMap &toSend(data.toSendMap());
mtpPreRequestMap::iterator i = toSend.find(requestId);
if (i != toSend.end()) toSend.erase(i);
void MTProtoSession::cancel(mtpRequestId requestId, mtpMsgId msgId) {
if (requestId) {
QWriteLocker locker(data.toSendMutex());
data.toSendMap().remove(requestId);
}
if (msgId) {
QWriteLocker locker(data.haveSentMutex());
data.haveSentMap().remove(msgId);
}
}
int32 MTProtoSession::requestState(mtpRequestId requestId) const {
@ -340,28 +374,7 @@ void MTProtoSession::sendPrepared(const mtpRequest &request, uint64 msCanWait, b
DEBUG_LOG(("MTP Info: added, requestId %1").arg(request->requestId));
uint64 ms = getms();
if (msSendCall) {
if (ms > msSendCall + msWait) {
msWait = 0;
} else {
msWait = (msSendCall + msWait) - ms;
if (msWait > msCanWait) {
msWait = msCanWait;
}
}
} else {
msWait = msCanWait;
}
if (msWait) {
msSendCall = ms;
emit startSendTimer(msWait);
DEBUG_LOG(("MTP Info: can wait for %1ms from current %2").arg(msWait).arg(msSendCall));
} else {
emit stopSendTimer();
msSendCall = 0;
emit needToSendAsync();
}
sendAnything(msCanWait);
}
void MTProtoSession::sendPreparedWithInit(const mtpRequest &request, uint64 msCanWait) { // returns true, if emit of needToSend() is needed
@ -369,14 +382,16 @@ void MTProtoSession::sendPreparedWithInit(const mtpRequest &request, uint64 msCa
sendPrepared(request, msCanWait, false);
return;
}
MTPInitConnection<mtpRequest> requestWrap(MTPinitConnection<mtpRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request));
uint32 requestSize = requestWrap.size() >> 2;
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize));
requestWrap.write(*reqSerialized);
reqSerialized->msDate = getms(); // > 0 - can send without container
_mtp_internal::replaceRequest(reqSerialized, request);
sendPrepared(reqSerialized, msCanWait);
{
MTPInitConnection<mtpRequest> requestWrap(MTPinitConnection<mtpRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request));
uint32 requestSize = requestWrap.size() >> 2;
mtpRequest reqSerialized(mtpRequestData::prepare(requestSize));
requestWrap.write(*reqSerialized);
request->resize(reqSerialized->size());
memcpy(request->data(), reqSerialized->constData(), reqSerialized->size());
}
request->msDate = getms(); // > 0 - can send without container
sendPrepared(request, msCanWait);
}
QReadWriteLock *MTProtoSession::keyMutex() const {

View File

@ -98,6 +98,9 @@ public:
QReadWriteLock *haveReceivedMutex() const {
return &haveReceivedLock;
}
QReadWriteLock *stateRequestMutex() const {
return &stateRequestLock;
}
mtpPreRequestMap &toSendMap() {
return toSend;
@ -117,10 +120,10 @@ public:
const mtpRequestIdsMap &toResendMap() const {
return toResend;
}
mtpMsgIdsSet &receivedIdsSet() {
mtpMsgIdsMap &receivedIdsSet() {
return receivedIds;
}
const mtpMsgIdsSet &receivedIdsSet() const {
const mtpMsgIdsMap &receivedIdsSet() const {
return receivedIds;
}
mtpRequestIdsMap &wereAckedMap() {
@ -135,6 +138,12 @@ public:
const mtpResponseMap &haveReceivedMap() const {
return haveReceived;
}
mtpMsgIdsSet &stateRequestMap() {
return stateRequest;
}
const mtpMsgIdsSet &stateRequestMap() const {
return stateRequest;
}
mtpRequestId nextFakeRequestId() { // must be locked by haveReceivedMutex()
if (haveReceived.isEmpty() || haveReceived.cbegin().key() > 0) {
@ -175,9 +184,10 @@ private:
mtpPreRequestMap toSend; // map of request_id -> request, that is waiting to be sent
mtpRequestMap haveSent; // map of msg_id -> request, that was sent, msDate = 0 for msgs_state_req (no resend / state req), msDate = 0, seqNo = 0 for containers
mtpRequestIdsMap toResend; // map of msg_id -> request_id, that request_id -> request lies in toSend and is waiting to be resent
mtpMsgIdsSet receivedIds; // set of received msg_id's, for checking new msg_ids
mtpMsgIdsMap receivedIds; // set of received msg_id's, for checking new msg_ids
mtpRequestIdsMap wereAcked; // map of msg_id -> request_id, this msg_ids already were acked or do not need ack
mtpResponseMap haveReceived; // map of request_id -> response, that should be processed in other thread
mtpMsgIdsSet stateRequest; // set of msg_id's, whose state should be requested
// mutexes
mutable QReadWriteLock lock;
@ -187,6 +197,7 @@ private:
mutable QReadWriteLock receivedIdsLock;
mutable QReadWriteLock wereAckedLock;
mutable QReadWriteLock haveReceivedLock;
mutable QReadWriteLock stateRequestLock;
};
@ -209,9 +220,10 @@ public:
void destroyKey();
template <typename TRequest>
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false); // send mtp request
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false, mtpRequestId after = 0); // send mtp request
void sendAnything(uint64 msCanWait);
void cancel(mtpRequestId requestId);
void cancel(mtpRequestId requestId, mtpMsgId msgId);
int32 requestState(mtpRequestId requestId) const;
int32 getState() const;
QString transport() const;
@ -244,7 +256,7 @@ public slots:
private:
template <typename TRequest>
mtpRequestId sendFirst(const MTPInitConnection<TRequest> &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false); // send first mtp request
mtpRequestId sendFirst(const MTPInitConnection<TRequest> &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, uint32 layer = 0, bool toMainDC = false, mtpRequestId after = 0); // send first mtp request
typedef QList<MTProtoConnection*> MTProtoConnections;
MTProtoConnections connections;

View File

@ -18,11 +18,11 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
#pragma once
template <typename TRequest>
mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC) {
mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC, mtpRequestId after) {
mtpRequestId requestId = 0;
if (layer && dc->needConnectionInit()) {
MTPInitConnection<TRequest> requestWrap(MTPinitConnection<TRequest>(MTP_int(ApiId), MTP_string(cApiDeviceModel()), MTP_string(cApiSystemVersion()), MTP_string(cApiAppVersion()), MTP_string(ApiLang), request));
return sendFirst(requestWrap, callbacks, msCanWait, layer, toMainDC);
return sendFirst(requestWrap, callbacks, msCanWait, layer, toMainDC, after);
}
try {
uint32 requestSize = request.size() >> 2;
@ -34,7 +34,8 @@ mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler ca
DEBUG_LOG(("MTP Info: adding request to toSendMap, msCanWait %1").arg(msCanWait));
reqSerialized->msDate = getms(); // > 0 - can send without container
requestId = _mtp_internal::storeRequest(reqSerialized, callbacks);
if (after) reqSerialized->after = _mtp_internal::getRequest(after);
requestId = _mtp_internal::storeRequest(reqSerialized, callbacks);
sendPrepared(reqSerialized, msCanWait);
} catch (Exception &e) {
@ -61,7 +62,7 @@ private:
};
template <typename TRequest>
mtpRequestId MTProtoSession::sendFirst(const MTPInitConnection<TRequest> &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC) {
mtpRequestId MTProtoSession::sendFirst(const MTPInitConnection<TRequest> &request, RPCResponseHandler callbacks, uint64 msCanWait, uint32 layer, bool toMainDC, mtpRequestId after) {
mtpRequestId requestId = 0;
try {
uint32 requestSize = request.size() >> 2;
@ -72,7 +73,8 @@ mtpRequestId MTProtoSession::sendFirst(const MTPInitConnection<TRequest> &reques
DEBUG_LOG(("MTP Info: adding wrapped to init connection request to toSendMap, msCanWait %1").arg(msCanWait));
callbacks.onDone = RPCDoneHandlerPtr(new RPCWrappedDcDoneHandler(dc, callbacks.onDone));
reqSerialized->msDate = getms(); // > 0 - can send without container
requestId = _mtp_internal::storeRequest(reqSerialized, callbacks);
if (after) reqSerialized->after = _mtp_internal::getRequest(after);
requestId = _mtp_internal::storeRequest(reqSerialized, callbacks);
sendPrepared(reqSerialized, msCanWait);
} catch (Exception &e) {

View File

@ -1848,7 +1848,7 @@ void OverviewWidget::onDeleteContextSure() {
}
if (item->id > 0) {
MTP::send(MTPmessages_DeleteMessages(MTP_vector<MTPint>(QVector<MTPint>(1, MTP_int(item->id)))));
MTP::send(MTPmessages_DeleteMessages(MTP_vector<MTPint>(1, MTP_int(item->id))));
}
item->destroy();
App::wnd()->hideLayer();

View File

@ -252,7 +252,7 @@ void ProfileInner::gotFullUser(const MTPUserFull &user) {
_loadingId = 0;
const MTPDuserFull &d(user.c_userFull());
App::feedPhoto(d.vprofile_photo);
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, d.vuser)));
App::feedUsers(MTP_vector<MTPUser>(1, d.vuser));
PhotoData *userPhoto = _peerUser->photoId ? App::photo(_peerUser->photoId) : 0;
if (userPhoto && userPhoto->date) {
_photoLink = TextLinkPtr(new PhotoLink(userPhoto, _peer));

View File

@ -642,7 +642,7 @@ void SettingsInner::updateConnectionType() {
void SettingsInner::gotFullSelf(const MTPUserFull &selfFull) {
if (!self()) return;
App::feedPhoto(selfFull.c_userFull().vprofile_photo);
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, selfFull.c_userFull().vuser)));
App::feedUsers(MTP_vector<MTPUser>(1, selfFull.c_userFull().vuser));
PhotoData *selfPhoto = self()->photoId ? App::photo(self()->photoId) : 0;
if (selfPhoto && selfPhoto->date) {
_photoLink = TextLinkPtr(new PhotoLink(selfPhoto, self()));

View File

@ -469,7 +469,7 @@ void Window::setupMain(bool anim) {
if (anim) {
main->animShow(bg);
} else {
MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(QVector<MTPInputUser>(1, MTP_inputUserSelf()))), main->rpcDone(&MainWidget::startFull));
MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(1, MTP_inputUserSelf())), main->rpcDone(&MainWidget::startFull));
main->activate();
}

View File

@ -11,7 +11,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.6.6</string>
<string>0.6.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>NOTE</key>

Binary file not shown.

View File

@ -1515,7 +1515,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.6;
CURRENT_PROJECT_VERSION = 0.6.7;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@ -1533,7 +1533,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.6.6;
CURRENT_PROJECT_VERSION = 0.6.7;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@ -1559,10 +1559,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.6;
CURRENT_PROJECT_VERSION = 0.6.7;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.6;
DYLIB_CURRENT_VERSION = 0.6.6;
DYLIB_CURRENT_VERSION = 0.6.7;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@ -1701,10 +1701,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.6.6;
CURRENT_PROJECT_VERSION = 0.6.7;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.6;
DYLIB_CURRENT_VERSION = 0.6.6;
DYLIB_CURRENT_VERSION = 0.6.7;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;