Don't accept drafts older than last saved.

I hope it finally fixes #4922, partially fixes #10001.

The rest of #10001 like RAM usage / crashes are unrelated to drafts.
This commit is contained in:
John Preston 2021-03-12 15:18:33 +04:00
parent 74c21039b3
commit 5794679277
4 changed files with 86 additions and 52 deletions

View file

@ -114,6 +114,10 @@ using PhotoFileLocationId = Data::PhotoFileLocationId;
using DocumentFileLocationId = Data::DocumentFileLocationId; using DocumentFileLocationId = Data::DocumentFileLocationId;
using UpdatedFileReferences = Data::UpdatedFileReferences; using UpdatedFileReferences = Data::UpdatedFileReferences;
[[nodiscard]] TimeId UnixtimeFromMsgId(mtpMsgId msgId) {
return TimeId(msgId << 32);
}
} // namespace } // namespace
MTPInputPrivacyKey ApiWrap::Privacy::Input(Key key) { MTPInputPrivacyKey ApiWrap::Privacy::Input(Key key) {
@ -2445,38 +2449,41 @@ void ApiWrap::saveDraftsToCloud() {
TextUtilities::ConvertTextTagsToEntities(textWithTags.tags), TextUtilities::ConvertTextTagsToEntities(textWithTags.tags),
Api::ConvertOption::SkipLocal); Api::ConvertOption::SkipLocal);
const auto draftText = textWithTags.text; history->startSavingCloudDraft();
history->setSentDraftText(draftText);
cloudDraft->saveRequestId = request(MTPmessages_SaveDraft( cloudDraft->saveRequestId = request(MTPmessages_SaveDraft(
MTP_flags(flags), MTP_flags(flags),
MTP_int(cloudDraft->msgId), MTP_int(cloudDraft->msgId),
history->peer->input, history->peer->input,
MTP_string(textWithTags.text), MTP_string(textWithTags.text),
entities entities
)).done([=](const MTPBool &result, mtpRequestId requestId) { )).done([=](const MTPBool &result, const MTP::Response &response) {
history->clearSentDraftText(draftText); history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
if (const auto cloudDraft = history->cloudDraft()) { if (const auto cloudDraft = history->cloudDraft()) {
if (cloudDraft->saveRequestId == requestId) { if (cloudDraft->saveRequestId == response.requestId) {
cloudDraft->saveRequestId = 0; cloudDraft->saveRequestId = 0;
history->draftSavedToCloud(); history->draftSavedToCloud();
} }
} }
auto i = _draftsSaveRequestIds.find(history); auto i = _draftsSaveRequestIds.find(history);
if (i != _draftsSaveRequestIds.cend() && i->second == requestId) { if (i != _draftsSaveRequestIds.cend()
&& i->second == response.requestId) {
_draftsSaveRequestIds.erase(history); _draftsSaveRequestIds.erase(history);
checkQuitPreventFinished(); checkQuitPreventFinished();
} }
}).fail([=](const RPCError &error, mtpRequestId requestId) { }).fail([=](const RPCError &error, const MTP::Response &response) {
history->clearSentDraftText(draftText); history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
if (const auto cloudDraft = history->cloudDraft()) { if (const auto cloudDraft = history->cloudDraft()) {
if (cloudDraft->saveRequestId == requestId) { if (cloudDraft->saveRequestId == response.requestId) {
history->clearCloudDraft(); history->clearCloudDraft();
} }
} }
auto i = _draftsSaveRequestIds.find(history); auto i = _draftsSaveRequestIds.find(history);
if (i != _draftsSaveRequestIds.cend() && i->second == requestId) { if (i != _draftsSaveRequestIds.cend()
&& i->second == response.requestId) {
_draftsSaveRequestIds.erase(history); _draftsSaveRequestIds.erase(history);
checkQuitPreventFinished(); checkQuitPreventFinished();
} }
@ -4027,10 +4034,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
if (!sentEntities.v.isEmpty()) { if (!sentEntities.v.isEmpty()) {
sendFlags |= MTPmessages_SendMessage::Flag::f_entities; sendFlags |= MTPmessages_SendMessage::Flag::f_entities;
} }
if (action.clearDraft) { const auto clearCloudDraft = action.clearDraft;
if (clearCloudDraft) {
sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft; sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
history->clearCloudDraft(); history->clearCloudDraft();
history->setSentDraftText(QString()); history->startSavingCloudDraft();
} }
auto messageFromId = anonymousPost ? 0 : _session->userPeerId(); auto messageFromId = anonymousPost ? 0 : _session->userPeerId();
auto messagePostAuthor = peer->isBroadcast() auto messagePostAuthor = peer->isBroadcast()
@ -4080,17 +4088,27 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
MTPReplyMarkup(), MTPReplyMarkup(),
sentEntities, sentEntities,
MTP_int(action.options.scheduled) MTP_int(action.options.scheduled)
)).done([=](const MTPUpdates &result) { )).done([=](
const MTPUpdates &result,
const MTP::Response &response) {
applyUpdates(result, randomId); applyUpdates(result, randomId);
history->clearSentDraftText(QString()); if (clearCloudDraft) {
history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
}
finish(); finish();
}).fail([=](const RPCError &error) { }).fail([=](
const RPCError &error,
const MTP::Response &response) {
if (error.type() == qstr("MESSAGE_EMPTY")) { if (error.type() == qstr("MESSAGE_EMPTY")) {
lastMessage->destroy(); lastMessage->destroy();
} else { } else {
sendMessageFail(error, peer, randomId, newId); sendMessageFail(error, peer, randomId, newId);
} }
history->clearSentDraftText(QString()); if (clearCloudDraft) {
history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
}
finish(); finish();
}).afterRequest(history->sendRequestId }).afterRequest(history->sendRequestId
).send(); ).send();
@ -4188,7 +4206,7 @@ void ApiWrap::sendInlineResult(
messagePostAuthor); messagePostAuthor);
history->clearCloudDraft(); history->clearCloudDraft();
history->setSentDraftText(QString()); history->startSavingCloudDraft();
auto &histories = history->owner().histories(); auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send; const auto requestType = Data::Histories::RequestType::Send;
@ -4201,13 +4219,19 @@ void ApiWrap::sendInlineResult(
MTP_long(data->getQueryId()), MTP_long(data->getQueryId()),
MTP_string(data->getId()), MTP_string(data->getId()),
MTP_int(action.options.scheduled) MTP_int(action.options.scheduled)
)).done([=](const MTPUpdates &result) { )).done([=](
const MTPUpdates &result,
const MTP::Response &response) {
applyUpdates(result, randomId); applyUpdates(result, randomId);
history->clearSentDraftText(QString()); history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
finish(); finish();
}).fail([=](const RPCError &error) { }).fail([=](
const RPCError &error,
const MTP::Response &response) {
sendMessageFail(error, peer, randomId, newId); sendMessageFail(error, peer, randomId, newId);
history->clearSentDraftText(QString()); history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
finish(); finish();
}).afterRequest(history->sendRequestId }).afterRequest(history->sendRequestId
).send(); ).send();
@ -4894,10 +4918,12 @@ void ApiWrap::createPoll(
if (action.replyTo) { if (action.replyTo) {
sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to_msg_id;
} }
if (action.clearDraft) { const auto clearCloudDraft = action.clearDraft;
if (clearCloudDraft) {
sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft; sendFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
history->clearLocalDraft(); history->clearLocalDraft();
history->clearCloudDraft(); history->clearCloudDraft();
history->startSavingCloudDraft();
} }
const auto silentPost = ShouldSendSilent(peer, action.options); const auto silentPost = ShouldSendSilent(peer, action.options);
if (silentPost) { if (silentPost) {
@ -4920,8 +4946,14 @@ void ApiWrap::createPoll(
MTPReplyMarkup(), MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(), MTPVector<MTPMessageEntity>(),
MTP_int(action.options.scheduled) MTP_int(action.options.scheduled)
)).done([=](const MTPUpdates &result) mutable { )).done([=](
const MTPUpdates &result,
const MTP::Response &response) mutable {
applyUpdates(result); applyUpdates(result);
if (clearCloudDraft) {
history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
}
_session->changes().historyUpdated( _session->changes().historyUpdated(
history, history,
(action.options.scheduled (action.options.scheduled
@ -4929,7 +4961,13 @@ void ApiWrap::createPoll(
: Data::HistoryUpdate::Flag::MessageSent)); : Data::HistoryUpdate::Flag::MessageSent));
done(); done();
finish(); finish();
}).fail([=](const RPCError &error) mutable { }).fail([=](
const RPCError &error,
const MTP::Response &response) mutable {
if (clearCloudDraft) {
history->finishSavingCloudDraft(
UnixtimeFromMsgId(response.outerMsgId));
}
fail(error); fail(error);
finish(); finish();
}).afterRequest(history->sendRequestId }).afterRequest(history->sendRequestId

View file

@ -48,7 +48,11 @@ void ApplyPeerCloudDraft(
PeerId peerId, PeerId peerId,
const MTPDdraftMessage &draft) { const MTPDdraftMessage &draft) {
const auto history = session->data().history(peerId); const auto history = session->data().history(peerId);
const auto textWithTags = TextWithTags { const auto date = draft.vdate().v;
if (history->skipCloudDraftUpdate(date)) {
return;
}
const auto textWithTags = TextWithTags{
qs(draft.vmessage()), qs(draft.vmessage()),
TextUtilities::ConvertEntitiesToTextTags( TextUtilities::ConvertEntitiesToTextTags(
Api::EntitiesFromMTP( Api::EntitiesFromMTP(
@ -56,9 +60,6 @@ void ApplyPeerCloudDraft(
draft.ventities().value_or_empty())) draft.ventities().value_or_empty()))
}; };
const auto replyTo = draft.vreply_to_msg_id().value_or_empty(); const auto replyTo = draft.vreply_to_msg_id().value_or_empty();
if (history->skipCloudDraft(textWithTags.text, replyTo, draft.vdate().v)) {
return;
}
auto cloudDraft = std::make_unique<Draft>( auto cloudDraft = std::make_unique<Draft>(
textWithTags, textWithTags,
replyTo, replyTo,
@ -66,7 +67,7 @@ void ApplyPeerCloudDraft(
(draft.is_no_webpage() (draft.is_no_webpage()
? Data::PreviewState::Cancelled ? Data::PreviewState::Cancelled
: Data::PreviewState::Allowed)); : Data::PreviewState::Allowed));
cloudDraft->date = draft.vdate().v; cloudDraft->date = date;
history->setCloudDraft(std::move(cloudDraft)); history->setCloudDraft(std::move(cloudDraft));
history->applyCloudDraft(); history->applyCloudDraft();
@ -77,7 +78,7 @@ void ClearPeerCloudDraft(
PeerId peerId, PeerId peerId,
TimeId date) { TimeId date) {
const auto history = session->data().history(peerId); const auto history = session->data().history(peerId);
if (history->skipCloudDraft(QString(), MsgId(0), date)) { if (history->skipCloudDraftUpdate(date)) {
return; return;
} }

View file

@ -50,7 +50,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace { namespace {
constexpr auto kNewBlockEachMessage = 50; constexpr auto kNewBlockEachMessage = 50;
constexpr auto kSkipCloudDraftsFor = TimeId(3); constexpr auto kSkipCloudDraftsFor = TimeId(2);
constexpr auto kSendingDraftTime = TimeId(-1);
using UpdateFlag = Data::HistoryUpdate::Flag; using UpdateFlag = Data::HistoryUpdate::Flag;
@ -299,27 +300,21 @@ Data::Draft *History::createCloudDraft(const Data::Draft *fromDraft) {
return cloudDraft(); return cloudDraft();
} }
bool History::skipCloudDraft(const QString &text, MsgId replyTo, TimeId date) const { bool History::skipCloudDraftUpdate(TimeId date) const {
if (Data::draftStringIsEmpty(text) return (_savingCloudDraftRequests > 0)
&& !replyTo || (date < _acceptCloudDraftsAfter);
&& date > 0
&& date <= _lastSentDraftTime + kSkipCloudDraftsFor) {
return true;
} else if (_lastSentDraftText && *_lastSentDraftText == text) {
return true;
}
return false;
} }
void History::setSentDraftText(const QString &text) { void History::startSavingCloudDraft() {
_lastSentDraftText = text; ++_savingCloudDraftRequests;
} }
void History::clearSentDraftText(const QString &text) { void History::finishSavingCloudDraft(TimeId savedAt) {
if (_lastSentDraftText && *_lastSentDraftText == text) { if (_savingCloudDraftRequests > 0) {
_lastSentDraftText = std::nullopt; --_savingCloudDraftRequests;
} }
accumulate_max(_lastSentDraftTime, base::unixtime::now()); const auto acceptAfter = savedAt + kSkipCloudDraftsFor;
_acceptCloudDraftsAfter = std::max(_acceptCloudDraftsAfter, acceptAfter);
} }
void History::applyCloudDraft() { void History::applyCloudDraft() {

View file

@ -339,9 +339,9 @@ public:
} }
void clearDrafts(); void clearDrafts();
Data::Draft *createCloudDraft(const Data::Draft *fromDraft); Data::Draft *createCloudDraft(const Data::Draft *fromDraft);
bool skipCloudDraft(const QString &text, MsgId replyTo, TimeId date) const; bool skipCloudDraftUpdate(TimeId date) const;
void setSentDraftText(const QString &text); void startSavingCloudDraft();
void clearSentDraftText(const QString &text); void finishSavingCloudDraft(TimeId savedAt);
void takeLocalDraft(not_null<History*> from); void takeLocalDraft(not_null<History*> from);
void applyCloudDraft(); void applyCloudDraft();
void draftSavedToCloud(); void draftSavedToCloud();
@ -584,8 +584,8 @@ private:
std::unique_ptr<BuildingBlock> _buildingFrontBlock; std::unique_ptr<BuildingBlock> _buildingFrontBlock;
Data::HistoryDrafts _drafts; Data::HistoryDrafts _drafts;
std::optional<QString> _lastSentDraftText; TimeId _acceptCloudDraftsAfter = 0;
TimeId _lastSentDraftTime = 0; int _savingCloudDraftRequests = 0;
MessageIdsList _forwardDraft; MessageIdsList _forwardDraft;
QString _topPromotedMessage; QString _topPromotedMessage;