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

View file

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

View file

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

View file

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