From ae6bc3852ac857b57f95e41a7a9d4f942d3b55c8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 13 Sep 2015 11:41:27 +0300 Subject: [PATCH] pts handled for channels now --- Telegram/SourceFiles/apiwrap.cpp | 18 +- Telegram/SourceFiles/apiwrap.h | 2 +- Telegram/SourceFiles/boxes/confirmbox.cpp | 2 +- Telegram/SourceFiles/config.h | 2 + Telegram/SourceFiles/dialogswidget.cpp | 52 ++- Telegram/SourceFiles/dialogswidget.h | 2 - Telegram/SourceFiles/history.cpp | 20 +- Telegram/SourceFiles/history.h | 1 + Telegram/SourceFiles/historywidget.cpp | 24 +- Telegram/SourceFiles/historywidget.h | 5 +- Telegram/SourceFiles/mainwidget.cpp | 404 +++++++++++++----- Telegram/SourceFiles/mainwidget.h | 61 +-- .../SourceFiles/mtproto/mtpConnection.cpp | 2 + Telegram/SourceFiles/mtproto/mtpSessionImpl.h | 2 +- Telegram/SourceFiles/overviewwidget.cpp | 6 + Telegram/SourceFiles/structs.cpp | 65 +++ Telegram/SourceFiles/structs.h | 86 ++++ 17 files changed, 570 insertions(+), 184 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 3a4f8c187e..3d619c9761 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -165,6 +165,12 @@ void ApiWrap::gotReplyTo(ChannelData *channel, const MTPmessages_Messages &msgs, case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &d(msgs.c_messages_channelMessages()); + if (channel) { + channel->ptsReceived(d.vpts.v); + } else { + LOG(("App Error: received messages.channelMessages in ApiWrap::gotReplyTo when no channel was passed!")); + } + App::feedUsers(d.vusers); App::feedChats(d.vchats); App::feedMsgs(d.vmessages, -1); @@ -566,11 +572,11 @@ void ApiWrap::resolveWebPages() { } } - mtpRequestId req = ids.isEmpty() ? 0 : MTP::send(MTPmessages_GetMessages(MTP_vector(ids)), rpcDone(&ApiWrap::gotWebPages), RPCFailHandlerPtr(), 0, 5); + mtpRequestId req = ids.isEmpty() ? 0 : MTP::send(MTPmessages_GetMessages(MTP_vector(ids)), rpcDone(&ApiWrap::gotWebPages, (ChannelData*)0), RPCFailHandlerPtr(), 0, 5); typedef QVector RequestIds; RequestIds reqsByIndex(idsByChannel.size(), 0); for (MessageIdsByChannel::const_iterator i = idsByChannel.cbegin(), e = idsByChannel.cend(); i != e; ++i) { - reqsByIndex[i.value().first] = MTP::send(MTPmessages_GetChannelMessages(i.key()->input, MTP_vector(i.value().second)), rpcDone(&ApiWrap::gotWebPages), RPCFailHandlerPtr(), 0, 5); + reqsByIndex[i.value().first] = MTP::send(MTPmessages_GetChannelMessages(i.key()->input, MTP_vector(i.value().second)), rpcDone(&ApiWrap::gotWebPages, i.key()), RPCFailHandlerPtr(), 0, 5); } if (req || !reqsByIndex.isEmpty()) { for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) { @@ -588,7 +594,7 @@ void ApiWrap::resolveWebPages() { if (m < INT_MAX) _webPagesTimer.start(m * 1000); } -void ApiWrap::gotWebPages(const MTPmessages_Messages &msgs, mtpRequestId req) { +void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) { const QVector *v = 0; switch (msgs.type()) { case mtpc_messages_messages: { @@ -607,6 +613,12 @@ void ApiWrap::gotWebPages(const MTPmessages_Messages &msgs, mtpRequestId req) { case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &d(msgs.c_messages_channelMessages()); + if (channel) { + channel->ptsReceived(d.vpts.v); + } else { + LOG(("App Error: received messages.channelMessages in ApiWrap::gotWebPages when no channel was passed!")); + } + App::feedUsers(d.vusers); App::feedChats(d.vchats); v = &d.vmessages.c_vector().v; diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index b51699ed74..177ace4f03 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -83,7 +83,7 @@ private: bool gotPeerFailed(PeerData *peer, const RPCError &err); PeerRequests _peerRequests; - void gotWebPages(const MTPmessages_Messages &result, mtpRequestId req); + void gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); typedef QMap WebPagesPending; WebPagesPending _webPagesPending; SingleTimer _webPagesTimer; diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index c601cfa979..45e4cd28f5 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.cpp +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -48,7 +48,7 @@ _text(100) { void ConfirmBox::init(const QString &text) { _text.setText(st::boxFont, text, (_infoMsg ? _confirmBoxTextOptions : _textPlainOptions)); - _textWidth = st::boxWidth - st::boxPadding.left() - st::boxPadding.right(); + _textWidth = st::boxWidth + 10 - st::boxPadding.left() - st::boxPadding.right(); _textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxFont->height); setMaxHeight(st::boxPadding.top() + _textHeight + st::boxPadding.bottom() + (_infoMsg ? _close.height() : _confirm.height())); diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 9dfc7e65a7..ebc06ab4dd 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -59,6 +59,8 @@ enum { MTPPingSendAfterAuto = 30, // send new ping starting from 30 seconds (add to existing container) MTPPingSendAfter = 45, // send new ping after 45 seconds without ping + MTPChannelGetDifferenceLimit = 100, + MaxSelectedItems = 100, MaxPhoneTailLength = 18, // rest of the phone number, without country code (seen 12 at least) diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 8c3eabc681..8bbdeaf2e0 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -772,6 +772,9 @@ void DialogsListWidget::dialogsReceived(const QVector &added) { case mtpc_dialogChannel: { const MTPDdialogChannel &d(i->c_dialogChannel()); History *history = App::historyFromDialog(peerFromMTP(d.vpeer), d.vunread_important_count.v, d.vread_inbox_max_id.v); + if (history->peer->isChannel()) { + history->peer->asChannel()->ptsReceived(d.vpts.v); + } App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, history); } break; } @@ -964,28 +967,6 @@ void DialogsListWidget::clearFilter() { } } -void DialogsListWidget::addDialog(const MTPDdialog &dialog) { - History *history = App::historyFromDialog(peerFromMTP(dialog.vpeer), dialog.vunread_count.v, dialog.vread_inbox_max_id.v); - - if (!history->lastMsgDate.isNull()) addSavedPeersAfter(history->lastMsgDate); - History::DialogLinks links = dialogs.addToEnd(history); - history->dialogs = links; - contactsNoDialogs.del(history->peer); - - App::main()->applyNotifySetting(MTP_notifyPeer(dialog.vpeer), dialog.vnotify_settings, history); -} - -void DialogsListWidget::addDialogChannel(const MTPDdialogChannel &dialogChannel) { - History *history = App::historyFromDialog(peerFromMTP(dialogChannel.vpeer), dialogChannel.vunread_important_count.v, dialogChannel.vread_inbox_max_id.v); - - if (!history->lastMsgDate.isNull()) addSavedPeersAfter(history->lastMsgDate); - History::DialogLinks links = dialogs.addToEnd(history); - history->dialogs = links; - contactsNoDialogs.del(history->peer); - - App::main()->applyNotifySetting(MTP_notifyPeer(dialogChannel.vpeer), dialogChannel.vnotify_settings, history); -} - void DialogsListWidget::selectSkip(int32 direction) { if (_state == DefaultState) { if (!sel) { @@ -1628,6 +1609,9 @@ void DialogsWidget::unreadCountsReceived(const QVector &dialogs) { const MTPDdialogChannel &d(i->c_dialogChannel()); Histories::iterator j = App::histories().find(peerFromMTP(d.vpeer)); if (j != App::histories().end()) { + if (j.value()->peer->isChannel()) { + j.value()->peer->asChannel()->ptsReceived(d.vpts.v); + } App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, j.value()); if (d.vunread_important_count.v >= j.value()->unreadCount) { j.value()->setUnreadCount(d.vunread_important_count.v, false); @@ -1722,9 +1706,11 @@ bool DialogsWidget::onSearchMessages(bool searchCache) { QString q = _filter.getLastText().trimmed(); if (q.isEmpty()) { if (_searchRequest) { + MTP::cancel(_searchRequest); _searchRequest = 0; } if (_peopleRequest) { + MTP::cancel(_peopleRequest); _peopleRequest = 0; } return true; @@ -1734,7 +1720,10 @@ bool DialogsWidget::onSearchMessages(bool searchCache) { if (i != _searchCache.cend()) { _searchQuery = q; _searchFull = false; - _searchRequest = 0; + if (_searchRequest) { + MTP::cancel(_searchRequest); + _searchRequest = 0; + } searchReceived(true, i.value(), 0); return true; } @@ -1742,6 +1731,9 @@ bool DialogsWidget::onSearchMessages(bool searchCache) { _searchQuery = q; _searchFull = false; int32 flags = (_searchInPeer && _searchInPeer->isChannel()) ? MTPmessages_Search_flag_only_important : 0; + if (_searchRequest) { + MTP::cancel(_searchRequest); + } _searchRequest = MTP::send(MTPmessages_Search(MTP_int(flags), _searchInPeer ? _searchInPeer->input : MTP_inputPeerEmpty(), MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, true), rpcFail(&DialogsWidget::searchFailed)); _searchQueries.insert(_searchRequest, _searchQuery); } @@ -1862,6 +1854,12 @@ void DialogsWidget::searchReceived(bool fromStart, const MTPmessages_Messages &r case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &d(result.c_messages_channelMessages()); + if (_searchInPeer && _searchInPeer->isChannel()) { + _searchInPeer->asChannel()->ptsReceived(d.vpts.v); + } else { + LOG(("App Error: received messages.channelMessages in DialogsWidget::searchReceived when no channel was passed!")); + } + App::feedUsers(d.vusers); App::feedChats(d.vchats); const QVector &msgs(d.vmessages.c_vector().v); @@ -2204,6 +2202,10 @@ void DialogsWidget::onNewGroup() { bool DialogsWidget::onCancelSearch() { bool clearing = !_filter.getLastText().isEmpty(); + if (_searchRequest) { + MTP::cancel(_searchRequest); + _searchRequest = 0; + } if (_searchInPeer && !clearing) { if (!cWideMode()) { App::main()->showPeerHistory(_searchInPeer->id, ShowAtUnreadMsgId); @@ -2220,6 +2222,10 @@ bool DialogsWidget::onCancelSearch() { } void DialogsWidget::onCancelSearchInPeer() { + if (_searchRequest) { + MTP::cancel(_searchRequest); + _searchRequest = 0; + } if (_searchInPeer) { if (!cWideMode()) { App::main()->showPeerHistory(_searchInPeer->id, ShowAtUnreadMsgId); diff --git a/Telegram/SourceFiles/dialogswidget.h b/Telegram/SourceFiles/dialogswidget.h index 0b76d7ed08..9a2bfcfd76 100644 --- a/Telegram/SourceFiles/dialogswidget.h +++ b/Telegram/SourceFiles/dialogswidget.h @@ -128,8 +128,6 @@ signals: private: - void addDialog(const MTPDdialog &dialog); - void addDialogChannel(const MTPDdialogChannel &dialogChannel); void clearSearchResults(bool clearPeople = true); DialogsIndexed dialogs; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 02a2a72998..00e0e3c239 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -597,22 +597,8 @@ inline bool isImportantChannelMessage(int32 flags) { } HistoryItem *Histories::addToBack(const MTPmessage &msg, int msgState) { - PeerId from_id = 0, to_id = 0; int32 flags = 0; - switch (msg.type()) { - case mtpc_message: - from_id = msg.c_message().has_from_id() ? peerFromUser(msg.c_message().vfrom_id) : 0; - to_id = peerFromMTP(msg.c_message().vto_id); - flags = msg.c_message().vflags.v; - break; - case mtpc_messageService: - from_id = msg.c_messageService().has_from_id() ? peerFromUser(msg.c_messageService().vfrom_id) : 0; - to_id = peerFromMTP(msg.c_messageService().vto_id); - flags = msg.c_messageService().vflags.v; - break; - } - PeerId peer = (from_id && peerToUser(to_id) == MTP::authedId()) ? from_id : to_id; - + PeerId peer = peerFromMessage(msg, &flags); if (!peer) return 0; iterator h = find(peer); @@ -1477,6 +1463,10 @@ void History::getReadyFor(MsgId msgId) { } } +void History::setNotLoadedAtBottom() { + newLoaded = false; +} + namespace { uint32 _dialogsPosToTopShift = 0x80000000UL; } diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 0c41f33048..47b46680c0 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -208,6 +208,7 @@ struct History : public QList { void clearNotifications(); bool loadedAtBottom() const; // last message is in the list + void setNotLoadedAtBottom(); bool loadedAtTop() const; // nothing was added after loading history back bool isReadyFor(MsgId msgId, bool check = false) const; // has messages for showing history at msgId void getReadyFor(MsgId msgId); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index ee5715a252..f99b5f232e 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3273,7 +3273,7 @@ bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId return true; } -void HistoryWidget::messagesReceived(const MTPmessages_Messages &messages, mtpRequestId requestId) { +void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages &messages, mtpRequestId requestId) { if (!_history) { _preloadRequest = _preloadDownRequest = _firstLoadRequest = _delayedShowAtRequest = 0; return; @@ -3298,6 +3298,12 @@ void HistoryWidget::messagesReceived(const MTPmessages_Messages &messages, mtpRe } break; case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &data(messages.c_messages_channelMessages()); + if (peer && peer->isChannel()) { + peer->asChannel()->ptsReceived(data.vpts.v); + } else { + LOG(("App Error: received messages.channelMessages in HistoryWidget::messagesReceived when no channel was passed!")); + } + App::feedUsers(data.vusers); App::feedChats(data.vchats); histList = &data.vmessages.c_vector().v; @@ -3405,9 +3411,9 @@ void HistoryWidget::firstLoadMessages() { from = _showAtMsgId; } if (_peer->isChannel()) { - _firstLoadRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + _firstLoadRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } else { - _firstLoadRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + _firstLoadRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } } @@ -3417,9 +3423,9 @@ void HistoryWidget::loadMessages() { MsgId min = _history->minMsgId(); int32 offset = 0, loadCount = min ? MessagesPerPage : MessagesFirstLoad; if (_peer->isChannel()) { - _preloadRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(min), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + _preloadRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(min), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } else { - _preloadRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(min), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + _preloadRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(min), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } } @@ -3431,9 +3437,9 @@ void HistoryWidget::loadMessagesDown() { int32 loadCount = MessagesPerPage, offset = -loadCount - 1; if (_peer->isChannel()) { - _preloadDownRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(max + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + _preloadDownRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(max + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } else { - _preloadDownRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(max + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + _preloadDownRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(max + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } } @@ -3459,9 +3465,9 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { offset = -loadCount / 2; } if (_peer->isChannel()) { - _delayedShowAtRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + _delayedShowAtRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } else { - _delayedShowAtRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived), rpcFail(&HistoryWidget::messagesFailed)); + _delayedShowAtRequest = MTP::send(MTPmessages_GetHistory(_peer->input, MTP_int(from), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index c01f486e63..4cc73139d0 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -383,7 +383,7 @@ public: void start(); - void messagesReceived(const MTPmessages_Messages &messages, mtpRequestId requestId); + void messagesReceived(PeerData *peer, const MTPmessages_Messages &messages, mtpRequestId requestId); void historyLoaded(); void windowShown(); @@ -517,6 +517,7 @@ public: void clearAllLoadRequests(); void contactsReceived(); + void updateToEndVisibility(); ~HistoryWidget(); @@ -662,8 +663,6 @@ private: void countHistoryShowFrom(); - void updateToEndVisibility(); - void stickersGot(const MTPmessages_AllStickers &stickers); bool stickersFailed(const RPCError &error); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index d6f3847af4..c95b7bc430 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -366,11 +366,12 @@ _started(0), failedObjId(0), _toForwardNameVersion(0), _dialogsWidth(st::dlgMinW dialogs(this), history(this), profile(0), overview(0), _player(this), _topBar(this), _forwardConfirm(0), _hider(0), _peerInStack(0), _msgIdInStack(0), _playerHeight(0), _contentScrollAddToY(0), _mediaType(this), _mediaTypeMask(0), -updGoodPts(0), updLastPts(0), updPtsCount(0), updDate(0), updQts(-1), updSeq(0), updInited(false), updSkipPtsUpdateLevel(0), +updDate(0), updQts(-1), updSeq(0), _getDifferenceTimeByPts(0), _getDifferenceTimeAfterFail(0), _onlineRequest(0), _lastWasOnline(false), _lastSetOnline(0), _isIdle(false), _failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _background(0), _api(new ApiWrap(this)) { setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight)); + _ptsWaiter.setRequesting(true); updateScrollColors(); connect(window, SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &))); @@ -382,8 +383,8 @@ _failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _backgr connect(&_onlineUpdater, SIGNAL(timeout()), this, SLOT(updateOnlineDisplay())); connect(&_idleFinishTimer, SIGNAL(timeout()), this, SLOT(checkIdleFinish())); connect(&_bySeqTimer, SIGNAL(timeout()), this, SLOT(getDifference())); - connect(&_byPtsTimer, SIGNAL(timeout()), this, SLOT(getDifference())); - connect(&_failDifferenceTimer, SIGNAL(timeout()), this, SLOT(getDifferenceForce())); + connect(&_byPtsTimer, SIGNAL(timeout()), this, SLOT(onGetDifferenceTimeByPts())); + connect(&_failDifferenceTimer, SIGNAL(timeout()), this, SLOT(onGetDifferenceTimeAfterFail())); connect(_api, SIGNAL(fullPeerUpdated(PeerData*)), this, SIGNAL(peerUpdated(PeerData*))); connect(this, SIGNAL(peerUpdated(PeerData*)), &history, SLOT(peerUpdated(PeerData*))); connect(&_topBar, SIGNAL(clicked()), this, SLOT(onTopBarClick())); @@ -774,7 +775,7 @@ void MainWidget::deleteHistoryAfterLeave(PeerData *peer, const MTPUpdates &updat void MainWidget::deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHistory &result) { const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory()); - updPtsUpdated(d.vpts.v, d.vpts_count.v); + ptsUpdated(d.vpts.v, d.vpts_count.v); int32 offset = d.voffset.v; if (!MTP::authedId()) return; @@ -888,8 +889,14 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu v = &d.vmessages.c_vector().v; } break; - case mtpc_messages_channelMessages: { // CHANNELS_TODO - all mtpc_messages_channelMessages handle! + case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &d(result.c_messages_channelMessages()); + if (peer && peer->isChannel()) { + peer->asChannel()->ptsReceived(d.vpts.v); + } else { + LOG(("App Error: received messages.channelMessages in MainWidget::checkedHistory when no channel was passed!")); + } + App::feedUsers(d.vusers); App::feedChats(d.vchats); v = &d.vmessages.c_vector().v; @@ -1253,6 +1260,12 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &d(result.c_messages_channelMessages()); + if (peer && peer->isChannel()) { + peer->asChannel()->ptsReceived(d.vpts.v); + } else { + LOG(("App Error: received messages.channelMessages in MainWidget::overviewPreloaded when no channel was passed!")); + } + App::feedUsers(d.vusers); App::feedChats(d.vchats); h->_overviewCount[type] = d.vcount.v; @@ -1454,6 +1467,12 @@ void MainWidget::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpR case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &d(msgs.c_messages_channelMessages()); + if (h && h->peer->isChannel()) { + h->peer->asChannel()->ptsReceived(d.vpts.v); + } else { + LOG(("App Error: received messages.channelMessages in MainWidget::photosLoaded when no channel was passed!")); + } + App::feedUsers(d.vusers); App::feedChats(d.vchats); h->_overviewCount[type] = d.vcount.v; @@ -1491,7 +1510,7 @@ void MainWidget::sendReadRequest(PeerData *peer, MsgId upTo) { if (peer->isChannel()) { _readRequests.insert(peer, MTP::send(MTPmessages_ReadChannelHistory(peer->input, MTP_int(upTo)), rpcDone(&MainWidget::channelWasRead, peer), rpcFail(&MainWidget::readRequestFail, peer))); } else { - //_readRequests.insert(peer, MTP::send(MTPmessages_ReadHistory(peer->input, MTP_int(upTo), MTP_int(0)), rpcDone(&MainWidget::partWasRead, peer), rpcFail(&MainWidget::readRequestFail, peer))); + _readRequests.insert(peer, MTP::send(MTPmessages_ReadHistory(peer->input, MTP_int(upTo), MTP_int(0)), rpcDone(&MainWidget::partWasRead, peer), rpcFail(&MainWidget::readRequestFail, peer))); } } @@ -1501,7 +1520,7 @@ void MainWidget::channelWasRead(PeerData *peer, const MTPBool &result) { void MainWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result) { const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory()); - updPtsUpdated(d.vpts.v, d.vpts_count.v); + ptsUpdated(d.vpts.v, d.vpts_count.v); int32 offset = d.voffset.v; if (!MTP::authedId() || offset <= 0 || true) { @@ -1530,9 +1549,9 @@ void MainWidget::readRequestDone(PeerData *peer) { void MainWidget::messagesAffected(PeerData *peer, const MTPmessages_AffectedMessages &result) { const MTPDmessages_affectedMessages &d(result.c_messages_affectedMessages()); if (peer && peer->isChannel()) { - // CHANNELS_TODO + peer->asChannel()->ptsUpdated(d.vpts.v, d.vpts_count.v); } else { - updPtsUpdated(d.vpts.v, d.vpts_count.v); + ptsUpdated(d.vpts.v, d.vpts_count.v); } } @@ -1931,6 +1950,8 @@ void MainWidget::serviceHistoryDone(const MTPmessages_Messages &msgs) { case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &d(msgs.c_messages_channelMessages()); + LOG(("App Error: received messages.channelMessages in MainWidget::serviceHistoryDone!")); + App::feedUsers(d.vusers); App::feedChats(d.vchats); App::feedMsgs(d.vmessages); @@ -2731,7 +2752,7 @@ bool MainWidget::updateFail(const RPCError &e) { } void MainWidget::updSetState(int32 pts, int32 date, int32 qts, int32 seq) { - if (pts) updGoodPts = updLastPts = updPtsCount = pts; + if (pts) _ptsWaiter.init(pts); if (updDate < date) updDate = date; if (qts && updQts < qts) { updQts = qts; @@ -2755,6 +2776,78 @@ void MainWidget::updSetState(int32 pts, int32 date, int32 qts, int32 seq) { } } +void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_ChannelDifference &diff) { + _channelFailDifferenceTimeout.remove(channel); + + int32 timeout = 0, flags = 0; + switch (diff.type()) { + case mtpc_updates_channelDifferenceEmpty: { + const MTPDupdates_channelDifferenceEmpty &d(diff.c_updates_channelDifferenceEmpty()); + if (d.has_timeout()) timeout = d.vtimeout.v; + flags = d.vflags.v; + channel->ptsReceived(d.vpts.v); + } break; + + case mtpc_updates_channelDifferenceTooLong: { + const MTPDupdates_channelDifferenceTooLong &d(diff.c_updates_channelDifferenceTooLong()); + + App::feedUsers(d.vusers); + App::feedChats(d.vchats); + App::feedMsgs(d.vmessages); + if (History *h = App::historyLoaded(channel->id)) { + if (HistoryItem *item = App::histItemById(peerToChannel(channel->id), d.vtop_important_message.v)) { + h->setLastMessage(item); + } + if (d.vunread_important_count.v >= h->unreadCount) { + h->setUnreadCount(d.vunread_important_count.v, false); + h->inboxReadBefore = d.vread_inbox_max_id.v + 1; + } + h->setNotLoadedAtBottom(); + if (history.peer() == channel) { + history.updateToEndVisibility(); + } + } + + if (d.has_timeout()) timeout = d.vtimeout.v; + flags = d.vflags.v; + channel->ptsReceived(d.vpts.v); + } break; + + case mtpc_updates_channelDifference: { + const MTPDupdates_channelDifference &d(diff.c_updates_channelDifference()); + + App::feedUsers(d.vusers); + App::feedChats(d.vchats, false); + feedMessageIds(d.vother_updates); + App::feedMsgs(d.vnew_messages, 1); + feedUpdates(d.vother_updates, true); + + if (d.has_timeout()) timeout = d.vtimeout.v; + flags = d.vflags.v; + channel->ptsReceived(d.vpts.v); + } break; + } + + channel->ptsSetRequesting(false); + + if (flags & MTPupdates_ChannelDifference_flag_final) { + MTP_LOG(0, ("getChannelDifference { good - after not final channelDifference was received }%1").arg(cTestMode() ? " TESTMODE" : "")); + getChannelDifference(channel); + } else if (timeout) { + QTimer::singleShot(timeout * 1000, this, SLOT(getDifference())); + } + + App::emitPeerUpdated(); +} + +bool MainWidget::failChannelDifference(ChannelData *channel, const RPCError &error) { + if (mtpIsFlood(error)) return false; + + LOG(("RPC Error in getChannelDifference: %1 %2: %3").arg(error.code()).arg(error.type()).arg(error.description())); + failDifferenceStartTimerFor(channel); + return true; +} + void MainWidget::gotState(const MTPupdates_State &state) { const MTPDupdates_state &d(state.c_updates_state()); updSetState(d.vpts.v, d.vdate.v, d.vqts.v, d.vseq.v); @@ -2762,7 +2855,7 @@ void MainWidget::gotState(const MTPupdates_State &state) { MTP::setGlobalDoneHandler(rpcDone(&MainWidget::updateReceived)); _lastUpdateTime = getms(true); noUpdatesTimer.start(NoUpdatesTimeout); - updInited = true; + _ptsWaiter.setRequesting(false); dialogs.loadDialogs(); updateOnline(); @@ -2776,13 +2869,13 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) { switch (diff.type()) { case mtpc_updates_differenceEmpty: { const MTPDupdates_differenceEmpty &d(diff.c_updates_differenceEmpty()); - updSetState(updGoodPts, d.vdate.v, updQts, d.vseq.v); + updSetState(_ptsWaiter.current(), d.vdate.v, updQts, d.vseq.v); MTP::setGlobalDoneHandler(rpcDone(&MainWidget::updateReceived)); _lastUpdateTime = getms(true); noUpdatesTimer.start(NoUpdatesTimeout); - updInited = true; + _ptsWaiter.setRequesting(false); App::emitPeerUpdated(); } break; @@ -2793,7 +2886,7 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) { const MTPDupdates_state &s(d.vintermediate_state.c_updates_state()); updSetState(s.vpts.v, s.vdate.v, s.vqts.v, s.vseq.v); - updInited = true; + _ptsWaiter.setRequesting(false); MTP_LOG(0, ("getDifference { good - after a slice of difference was received }%1").arg(cTestMode() ? " TESTMODE" : "")); getDifference(); @@ -2809,49 +2902,85 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) { }; } -uint64 MainWidget::ptsKey(PtsSkippedQueue queue) { - return _byPtsQueue.insert(uint64(uint32(updLastPts)) << 32 | uint64(uint32(updPtsCount)), queue).key(); -} - -void MainWidget::applySkippedPtsUpdates() { - if (_byPtsTimer.isActive()) _byPtsTimer.stop(); - if (_byPtsQueue.isEmpty()) return; - ++updSkipPtsUpdateLevel; - for (QMap::const_iterator i = _byPtsQueue.cbegin(), e = _byPtsQueue.cend(); i != e; ++i) { - switch (i.value()) { - case SkippedUpdate: feedUpdate(_byPtsUpdate.value(i.key())); break; - case SkippedUpdates: handleUpdates(_byPtsUpdates.value(i.key())); break; -// case SkippedSentMessage: sentDataReceived(0, _byPtsSentMessage.value(i.key())); break; +bool MainWidget::getDifferenceTimeChanged(ChannelData *channel, int32 ms, ChannelGetDifferenceTime &channelCurTime, uint64 &curTime) { + if (channel) { + if (ms <= 0) { + ChannelGetDifferenceTime::iterator i = channelCurTime.find(channel); + if (i != channelCurTime.cend()) { + channelCurTime.erase(i); + } else { + return false; + } + } else { + uint64 when = getms(true) + ms; + ChannelGetDifferenceTime::iterator i = channelCurTime.find(channel); + if (i != channelCurTime.cend()) { + if (i.value() > when) { + i.value() = when; + } else { + return false; + } + } else { + channelCurTime.insert(channel, when); + } + } + } else { + if (ms <= 0) { + if (curTime) { + curTime = 0; + } else { + return false; + } + } else { + uint64 when = getms(true) + ms; + if (!curTime || curTime > when) { + curTime = when; + } else { + return false; + } } } - --updSkipPtsUpdateLevel; - clearSkippedPtsUpdates(); - App::emitPeerUpdated(); + return true; } -void MainWidget::clearSkippedPtsUpdates() { - _byPtsQueue.clear(); - _byPtsUpdate.clear(); - _byPtsUpdates.clear(); -// _byPtsSentMessage.clear(); - updSkipPtsUpdateLevel = 0; -} - -bool MainWidget::updPtsUpdated(int pts, int ptsCount) { // return false if need to save that update and apply later - if (!updInited || updSkipPtsUpdateLevel) return true; - - updLastPts = qMax(updLastPts, pts); - updPtsCount += ptsCount; - if (updLastPts == updPtsCount) { - applySkippedPtsUpdates(); - updGoodPts = updLastPts; - return true; - } else if (updLastPts < updPtsCount) { - _byPtsTimer.startIfNotActive(1); - } else { - _byPtsTimer.startIfNotActive(WaitForSkippedTimeout); +void MainWidget::ptsWaiterStartTimerFor(ChannelData *channel, int32 ms) { + if (getDifferenceTimeChanged(channel, ms, _channelGetDifferenceTimeByPts, _getDifferenceTimeByPts)) { + onGetDifferenceTimeByPts(); } - return !ptsCount; +} + +void MainWidget::failDifferenceStartTimerFor(ChannelData *channel) { + int32 ms = 0; + ChannelFailDifferenceTimeout::iterator i; + if (channel) { + i = _channelFailDifferenceTimeout.find(channel); + if (i == _channelFailDifferenceTimeout.cend()) { + i = _channelFailDifferenceTimeout.insert(channel, 1); + } + ms = i.value() * 1000; + } else { + ms = _failDifferenceTimeout * 1000; + } + if (getDifferenceTimeChanged(channel, ms, _channelGetDifferenceTimeAfterFail, _getDifferenceTimeAfterFail)) { + onGetDifferenceTimeAfterFail(); + } + if (channel) { + if (i.value() < 64) i.value() *= 2; + } else { + if (_failDifferenceTimeout < 64) _failDifferenceTimeout *= 2; + } +} + +bool MainWidget::ptsUpdated(int32 pts, int32 ptsCount) { // return false if need to save that update and apply later + return _ptsWaiter.updated(0, pts, ptsCount); +} + +bool MainWidget::ptsUpdated(int32 pts, int32 ptsCount, const MTPUpdates &updates) { + return _ptsWaiter.updated(0, pts, ptsCount, updates); +} + +bool MainWidget::ptsUpdated(int32 pts, int32 ptsCount, const MTPUpdate &update) { + return _ptsWaiter.updated(0, pts, ptsCount, update); } void MainWidget::feedDifference(const MTPVector &users, const MTPVector &chats, const MTPVector &msgs, const MTPVector &other) { @@ -2865,41 +2994,110 @@ void MainWidget::feedDifference(const MTPVector &users, const MTPVector } bool MainWidget::failDifference(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; - LOG(("RPC Error: %1 %2: %3").arg(error.code()).arg(error.type()).arg(error.description())); - _failDifferenceTimer.start(_failDifferenceTimeout * 1000); - if (_failDifferenceTimeout < 64) _failDifferenceTimeout *= 2; + LOG(("RPC Error in getDifference: %1 %2: %3").arg(error.code()).arg(error.type()).arg(error.description())); + failDifferenceStartTimerFor(0); return true; } -void MainWidget::getDifferenceForce() { - if (MTP::authedId()) { - updInited = true; - MTP_LOG(0, ("getDifference { force - after get difference failed }%1").arg(cTestMode() ? " TESTMODE" : "")); - getDifference(); +void MainWidget::onGetDifferenceTimeByPts() { + if (!MTP::authedId()) return; + + uint64 now = getms(true), wait = 0; + if (_getDifferenceTimeByPts) { + if (_getDifferenceTimeByPts > now) { + wait = _getDifferenceTimeByPts - now; + } else { + getDifference(); + } + } + for (ChannelGetDifferenceTime::iterator i = _channelGetDifferenceTimeByPts.begin(); i != _channelGetDifferenceTimeByPts.cend();) { + if (i.value() > now) { + wait = qMin(wait, i.value() - now); + ++i; + } else { + getChannelDifference(i.key()); + i = _channelGetDifferenceTimeByPts.erase(i); + } + } + if (wait) { + _byPtsTimer.start(wait); + } else { + _byPtsTimer.stop(); + } +} + +void MainWidget::onGetDifferenceTimeAfterFail() { + if (!MTP::authedId()) return; + + uint64 now = getms(true), wait = 0; + if (_getDifferenceTimeAfterFail) { + if (_getDifferenceTimeAfterFail > now) { + wait = _getDifferenceTimeAfterFail - now; + } else { + _ptsWaiter.setRequesting(false); + MTP_LOG(0, ("getDifference { force - after get difference failed }%1").arg(cTestMode() ? " TESTMODE" : "")); + getDifference(); + } + } + for (ChannelGetDifferenceTime::iterator i = _channelGetDifferenceTimeAfterFail.begin(); i != _channelGetDifferenceTimeAfterFail.cend();) { + if (i.value() > now) { + wait = qMin(wait, i.value() - now); + ++i; + } else { + getChannelDifference(i.key()); + i = _channelGetDifferenceTimeAfterFail.erase(i); + } + } + if (wait) { + _failDifferenceTimer.start(wait); + } else { + _failDifferenceTimer.stop(); } } void MainWidget::getDifference() { if (this != App::main()) return; + _getDifferenceTimeByPts = 0; + LOG(("Getting difference! no updates timer: %1, remains: %2").arg(noUpdatesTimer.isActive() ? 1 : 0).arg(noUpdatesTimer.remainingTime())); - if (!updInited) return; + if (_ptsWaiter.requesting()) return; _bySeqUpdates.clear(); _bySeqTimer.stop(); - clearSkippedPtsUpdates(); - _byPtsTimer.stop(); + _ptsWaiter.clearSkippedUpdates(); noUpdatesTimer.stop(); - _failDifferenceTimer.stop(); + _getDifferenceTimeAfterFail = 0; - LOG(("Getting difference for %1, %2").arg(updGoodPts).arg(updDate)); - updInited = false; + LOG(("Getting difference for %1, %2").arg(_ptsWaiter.current()).arg(updDate)); + _ptsWaiter.setRequesting(true); MTP::setGlobalDoneHandler(RPCDoneHandlerPtr(0)); - MTP::send(MTPupdates_GetDifference(MTP_int(updGoodPts), MTP_int(updDate), MTP_int(updQts)), rpcDone(&MainWidget::gotDifference), rpcFail(&MainWidget::failDifference)); + MTP::send(MTPupdates_GetDifference(MTP_int(_ptsWaiter.current()), MTP_int(updDate), MTP_int(updQts)), rpcDone(&MainWidget::gotDifference), rpcFail(&MainWidget::failDifference)); +} + +void MainWidget::getChannelDifference(ChannelData *channel, GetChannelDifferenceFrom from) { + if (this != App::main() || !channel) return; + + if (from != GetChannelDifferenceFromPtsGap) { + _channelGetDifferenceTimeByPts.remove(channel); + } + + LOG(("Getting channel difference!")); + if (!channel->ptsInited() || channel->ptsRequesting()) return; + + channel->ptsClearSkippedUpdates(); + + if (from != GetChannelDifferenceFromFail) { + _channelGetDifferenceTimeAfterFail.remove(channel); + } + + LOG(("Getting channel difference for %1").arg(channel->pts())); + channel->ptsSetRequesting(true); + MTP::send(MTPupdates_GetChannelDifference(channel->input, MTP_channelMessagesFilterCollapsed(), MTP_int(channel->pts()), MTP_int(MTPChannelGetDifferenceLimit)), rpcDone(&MainWidget::gotChannelDifference, channel), rpcFail(&MainWidget::failChannelDifference, channel)); } void MainWidget::mtpPing() { @@ -3504,8 +3702,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates, uint64 randomId) { MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : "")); return getDifference(); } - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdates.insert(ptsKey(SkippedUpdates), updates); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, updates)) { return; } int32 flags = d.vflags.v | MTPDmessage::flag_from_id; @@ -3526,8 +3723,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates, uint64 randomId) { if (noFrom) App::api()->requestFullPeer(App::chatLoaded(d.vchat_id.v)); return getDifference(); } - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdates.insert(ptsKey(SkippedUpdates), updates); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, updates)) { return; } int32 flags = d.vflags.v | MTPDmessage::flag_from_id; @@ -3568,8 +3764,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates, uint64 randomId) { } } - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdates.insert(ptsKey(SkippedUpdates), updates); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, updates)) { return; } @@ -3589,8 +3784,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { switch (update.type()) { case mtpc_updateNewMessage: { const MTPDupdateNewMessage &d(update.c_updateNewMessage()); - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; } if (d.vmessage.type() == mtpc_message) { // index forwarded messages to links overview @@ -3642,8 +3836,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateReadMessagesContents: { const MTPDupdateReadMessagesContents &d(update.c_updateReadMessagesContents()); - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; } const QVector &v(d.vmessages.c_vector().v); @@ -3662,8 +3855,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateReadHistoryInbox: { const MTPDupdateReadHistoryInbox &d(update.c_updateReadHistoryInbox()); - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; } App::feedInboxRead(peerFromMTP(d.vpeer), d.vmax_id.v); @@ -3671,8 +3863,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateReadHistoryOutbox: { const MTPDupdateReadHistoryOutbox &d(update.c_updateReadHistoryOutbox()); - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; } PeerId id = peerFromMTP(d.vpeer); @@ -3682,8 +3873,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateWebPage: { const MTPDupdateWebPage &d(update.c_updateWebPage()); - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; } App::feedWebPage(d.vwebpage); @@ -3693,8 +3883,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateDeleteMessages: { const MTPDupdateDeleteMessages &d(update.c_updateDeleteMessages()); - if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { - _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); + if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { return; } App::feedWereDeleted(NoChannel, d.vmessages.c_vector().v); @@ -3893,10 +4082,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateNewChannelMessage: { const MTPDupdateNewChannelMessage &d(update.c_updateNewChannelMessage()); - //if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { // CHANNELS_TODO - // _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); - // return; - //} + PeerId peer = peerFromMessage(d.vmessage); + if (ChannelData *channel = App::channelLoaded(peerToChannel(peer))) { + if (!channel->ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { + return; + } + } if (d.vmessage.type() == mtpc_message) { // index forwarded messages to links overview App::checkEntitiesUpdate(d.vmessage.c_message()); } @@ -3909,29 +4100,44 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateReadChannelInbox: { const MTPDupdateReadChannelInbox &d(update.c_updateReadChannelInbox()); - //if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { // CHANNELS_TODO - // _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); - // return; - //} App::feedInboxRead(peerFromMTP(d.vpeer), d.vmax_id.v); } break; case mtpc_updateDeleteChannelMessages: { const MTPDupdateDeleteChannelMessages &d(update.c_updateDeleteChannelMessages()); - //if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) { // CHANNELS_TODO - // _byPtsUpdate.insert(ptsKey(SkippedUpdate), update); - // return; - //} - App::feedWereDeleted(peerToChannel(peerFromMTP(d.vpeer)), d.vmessages.c_vector().v); + PeerId peer = peerFromMTP(d.vpeer); + if (ChannelData *channel = App::channelLoaded(peerToChannel(peer))) { + if (!channel->ptsUpdated(d.vpts.v, d.vpts_count.v, update)) { + return; + } + } + App::feedWereDeleted(peerToChannel(peer), d.vmessages.c_vector().v); history.peerMessagesUpdated(); } break; case mtpc_updateChannelGroup: { const MTPDupdateChannelGroup &d(update.c_updateChannelGroup()); + if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) { + if (d.vgroup.type() == mtpc_messageGroup) { + const MTPDmessageGroup &data(d.vgroup.c_messageGroup()); + } + } } break; case mtpc_updateChannelTooLong: { const MTPDupdateChannelTooLong &d(update.c_updateChannelTooLong()); + if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) { + getChannelDifference(channel); + } + } break; + + case mtpc_updateChannelMessageViews: { + const MTPDupdateChannelMessageViews &d(update.c_updateChannelMessageViews()); + if (HistoryItem *item = App::histItemById(peerToChannel(peerFromMTP(d.vpeer)), d.vid.v)) { + if (item->from()->id == peerFromMTP(d.vpeer) && item->channelId() != NoChannel) { + // CHANNELS_TODO + } + } } break; } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 50ce9f108f..13c014a88e 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -380,6 +380,10 @@ public: void contactsReceived(); + void ptsWaiterStartTimerFor(ChannelData *channel, int32 ms); // ms <= 0 - stop timer + void handleUpdates(const MTPUpdates &updates, uint64 randomId = 0); + void feedUpdate(const MTPUpdate &update); + ~MainWidget(); signals: @@ -414,8 +418,9 @@ public slots: void onParentResize(const QSize &newSize); void getDifference(); + void onGetDifferenceTimeByPts(); + void onGetDifferenceTimeAfterFail(); void mtpPing(); - void getDifferenceForce(); void updateOnline(bool gotOtherOffline = false); void checkIdleFinish(); @@ -476,18 +481,25 @@ private: SingleTimer _updateMutedTimer; + enum GetChannelDifferenceFrom { + GetChannelDifferenceFromUnknown, + GetChannelDifferenceFromPtsGap, + GetChannelDifferenceFromFail, + }; + void getChannelDifference(ChannelData *channel, GetChannelDifferenceFrom from = GetChannelDifferenceFromUnknown); void gotDifference(const MTPupdates_Difference &diff); bool failDifference(const RPCError &e); void feedDifference(const MTPVector &users, const MTPVector &chats, const MTPVector &msgs, const MTPVector &other); void gotState(const MTPupdates_State &state); void updSetState(int32 pts, int32 date, int32 qts, int32 seq); + void gotChannelDifference(ChannelData *channel, const MTPupdates_ChannelDifference &diff); + bool failChannelDifference(ChannelData *channel, const RPCError &err); + void failDifferenceStartTimerFor(ChannelData *channel); void feedUpdates(const MTPVector &updates, bool skipMessageIds = false); void feedMessageIds(const MTPVector &updates); - void feedUpdate(const MTPUpdate &update); void updateReceived(const mtpPrime *from, const mtpPrime *end); - void handleUpdates(const MTPUpdates &updates, uint64 randomId = 0); bool updateFail(const RPCError &e); void usernameResolveDone(QPair toProfileStartToken, const MTPcontacts_ResolvedPeer &result); @@ -529,12 +541,25 @@ private: Dropdown _mediaType; int32 _mediaTypeMask; - int updGoodPts, updLastPts, updPtsCount; - int updDate, updQts, updSeq; - bool updInited; - int updSkipPtsUpdateLevel; + int32 updDate, updQts, updSeq; SingleTimer noUpdatesTimer; + bool ptsUpdated(int32 pts, int32 ptsCount); + bool ptsUpdated(int32 pts, int32 ptsCount, const MTPUpdates &updates); + bool ptsUpdated(int32 pts, int32 ptsCount, const MTPUpdate &update); + PtsWaiter _ptsWaiter; + + typedef QMap ChannelGetDifferenceTime; + ChannelGetDifferenceTime _channelGetDifferenceTimeByPts, _channelGetDifferenceTimeAfterFail; + uint64 _getDifferenceTimeByPts, _getDifferenceTimeAfterFail; + + bool getDifferenceTimeChanged(ChannelData *channel, int32 ms, ChannelGetDifferenceTime &channelCurTime, uint64 &curTime); + + SingleTimer _byPtsTimer; + + QMap _bySeqUpdates; + SingleTimer _bySeqTimer; + mtpRequestId _onlineRequest; SingleTimer _onlineTimer, _onlineUpdater, _idleFinishTimer; bool _lastWasOnline; @@ -552,27 +577,9 @@ private: typedef QMap OverviewsPreload; OverviewsPreload _overviewPreload[OverviewCount], _overviewLoad[OverviewCount]; - enum PtsSkippedQueue { - SkippedUpdate, - SkippedUpdates, -// SkippedSentMessage, - SkippedStatedMessage, - SkippedStatedMessages - }; - uint64 ptsKey(PtsSkippedQueue queue); - void applySkippedPtsUpdates(); - void clearSkippedPtsUpdates(); - bool updPtsUpdated(int pts, int ptsCount); - QMap _byPtsQueue; - QMap _byPtsUpdate; - QMap _byPtsUpdates; -// QMap _byPtsSentMessage; - SingleTimer _byPtsTimer; - - QMap _bySeqUpdates; - SingleTimer _bySeqTimer; - int32 _failDifferenceTimeout; // growing timeout for getDifference calls, if it fails + typedef QMap ChannelFailDifferenceTimeout; + ChannelFailDifferenceTimeout _channelFailDifferenceTimeout; // growing timeout for getChannelDifference calls, if it fails SingleTimer _failDifferenceTimer; uint64 _lastUpdateTime; diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.cpp b/Telegram/SourceFiles/mtproto/mtpConnection.cpp index 58b0e77454..1953b7fd66 100644 --- a/Telegram/SourceFiles/mtproto/mtpConnection.cpp +++ b/Telegram/SourceFiles/mtproto/mtpConnection.cpp @@ -1950,6 +1950,8 @@ void MTProtoConnectionPrivate::socketStart(bool afterConfig) { } void MTProtoConnectionPrivate::restart(bool maybeBadKey) { + _needSessionReset = true; + QReadLocker lockFinished(&sessionDataMutex); if (!sessionData) return; diff --git a/Telegram/SourceFiles/mtproto/mtpSessionImpl.h b/Telegram/SourceFiles/mtproto/mtpSessionImpl.h index 033cab32d4..c59fae7596 100644 --- a/Telegram/SourceFiles/mtproto/mtpSessionImpl.h +++ b/Telegram/SourceFiles/mtproto/mtpSessionImpl.h @@ -29,7 +29,7 @@ mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler ca reqSerialized->msDate = getms(true); // > 0 - can send without container reqSerialized->needsLayer = needsLayer; - if (after) reqSerialized->after = _mtp_internal::getRequest(after); +// if (after) reqSerialized->after = _mtp_internal::getRequest(after); requestId = _mtp_internal::storeRequest(reqSerialized, callbacks); sendPrepared(reqSerialized, msCanWait); diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 5c9f3f91a9..3fad64c8db 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -325,6 +325,12 @@ void OverviewInner::searchReceived(bool fromStart, const MTPmessages_Messages &r case mtpc_messages_channelMessages: { const MTPDmessages_channelMessages &d(result.c_messages_channelMessages()); + if (_peer && _peer->isChannel()) { + _peer->asChannel()->ptsReceived(d.vpts.v); + } else { + LOG(("App Error: received messages.channelMessages in OverviewInner::searchReceived when no channel was passed!")); + } + App::feedUsers(d.vusers); App::feedChats(d.vchats); messages = &d.vmessages.c_vector().v; diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 30f1d023ea..247b42c415 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -362,6 +362,71 @@ void ChannelData::setName(const QString &newName, const QString &usern) { } } +uint64 PtsWaiter::ptsKey(PtsSkippedQueue queue) { + return _queue.insert(uint64(uint32(_last)) << 32 | uint64(uint32(_count)), queue).key(); +} + +void PtsWaiter::applySkippedUpdates(ChannelData *channel) { + if (!App::main()) return; + App::main()->ptsWaiterStartTimerFor(channel, -1); + + if (_queue.isEmpty()) return; + ++_applySkippedLevel; + for (QMap::const_iterator i = _queue.cbegin(), e = _queue.cend(); i != e; ++i) { + switch (i.value()) { + case SkippedUpdate: App::main()->feedUpdate(_updateQueue.value(i.key())); break; + case SkippedUpdates: App::main()->handleUpdates(_updatesQueue.value(i.key())); break; + } + } + --_applySkippedLevel; + clearSkippedUpdates(); + App::emitPeerUpdated(); +} + +void PtsWaiter::clearSkippedUpdates() { + _queue.clear(); + _updateQueue.clear(); + _updatesQueue.clear(); + _applySkippedLevel = 0; +} + +bool PtsWaiter::updated(ChannelData *channel, int32 pts, int32 count) { // return false if need to save that update and apply later + if (_requesting || _applySkippedLevel) return true; + + if (!inited()) { + init(pts); + return true; + } + _last = qMax(_last, pts); + _count += count; + if (_last == _count) { + applySkippedUpdates(channel); + _good = _last; + return true; + } else if (_last < _count) { + if (App::main()) App::main()->ptsWaiterStartTimerFor(channel, 1); + } else { + if (App::main()) App::main()->ptsWaiterStartTimerFor(channel, WaitForSkippedTimeout); + } + return !count; +} + +bool PtsWaiter::updated(ChannelData *channel, int32 pts, int32 ptsCount, const MTPUpdates &updates) { + if (!updated(channel, pts, ptsCount)) { + _updatesQueue.insert(ptsKey(SkippedUpdates), updates); + return false; + } + return true; +} + +bool PtsWaiter::updated(ChannelData *channel, int32 pts, int32 ptsCount, const MTPUpdate &update) { + if (!updated(channel, pts, ptsCount)) { + _updateQueue.insert(ptsKey(SkippedUpdate), update); + return false; + } + return true; +} + void PhotoLink::onClick(Qt::MouseButton button) const { if (button == Qt::LeftButton) { App::wnd()->showPhoto(this, App::hoveredLinkItem()); diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index 898fe92e17..e17d53a8c9 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -86,6 +86,22 @@ inline MTPpeer peerToMTP(const PeerId &id) { } return MTP_peerUser(MTP_int(0)); } +inline PeerId peerFromMessage(const MTPmessage &msg, int32 *msgFlags = 0) { + PeerId from_id = 0, to_id = 0; + switch (msg.type()) { + case mtpc_message: + from_id = msg.c_message().has_from_id() ? peerFromUser(msg.c_message().vfrom_id) : 0; + to_id = peerFromMTP(msg.c_message().vto_id); + if (msgFlags) *msgFlags = msg.c_message().vflags.v; + break; + case mtpc_messageService: + from_id = msg.c_messageService().has_from_id() ? peerFromUser(msg.c_messageService().vfrom_id) : 0; + to_id = peerFromMTP(msg.c_messageService().vto_id); + if (msgFlags) *msgFlags = msg.c_messageService().vflags.v; + break; + } + return (from_id && peerToUser(to_id) == MTP::authedId()) ? from_id : to_id; +} typedef uint64 PhotoId; typedef uint64 VideoId; @@ -355,6 +371,47 @@ public: QString invitationUrl; }; +enum PtsSkippedQueue { + SkippedUpdate, + SkippedUpdates, +}; +class PtsWaiter { +public: + + PtsWaiter() : _good(0), _last(0), _count(0), _applySkippedLevel(0), _requesting(false) { + } + void init(int32 pts) { + _good = _last = _count = pts; + clearSkippedUpdates(); + } + bool inited() const { + return _good > 0; + } + void setRequesting(bool isRequesting) { + _requesting = isRequesting; + } + bool requesting() const { + return _requesting; + } + int32 current() const{ + return _good; + } + bool updated(ChannelData *channel, int32 pts, int32 count); + bool updated(ChannelData *channel, int32 pts, int32 count, const MTPUpdates &updates); + bool updated(ChannelData *channel, int32 pts, int32 count, const MTPUpdate &update); + void applySkippedUpdates(ChannelData *channel); + void clearSkippedUpdates(); + +private: + uint64 ptsKey(PtsSkippedQueue queue); + QMap _queue; + QMap _updateQueue; + QMap _updatesQueue; + int32 _good, _last, _count; + int32 _applySkippedLevel; + bool _requesting; +}; + class ChannelData : public PeerData { public: @@ -378,6 +435,35 @@ public: int32 botStatus; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other // ImagePtr photoFull; QString invitationUrl; + + void ptsReceived(int32 pts) { + _ptsWaiter.updated(this, pts, 0); + } + bool ptsUpdated(int32 pts, int32 count) { + return _ptsWaiter.updated(this, pts, count); + } + bool ptsUpdated(int32 pts, int32 count, const MTPUpdate &update) { + return _ptsWaiter.updated(this, pts, count, update); + } + int32 pts() const { + return _ptsWaiter.current(); + } + bool ptsInited() const { + return _ptsWaiter.inited(); + } + bool ptsRequesting() const { + return _ptsWaiter.requesting(); + } + void ptsSetRequesting(bool isRequesting) { + return _ptsWaiter.setRequesting(isRequesting); + } + void ptsClearSkippedUpdates() { + return _ptsWaiter.clearSkippedUpdates(); + } + +private: + + PtsWaiter _ptsWaiter; }; inline UserData *PeerData::asUser() {