Initial support for min-user-from-message request.

This commit is contained in:
John Preston
2025-12-18 21:18:33 +04:00
parent 66645ce523
commit 53324d5494
12 changed files with 184 additions and 136 deletions

View File

@@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/stickers/data_custom_emoji.h"
#include "data/stickers/data_stickers_set.h"
#include "history/history.h"
#include "history/history_item.h"
#include "main/main_session.h"
namespace Api {
@@ -47,14 +49,23 @@ using namespace TextUtilities;
if (!parsed.userId || parsed.selfId != session->userId().bare) {
return {};
}
return MTP_inputMessageEntityMentionName(
offset,
length,
(parsed.userId == parsed.selfId
? MTP_inputUserSelf()
: MTP_inputUser(
MTP_long(parsed.userId),
MTP_long(parsed.accessHash))));
const auto user = session->data().user(UserId(parsed.userId));
const auto item = user->isLoaded()
? nullptr
: user->owner().messageWithPeer(user->id);
const auto input = item
? MTP_inputUserFromMessage(
item->history()->peer->input(),
MTP_int(item->id.bare),
MTP_long(parsed.userId))
: (parsed.userId == parsed.selfId)
? MTP_inputUserSelf()
: user->isLoaded()
? user->inputUser()
: MTP_inputUser(
MTP_long(parsed.userId),
MTP_long(parsed.accessHash));
return MTP_inputMessageEntityMentionName(offset, length, input);
}
} // namespace

View File

