Optimize getPeerDialog requests.

This commit is contained in:
John Preston 2019-01-16 13:01:38 +04:00
parent 2a5bcd3eec
commit 287b3509ab
8 changed files with 174 additions and 193 deletions

View File

@ -257,26 +257,23 @@ void ApiWrap::getProxyPromotionDelayed(TimeId now, TimeId next) {
};
void ApiWrap::proxyPromotionDone(const MTPhelp_ProxyData &proxy) {
if (proxy.type() == mtpc_help_proxyDataEmpty) {
const auto &data = proxy.c_help_proxyDataEmpty();
const auto next = _proxyPromotionNextRequestTime = data.vexpires.v;
getProxyPromotionDelayed(unixtime(), next);
_session->data().setProxyPromoted(nullptr);
return;
}
Assert(proxy.type() == mtpc_help_proxyDataPromo);
const auto &data = proxy.c_help_proxyDataPromo();
const auto next = _proxyPromotionNextRequestTime = data.vexpires.v;
getProxyPromotionDelayed(unixtime(), next);
_proxyPromotionNextRequestTime = proxy.match([&](const auto &data) {
return data.vexpires.v;
});
getProxyPromotionDelayed(unixtime(), _proxyPromotionNextRequestTime);
App::feedChats(data.vchats);
App::feedUsers(data.vusers);
const auto peerId = peerFromMTP(data.vpeer);
const auto peer = App::peer(peerId);
_session->data().setProxyPromoted(peer);
if (const auto history = App::historyLoaded(peer)) {
requestDialogEntry(history);
}
proxy.match([&](const MTPDhelp_proxyDataEmpty &data) {
_session->data().setProxyPromoted(nullptr);
}, [&](const MTPDhelp_proxyDataPromo &data) {
App::feedChats(data.vchats);
App::feedUsers(data.vusers);
const auto peerId = peerFromMTP(data.vpeer);
const auto peer = _session->data().peer(peerId);
_session->data().setProxyPromoted(peer);
if (const auto history = App::historyLoaded(peer)) {
requestDialogEntry(history);
}
});
}
void ApiWrap::requestDeepLinkInfo(
@ -687,69 +684,78 @@ void ApiWrap::requestDialogEntry(not_null<Data::Feed*> feed) {
void ApiWrap::requestDialogEntry(
not_null<History*> history,
Fn<void()> callback) {
const auto[i, ok] = _dialogRequests.try_emplace(history);
const auto i = _dialogRequests.find(history);
if (i != end(_dialogRequests)) {
if (callback) {
i->second.push_back(std::move(callback));
}
return;
}
const auto [j, ok] = _dialogRequestsPending.try_emplace(history);
if (callback) {
i->second.push_back(std::move(callback));
j->second.push_back(std::move(callback));
}
if (!ok) {
return;
}
if (_dialogRequestsPending.size() > 1) {
return;
}
Core::App().postponeCall(crl::guard(_session, [=] {
sendDialogRequests();
}));
}
void ApiWrap::sendDialogRequests() {
if (_dialogRequestsPending.empty()) {
return;
}
auto histories = std::vector<not_null<History*>>();
ranges::transform(
_dialogRequestsPending,
ranges::back_inserter(histories),
[](const auto &pair) { return pair.first; });
auto peers = QVector<MTPInputDialogPeer>();
const auto dialogPeer = [](not_null<History*> history) {
return MTP_inputDialogPeer(history->peer->input);
};
ranges::transform(
histories,
ranges::back_inserter(peers),
dialogPeer);
for (auto &[history, callbacks] : base::take(_dialogRequestsPending)) {
_dialogRequests.emplace(history, std::move(callbacks));
}
const auto finalize = [=] {
if (const auto callbacks = _dialogRequests.take(history)) {
for (const auto &callback : *callbacks) {
callback();
}
for (const auto history : histories) {
dialogEntryApplied(history);
history->updateChatListExistence();
}
};
auto peers = QVector<MTPInputDialogPeer>(
1,
MTP_inputDialogPeer(history->peer->input));
request(MTPmessages_GetPeerDialogs(
MTP_vector(std::move(peers))
)).done([=](const MTPmessages_PeerDialogs &result) {
applyPeerDialogs(result);
history->dialogEntryApplied();
finalize();
}).fail([=](const RPCError &error) {
finalize();
}).send();
}
void ApiWrap::requestDialogEntries(
std::vector<not_null<History*>> histories) {
const auto already = [&](not_null<History*> history) {
const auto [i, ok] = _dialogRequests.try_emplace(history);
return !ok;
};
histories.erase(ranges::remove_if(histories, already), end(histories));
if (histories.empty()) {
return;
}
auto peers = QVector<MTPInputDialogPeer>();
peers.reserve(histories.size());
for (const auto history : histories) {
peers.push_back(MTP_inputDialogPeer(history->peer->input));
}
const auto finalize = [=](std::vector<not_null<History*>> histories) {
for (const auto history : histories) {
if (const auto callbacks = _dialogRequests.take(history)) {
for (const auto &callback : *callbacks) {
callback();
}
}
void ApiWrap::dialogEntryApplied(not_null<History*> history) {
history->dialogEntryApplied();
if (const auto callbacks = _dialogRequestsPending.take(history)) {
for (const auto &callback : *callbacks) {
callback();
}
};
request(MTPmessages_GetPeerDialogs(
MTP_vector(std::move(peers))
)).done([=](const MTPmessages_PeerDialogs &result) {
applyPeerDialogs(result);
for (const auto history : histories) {
history->dialogEntryApplied();
}
if (const auto callbacks = _dialogRequests.take(history)) {
for (const auto &callback : *callbacks) {
callback();
}
finalize(histories);
}).fail([=](const RPCError &error) {
finalize(histories);
}).send();
}
}
void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
@ -1490,7 +1496,7 @@ void ApiWrap::applyLastParticipantsList(
Notify::peerUpdatedDelayed(update);
channel->mgInfo->botStatus = botStatus;
if (App::main()) fullPeerUpdated().notify(channel);
fullPeerUpdated().notify(channel);
}
void ApiWrap::applyBotsList(
@ -1532,7 +1538,7 @@ void ApiWrap::applyBotsList(
}
channel->mgInfo->botStatus = botStatus;
if (App::main()) fullPeerUpdated().notify(channel);
fullPeerUpdated().notify(channel);
}
void ApiWrap::applyAdminsList(
@ -1568,58 +1574,58 @@ void ApiWrap::applyAdminsList(
}
}
void ApiWrap::requestSelfParticipant(ChannelData *channel) {
void ApiWrap::requestSelfParticipant(not_null<ChannelData*> channel) {
if (_selfParticipantRequests.contains(channel)) {
return;
}
auto requestId = request(MTPchannels_GetParticipant(
const auto finalize = [=](UserId inviter, TimeId inviteDate) {
channel->inviter = inviter;
channel->inviteDate = inviteDate;
if (const auto history = App::historyLoaded(channel)) {
if (history->lastMessageKnown()) {
history->checkJoinedMessage(true);
history->owner().sendHistoryChangeNotifications();
} else {
requestDialogEntry(history);
}
}
};
_selfParticipantRequests.emplace(channel);
request(MTPchannels_GetParticipant(
channel->inputChannel,
MTP_inputUserSelf()
)).done([this, channel](const MTPchannels_ChannelParticipant &result) {
_selfParticipantRequests.remove(channel);
if (result.type() != mtpc_channels_channelParticipant) {
LOG(("API Error: unknown type in gotSelfParticipant (%1)").arg(result.type()));
channel->inviter = -1;
if (App::main()) App::main()->onSelfParticipantUpdated(channel);
return;
}
)).done([=](const MTPchannels_ChannelParticipant &result) {
_selfParticipantRequests.erase(channel);
result.match([&](const MTPDchannels_channelParticipant &data) {
App::feedUsers(data.vusers);
auto &p = result.c_channels_channelParticipant();
App::feedUsers(p.vusers);
switch (p.vparticipant.type()) {
case mtpc_channelParticipantSelf: {
auto &d = p.vparticipant.c_channelParticipantSelf();
channel->inviter = d.vinviter_id.v;
channel->inviteDate = d.vdate.v;
} break;
case mtpc_channelParticipantCreator: {
auto &d = p.vparticipant.c_channelParticipantCreator();
channel->inviter = _session->userId();
channel->inviteDate = channel->date;
if (channel->mgInfo) {
channel->mgInfo->creator = _session->user();
}
} break;
case mtpc_channelParticipantAdmin: {
auto &d = p.vparticipant.c_channelParticipantAdmin();
channel->inviter = (d.is_self() && d.has_inviter_id())
? d.vinviter_id.v
: 0;
channel->inviteDate = d.vdate.v;
} break;
}
if (App::main()) App::main()->onSelfParticipantUpdated(channel);
}).fail([this, channel](const RPCError &error) {
_selfParticipantRequests.remove(channel);
if (error.type() == qstr("USER_NOT_PARTICIPANT")) {
channel->inviter = -1;
}
const auto &participant = data.vparticipant;
participant.match([&](const MTPDchannelParticipantSelf &data) {
finalize(data.vinviter_id.v, data.vdate.v);
}, [&](const MTPDchannelParticipantCreator &) {
if (channel->mgInfo) {
channel->mgInfo->creator = _session->user();
}
finalize(_session->userId(), channel->date);
}, [&](const MTPDchannelParticipantAdmin &data) {
const auto inviter = (data.is_self()
&& data.has_inviter_id())
? data.vinviter_id.v
: -1;
finalize(inviter, data.vdate.v);
}, [&](const MTPDchannelParticipantBanned &data) {
LOG(("API Error: Got self banned participant."));
finalize(-1, 0);
}, [&](const MTPDchannelParticipant &data) {
LOG(("API Error: Got self regular participant."));
finalize(-1, 0);
});
});
}).fail([=](const RPCError &error) {
_selfParticipantRequests.erase(channel);
finalize(-1, 0);
}).afterDelay(kSmallDelayMs).send();
_selfParticipantRequests.insert(channel, requestId);
}
void ApiWrap::kickParticipant(

View File

@ -83,7 +83,7 @@ public:
void requestDialogEntry(
not_null<History*> history,
Fn<void()> callback = nullptr);
void requestDialogEntries(std::vector<not_null<History*>> histories);
void dialogEntryApplied(not_null<History*> history);
//void applyFeedSources(const MTPDchannels_feedSources &data); // #feed
//void setFeedChannels(
// not_null<Data::Feed*> feed,
@ -146,7 +146,7 @@ public:
void markMediaRead(const base::flat_set<not_null<HistoryItem*>> &items);
void markMediaRead(not_null<HistoryItem*> item);
void requestSelfParticipant(ChannelData *channel);
void requestSelfParticipant(not_null<ChannelData*> channel);
void kickParticipant(not_null<ChatData*> chat, not_null<UserData*> user);
void kickParticipant(
not_null<ChannelData*> channel,
@ -592,6 +592,8 @@ private:
not_null<ChannelData*> channel);
void migrateFail(not_null<PeerData*> peer, const RPCError &error);
void sendDialogRequests();
not_null<AuthSession*> _session;
MessageDataRequests _messageDataRequests;
@ -624,7 +626,7 @@ private:
not_null<PeerData*>,
mtpRequestId> _defaultRestrictionsRequests;
QMap<ChannelData*, mtpRequestId> _selfParticipantRequests;
base::flat_set<not_null<ChannelData*>> _selfParticipantRequests;
base::flat_map<
not_null<ChannelData*>,
@ -666,6 +668,9 @@ private:
base::flat_map<
not_null<History*>,
std::vector<Fn<void()>>> _dialogRequests;
base::flat_map<
not_null<History*>,
std::vector<Fn<void()>>> _dialogRequestsPending;
base::flat_set<not_null<History*>> _fakeChatListRequests;
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;

View File

@ -1298,14 +1298,14 @@ void DialogsInner::createDialog(Dialogs::Key key) {
const auto from = dialogsOffset() + changed.movedFrom * st::dialogsRowHeight;
const auto to = dialogsOffset() + changed.movedTo * st::dialogsRowHeight;
if (!_dragging) {
if (!_dragging && from != to) {
// Don't jump in chats list scroll position while dragging.
emit dialogMoved(from, to);
}
if (creating) {
refresh();
} else if (_state == State::Default && changed.movedFrom != changed.movedTo) {
} else if (_state == State::Default && from != to) {
update(0, qMin(from, to), getFullWidth(), qAbs(from - to) + st::dialogsRowHeight);
}
}
@ -1948,7 +1948,6 @@ bool DialogsInner::searchReceived(
auto isGlobalSearch = (type == DialogsSearchFromStart || type == DialogsSearchFromOffset);
auto isMigratedSearch = (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset);
auto unknownUnreadCounts = std::vector<not_null<History*>>();
TimeId lastDateFound = 0;
for (const auto &message : messages) {
auto msgId = IdFromMessage(message);
@ -1966,7 +1965,7 @@ bool DialogsInner::searchReceived(
_searchInChat,
item));
if (uniquePeers && !history->unreadCountKnown()) {
unknownUnreadCounts.push_back(history);
history->session().api().requestDialogEntry(history);
}
}
lastDateFound = lastDate;
@ -2001,9 +2000,6 @@ bool DialogsInner::searchReceived(
refresh();
if (!unknownUnreadCounts.empty()) {
Auth().api().requestDialogEntries(std::move(unknownUnreadCounts));
}
return lastDateFound != 0;
}
@ -2123,16 +2119,15 @@ void DialogsInner::notify_historyMuteUpdated(History *history) {
return;
}
int from = dialogsOffset() + changed.movedFrom * st::dialogsRowHeight;
int to = dialogsOffset() + changed.movedTo * st::dialogsRowHeight;
if (!_dragging) {
const auto from = dialogsOffset() + changed.movedFrom * st::dialogsRowHeight;
const auto to = dialogsOffset() + changed.movedTo * st::dialogsRowHeight;
if (!_dragging && from != to) {
// Don't jump in chats list scroll position while dragging.
emit dialogMoved(from, to);
}
if (creating) {
refresh();
} else if (_state == State::Default && changed.movedFrom != changed.movedTo) {
} else if (_state == State::Default && from != to) {
update(0, qMin(from, to), getFullWidth(), qAbs(from - to) + st::dialogsRowHeight);
}
}

View File

@ -481,36 +481,29 @@ void DialogsWidget::updateDialogsOffset(
auto lastDate = TimeId(0);
auto lastPeer = PeerId(0);
auto lastMsgId = MsgId(0);
const auto fillFromDialog = [&](const auto &dialog) {
const auto peer = peerFromMTP(dialog.vpeer);
const auto msgId = dialog.vtop_message.v;
if (!peer || !msgId) {
return;
}
if (!lastPeer) {
lastPeer = peer;
}
if (!lastMsgId) {
lastMsgId = msgId;
}
for (auto j = messages.size(); j != 0;) {
const auto &message = messages[--j];
if (IdFromMessage(message) == msgId
&& PeerFromMessage(message) == peer) {
if (const auto date = DateFromMessage(message)) {
lastDate = date;
}
for (const auto &dialog : ranges::view::reverse(dialogs)) {
dialog.match([&](const auto &dialog) {
const auto peer = peerFromMTP(dialog.vpeer);
const auto messageId = dialog.vtop_message.v;
if (!peer || !messageId) {
return;
}
}
};
for (auto i = dialogs.size(); i != 0;) {
const auto &dialog = dialogs[--i];
switch (dialog.type()) {
case mtpc_dialog: fillFromDialog(dialog.c_dialog()); break;
// case mtpc_dialogFeed: fillFromDialog(dialog.c_dialogFeed()); break; // #feed
default: Unexpected("Type in DialogsWidget::updateDialogsOffset");
}
if (!lastPeer) {
lastPeer = peer;
}
if (!lastMsgId) {
lastMsgId = messageId;
}
for (const auto &message : ranges::view::reverse(messages)) {
if (IdFromMessage(message) == messageId
&& PeerFromMessage(message) == peer) {
if (const auto date = DateFromMessage(message)) {
lastDate = date;
}
return;
}
}
});
if (lastDate) {
break;
}

View File

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "apiwrap.h"
#include "mainwidget.h"
#include "application.h"
#include "mainwindow.h"
#include "storage/localstorage.h"
#include "observer_peer.h"
@ -2178,7 +2179,9 @@ void History::setChatListMessageFromLast() {
void History::requestChatListMessage() {
if (!lastMessageKnown()) {
session().api().requestDialogEntry(this);
session().api().requestDialogEntry(this, [=] {
requestChatListMessage();
});
return;
} else if (chatListMessageKnown()) {
return;
@ -2336,13 +2339,16 @@ void History::applyDialog(const MTPDdialog &data) {
if (data.has_draft() && data.vdraft.type() == mtpc_draftMessage) {
Data::applyPeerCloudDraft(peer->id, data.vdraft.c_draftMessage());
}
session().api().dialogEntryApplied(this);
}
void History::dialogEntryApplied() {
if (!lastMessageKnown()) {
setLastMessage(nullptr);
}
if (!chatListMessageKnown()) {
if (peer->migrateTo()) {
return;
} else if (!chatListMessageKnown()) {
requestChatListMessage();
return;
}
@ -2371,7 +2377,7 @@ void History::dialogEntryApplied() {
if (chatListTimeId() != 0 && loadedAtBottom()) {
if (const auto channel = peer->asChannel()) {
const auto inviter = channel->inviter;
if (inviter != 0
if (inviter > 0
&& chatListTimeId() <= channel->inviteDate
&& channel->amIn()) {
if (const auto from = App::userLoaded(inviter)) {
@ -2380,7 +2386,6 @@ void History::dialogEntryApplied() {
}
}
}
updateChatListExistence();
}
bool History::clearUnreadOnClientSide() const {

View File

@ -306,7 +306,7 @@ void NotificationsController::applyFeedDialogs(
const auto history = App::history(peerId);
const auto channel = history->peer->asChannel();
history->applyDialog(dialog.c_dialog());
channels.push_back(channel);
channels.emplace_back(channel);
} else {
LOG(("API Error: "
"Unexpected non-channel in feed dialogs list."));

View File

@ -3305,24 +3305,6 @@ void MainWidget::openPeerByName(
}
}
void MainWidget::onSelfParticipantUpdated(ChannelData *channel) {
auto history = App::historyLoaded(channel->id);
if (_updatedChannels.contains(channel)) {
_updatedChannels.remove(channel);
if (!history) {
history = App::history(channel);
}
if (history->isEmpty()) {
Auth().api().requestDialogEntry(history);
} else {
history->checkJoinedMessage(true);
}
} else if (history) {
history->checkJoinedMessage();
}
Auth().data().sendHistoryChangeNotifications();
}
bool MainWidget::contentOverlapped(const QRect &globalRect) {
return (_history->contentOverlapped(globalRect)
|| _playerPanel->overlaps(globalRect)
@ -4461,22 +4443,21 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
auto &d = update.c_updateChannel();
if (const auto channel = App::channelLoaded(d.vchannel_id.v)) {
channel->inviter = UserId(0);
if (channel->amIn()
&& !channel->amCreator()
&& App::history(channel->id)) {
_updatedChannels.insert(channel, true);
Auth().api().requestSelfParticipant(channel);
}
if (const auto feed = channel->feed()) {
feed->requestChatListMessage();
if (!feed->unreadCountKnown()) {
feed->session().api().requestDialogEntry(feed);
if (channel->amIn()) {
const auto history = App::history(channel);
if (const auto feed = channel->feed()) {
feed->requestChatListMessage();
if (!feed->unreadCountKnown()) {
feed->session().api().requestDialogEntry(feed);
}
} else {
history->requestChatListMessage();
if (!history->unreadCountKnown()) {
history->session().api().requestDialogEntry(history);
}
}
} else if (channel->amIn()) {
const auto history = App::history(channel->id);
history->requestChatListMessage();
if (!history->unreadCountKnown()) {
history->session().api().requestDialogEntry(history);
if (!channel->amCreator()) {
Auth().api().requestSelfParticipant(channel);
}
}
}

View File

@ -253,7 +253,6 @@ public:
void scheduleViewIncrement(HistoryItem *item);
void onSelfParticipantUpdated(ChannelData *channel);
void feedChannelDifference(const MTPDupdates_channelDifference &data);
// Mayde public for ApiWrap, while it is still here.
@ -537,9 +536,6 @@ private:
int _cachedY = 0;
SingleTimer _cacheBackgroundTimer;
typedef QMap<ChannelData*, bool> UpdatedChannels;
UpdatedChannels _updatedChannels;
PhotoData *_deletingPhoto = nullptr;
typedef QMap<MsgId, bool> ViewsIncrementMap;