@@ -137,100 +137,6 @@ bool HasForceLogoutNotification(const MTPUpdates &updates) {
return false;
}
bool ForwardedInfoDataLoaded(
not_null<Main::Session*> session,
const MTPMessageFwdHeader &header) {
return header.match([&](const MTPDmessageFwdHeader &data) {
if (const auto fromId = data.vfrom_id()) {
// Fully loaded is required in this case.
if (!session->data().peerLoaded(peerFromMTP(*fromId))) {
return false;
}
}
return true;
});
}
bool MentionUsersLoaded(
not_null<Main::Session*> session,
const MTPVector<MTPMessageEntity> &entities) {
for (const auto &entity : entities.v) {
auto type = entity.type();
if (type == mtpc_messageEntityMentionName) {
if (!session->data().userLoaded(entity.c_messageEntityMentionName().vuser_id())) {
return false;
}
} else if (type == mtpc_inputMessageEntityMentionName) {
auto &inputUser = entity.c_inputMessageEntityMentionName().vuser_id();
if (inputUser.type() == mtpc_inputUser) {
if (!session->data().userLoaded(inputUser.c_inputUser().vuser_id())) {
return false;
}
}
}
}
return true;
}
DataIsLoadedResult AllDataLoadedForMessage(
not_null<Main::Session*> session,
const MTPMessage &message) {
return message.match([&](const MTPDmessage &message) {
if (const auto fromId = message.vfrom_id()) {
if (!message.is_post()
&& !session->data().peerLoaded(peerFromMTP(*fromId))) {
return DataIsLoadedResult::FromNotLoaded;
}
}
if (const auto viaBotId = message.vvia_bot_id()) {
if (!session->data().userLoaded(*viaBotId)) {
return DataIsLoadedResult::NotLoaded;
}
}
if (const auto fwd = message.vfwd_from()) {
if (!ForwardedInfoDataLoaded(session, *fwd)) {
return DataIsLoadedResult::NotLoaded;
}
}
if (const auto entities = message.ventities()) {
if (!MentionUsersLoaded(session, *entities)) {
return DataIsLoadedResult::MentionNotLoaded;
}
}
return DataIsLoadedResult::Ok;
}, [&](const MTPDmessageService &message) {
if (const auto fromId = message.vfrom_id()) {
if (!message.is_post()
&& !session->data().peerLoaded(peerFromMTP(*fromId))) {
return DataIsLoadedResult::FromNotLoaded;
}
}
return message.vaction().match(
[&](const MTPDmessageActionChatAddUser &action) {
for (const auto &userId : action.vusers().v) {
if (!session->data().userLoaded(userId)) {
return DataIsLoadedResult::NotLoaded;
}
}
return DataIsLoadedResult::Ok;
}, [&](const MTPDmessageActionChatJoinedByLink &action) {
if (!session->data().userLoaded(action.vinviter_id())) {
return DataIsLoadedResult::NotLoaded;
}
return DataIsLoadedResult::Ok;
}, [&](const MTPDmessageActionChatDeleteUser &action) {
if (!session->data().userLoaded(action.vuser_id())) {
return DataIsLoadedResult::NotLoaded;
}
return DataIsLoadedResult::Ok;
}, [](const auto &) {
return DataIsLoadedResult::Ok;
});
}, [](const MTPDmessageEmpty &message) {
return DataIsLoadedResult::Ok;
});
}
} // namespace
Updates::Updates(not_null<Main::Session*> session)
@@ -1613,25 +1519,13 @@ void Updates::feedUpdate(const MTPUpdate &update) {
// New messages.
case mtpc_updateNewMessage: {
auto &d = update.c_updateNewMessage();
const auto isDataLoaded = AllDataLoadedForMessage(&session(), d.vmessage());
if (!requestingDifference() && isDataLoaded != DataIsLoadedResult::Ok) {
MTP_LOG(0, ("getDifference "
"{ good - after not all data loaded in updateNewMessage }%1"
).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
// This can be if this update was created by grouping
// some short message update into an updates vector.
return getDifference();
}
_session->data().fillMessagePeers(d.vmessage());
updateAndApply(d.vpts().v, d.vpts_count().v, update);
} break;
case mtpc_updateNewChannelMessage: {
auto &d = update.c_updateNewChannelMessage();
auto channel = session().data().channelLoaded(peerToChannel(PeerFromMessage(d.vmessage())));
const auto isDataLoaded = AllDataLoadedForMessage(&session(), d.vmessage());
{
// Todo delete.
const auto messageId = IdFromMessage(d.vmessage());
@@ -1643,27 +1537,16 @@ void Updates::feedUpdate(const MTPUpdate &update) {
}
}
}
if (!requestingDifference() && (!channel || isDataLoaded != DataIsLoadedResult::Ok)) {
if (!requestingDifference() && !channel) {
MTP_LOG(0, ("getDifference "
"{ good - after not all data loaded in updateNewChannelMessage }%1"
).arg(_session->mtp().isTestMode() ? " TESTMODE" : ""));
// Request last active supergroup participants if the 'from' user was not loaded yet.
// This will optimize similar getDifference() calls for almost all next messages.
if (isDataLoaded == DataIsLoadedResult::FromNotLoaded && channel && channel->isMegagroup()) {
if (channel->canViewMembers()
&& channel->mgInfo->lastParticipants.size() < _session->serverConfig().chatSizeMax
&& (channel->mgInfo->lastParticipants.empty()
|| channel->mgInfo->lastParticipants.size() < channel->membersCount())) {
session().api().chatParticipants().requestLast(channel);
}
}
if (!_byMinChannelTimer.isActive()) { // getDifference after timeout
_byMinChannelTimer.callOnce(PtsWaiter::kWaitForSkippedTimeout);
}
return;
}
_session->data().fillMessagePeers(d.vmessage());
if (channel && !_handlingChannelDifference) {
if (channel->ptsRequesting()) { // skip global updates while getting channel difference
MTP_LOG(0, ("Skipping new channel message because getting the difference."));

View File

@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "core/application.h"
#include "history/history.h"
#include "history/history_item.h"
#include "api/api_chat_invite.h"
#include "api/api_invite_links.h"
#include "apiwrap.h"
@@ -1210,6 +1211,19 @@ void ChannelData::updateSubscriptionUntilDate(TimeId subscriptionUntilDate) {
_subscriptionUntilDate = subscriptionUntilDate;
}
MTPInputChannel ChannelData::inputChannel() const {
const auto item = isLoaded() ? nullptr : owner().messageWithPeer(id);
if (item) {
return MTP_inputChannelFromMessage(
item->history()->peer->input(),
MTP_int(item->id.bare),
MTP_long(peerToChannel(id).bare));
}
return MTP_inputChannel(
MTP_long(peerToChannel(id).bare),
MTP_long(_accessHash));
}
namespace Data {
void ApplyMigration(

View File

@@ -553,11 +553,9 @@ public:
[[nodiscard]] TimeId subscriptionUntilDate() const;
void updateSubscriptionUntilDate(TimeId subscriptionUntilDate);
[[nodiscard]] MTPInputChannel inputChannel() const;
// Still public data members.
uint64 access = 0;
MTPinputChannel inputChannel = MTP_inputChannelEmpty();
int32 date = 0;
std::unique_ptr<MegagroupInfo> mgInfo;
@@ -588,6 +586,8 @@ private:
std::vector<UserId> _recentRequesters;
MsgId _availableMinId = 0;
uint64 _accessHash = 0;
RestrictionFlags _defaultRestrictions;
AdminRightFlags _adminRights;
RestrictionFlags _restrictions;

View File

@@ -313,6 +313,10 @@ const Data::AllowedReactions &ChatData::allowedReactions() const {
return _allowedReactions;
}
MTPlong ChatData::inputChat() const {
return MTP_long(peerToChat(id).bare);
}
namespace Data {
void ApplyChatUpdate(

View File

@@ -166,9 +166,9 @@ public:
void setAllowedReactions(Data::AllowedReactions value);
[[nodiscard]] const Data::AllowedReactions &allowedReactions() const;
// Still public data members.
const MTPlong inputChat;
[[nodiscard]] MTPlong inputChat() const;
// Still public data members.
int count = 0;
TimeId date = 0;
UserId creator = 0;

View File

@@ -2014,6 +2014,41 @@ int PeerData::peerGiftsCount() const {
return 0;
}
MTPInputPeer PeerData::input() const {
if (const auto user = asUser()) {
const auto specific = user->inputUser();
return specific.match([](const MTPDinputUser &data) {
return MTP_inputPeerUser(data.vuser_id(), data.vaccess_hash());
}, [](const MTPDinputUserFromMessage &data) {
return MTP_inputPeerUserFromMessage(
data.vpeer(),
data.vmsg_id(),
data.vuser_id());
}, [](const MTPDinputUserEmpty &) {
return MTP_inputPeerEmpty();
}, [](const MTPDinputUserSelf &) {
return MTP_inputPeerSelf();
});
} else if (const auto chat = asChat()) {
return MTP_inputPeerChat(chat->inputChat());
} else if (const auto channel = asChannel()) {
const auto &specific = channel->inputChannel();
return specific.match([](const MTPDinputChannel &data) {
return MTP_inputPeerChannel(
data.vchannel_id(),
data.vaccess_hash());
}, [](const MTPDinputChannelFromMessage &data) {
return MTP_inputPeerChannelFromMessage(
data.vpeer(),
data.vmsg_id(),
data.vchannel_id());
}, [](const MTPDinputChannelEmpty &) {
return MTP_inputPeerEmpty();
});
}
return MTP_inputPeerEmpty();
}
void PeerData::setIsBlocked(bool is) {
const auto status = is
? BlockStatus::Blocked

View File

@@ -584,8 +584,9 @@ public:
[[nodiscard]] int peerGiftsCount() const;
[[nodiscard]] MTPInputPeer input() const;
const PeerId id;
MTPinputPeer input = MTP_inputPeerEmpty();
protected:
void updateNameDelayed(

View File

@@ -5363,4 +5363,83 @@ void Session::clearLocalStorage() {
_bigFileCache->clear();
}
void Session::fillMessagePeers(const MTPMessage &message) {
const auto id = IdFromMessage(message);
const auto peerId = PeerFromMessage(message);
if (!id || !peerId) {
return;
}
const auto fullId = FullMsgId(peerId, id);
const auto fill = [&](PeerId peerId) {
if (!peerLoaded(peerId)) {
_messagesWithPeer[peerId].push_back(fullId);
}
};
const auto fillForwardedInfo = [&](const MTPMessageFwdHeader &header) {
return header.match([&](const MTPDmessageFwdHeader &data) {
if (const auto fromId = data.vfrom_id()) {
fill(peerFromMTP(*fromId));
}
});
};
const auto fillMentionUsers = [&](
const MTPVector<MTPMessageEntity> &entities) {
for (const auto &entity : entities.v) {
entity.match([&](const MTPDmessageEntityMentionName &data) {
fill(peerFromUser(data.vuser_id()));
}, [&](const MTPDinputMessageEntityMentionName &data) {
data.vuser_id().match([&](const MTPDinputUser &data) {
fill(peerFromUser(data.vuser_id()));
}, [](const auto &) {});
}, [](const auto &) {});
}
};
return message.match([&](const MTPDmessage &message) {
if (const auto fromId = message.vfrom_id()) {
fill(peerFromMTP(*fromId));
}
if (const auto viaBotId = message.vvia_bot_id()) {
fill(peerFromUser(*viaBotId));
}
if (const auto fwd = message.vfwd_from()) {
fillForwardedInfo(*fwd);
}
if (const auto entities = message.ventities()) {
fillMentionUsers(*entities);
}
}, [&](const MTPDmessageService &message) {
if (const auto fromId = message.vfrom_id()) {
fill(peerFromMTP(*fromId));
}
return message.vaction().match(
[&](const MTPDmessageActionChatAddUser &action) {
for (const auto &userId : action.vusers().v) {
fill(peerFromUser(userId));
}
}, [&](const MTPDmessageActionChatJoinedByLink &action) {
fill(peerFromUser(action.vinviter_id()));
}, [&](const MTPDmessageActionChatDeleteUser &action) {
fill(peerFromUser(action.vuser_id()));
}, [](const auto &) {
});
}, [](const MTPDmessageEmpty &message) {
});
}
HistoryItem *Session::messageWithPeer(PeerId id) const {
const auto i = _messagesWithPeer.find(id);
if (i == end(_messagesWithPeer)) {
return nullptr;
}
auto &list = i->second;
for (auto j = begin(list); j != end(list);) {
if (const auto item = message(*j)) {
return item;
}
j = list.erase(j);
}
_messagesWithPeer.erase(i);
return nullptr;
}
} // namespace Data

View File

@@ -918,6 +918,9 @@ public:
void clearLocalStorage();
void fillMessagePeers(const MTPMessage &message);
[[nodiscard]] HistoryItem *messageWithPeer(PeerId id) const;
private:
using Messages = std::unordered_map<MsgId, not_null<HistoryItem*>>;
@@ -1259,6 +1262,8 @@ private:
not_null<ChannelData*>,
mtpRequestId> _viewAsMessagesRequests;
mutable base::flat_map<PeerId, std::vector<FullMsgId>> _messagesWithPeer;
Groups _groups;
const std::unique_ptr<ChatFilters> _chatsFilters;
const std::unique_ptr<CloudThemes> _cloudThemes;

View File

@@ -33,6 +33,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_wall_paper.h"
#include "data/notify/data_notify_settings.h"
#include "history/history.h"
#include "history/history_item.h"
#include "api/api_peer_photo.h"
#include "apiwrap.h"
#include "lang/lang_keys.h"
@@ -317,6 +318,21 @@ void UserData::setPersonalChannel(ChannelId channelId, MsgId messageId) {
}
}
MTPInputUser UserData::inputUser() const {
const auto item = isLoaded() ? nullptr : owner().messageWithPeer(id);
if (item) {
return MTP_inputUserFromMessage(
item->history()->peer->input(),
MTP_int(item->id.bare),
MTP_long(peerToUser(id).bare));
} else if (isSelf()) {
return MTP_inputUserSelf();
}
return MTP_inputUser(
MTP_long(peerToUser(id).bare),
MTP_long(_accessHash));
}
void UserData::setName(
const QString &newFirstName,
const QString &newLastName,

View File

@@ -286,7 +286,7 @@ public:
[[nodiscard]] MsgId personalChannelMessageId() const;
void setPersonalChannel(ChannelId channelId, MsgId messageId);
MTPInputUser inputUser = MTP_inputUserEmpty();
[[nodiscard]] MTPInputUser inputUser() const;
QString firstName;
QString lastName;