Send scheduled paid reactions on quit.

This commit is contained in:
John Preston 2024-08-09 15:58:47 +02:00
parent 92f70a0ebb
commit ba4c521d7a
3 changed files with 74 additions and 28 deletions

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_forum.h" #include "data/data_forum.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_message_reactions.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_stories.h" #include "data/data_stories.h"
#include "data/data_user.h" #include "data/data_user.h"
@ -1740,6 +1741,9 @@ bool Application::readyToQuit() {
if (session->data().stories().isQuitPrevent()) { if (session->data().stories().isQuitPrevent()) {
prevented = true; prevented = true;
} }
if (session->data().reactions().isQuitPrevent()) {
prevented = true;
}
} }
} }
} }

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_message_reactions.h" #include "data/data_message_reactions.h"
#include "chat_helpers/stickers_lottie.h" #include "chat_helpers/stickers_lottie.h"
#include "core/application.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history_item_components.h" #include "history/history_item_components.h"
@ -304,8 +305,9 @@ Reactions::Reactions(not_null<Session*> owner)
_pollItems.remove(item); _pollItems.remove(item);
_repaintItems.remove(item); _repaintItems.remove(item);
_sendPaidItems.remove(item); _sendPaidItems.remove(item);
if (_sendingPaid == item) { if (const auto i = _sendingPaid.find(item)
_sendingPaid = nullptr; ; i != end(_sendingPaid)) {
_sendingPaid.erase(i);
_owner->session().credits().invalidate(); _owner->session().credits().invalidate();
crl::on_main(&_owner->session(), [=] { crl::on_main(&_owner->session(), [=] {
sendPaid(); sendPaid();
@ -1548,6 +1550,23 @@ rpl::producer<std::vector<Reaction>> Reactions::myTagsValue(
) | rpl::map(list)); ) | rpl::map(list));
} }
bool Reactions::isQuitPrevent() {
for (auto i = begin(_sendPaidItems); i != end(_sendPaidItems);) {
const auto item = i->first;
if (_sendingPaid.contains(item)) {
++i;
} else {
i = _sendPaidItems.erase(i);
sendPaid(item);
}
}
if (_sendingPaid.empty()) {
return false;
}
LOG(("Reactions prevents quit, sending paid..."));
return true;
}
void Reactions::schedulePaid(not_null<HistoryItem*> item) { void Reactions::schedulePaid(not_null<HistoryItem*> item) {
_sendPaidItems[item] = crl::now() + kPaidAccumulatePeriod; _sendPaidItems[item] = crl::now() + kPaidAccumulatePeriod;
if (!_sendPaidTimer.isActive()) { if (!_sendPaidTimer.isActive()) {
@ -1625,7 +1644,8 @@ void Reactions::pollCollected() {
} }
bool Reactions::sending(not_null<HistoryItem*> item) const { bool Reactions::sending(not_null<HistoryItem*> item) const {
return _sentRequests.contains(item->fullId()) || (_sendingPaid == item); return _sentRequests.contains(item->fullId())
|| _sendingPaid.contains(item);
} }
bool Reactions::HasUnread(const MTPMessageReactions &data) { bool Reactions::HasUnread(const MTPMessageReactions &data) {
@ -1658,7 +1678,7 @@ void Reactions::CheckUnknownForUnread(
} }
void Reactions::sendPaid() { void Reactions::sendPaid() {
if (_sendingPaid) { if (!_sendingPaid.empty()) {
return; return;
} }
auto next = crl::time(); auto next = crl::time();
@ -1684,48 +1704,65 @@ void Reactions::sendPaid() {
} }
bool Reactions::sendPaid(not_null<HistoryItem*> item) { bool Reactions::sendPaid(not_null<HistoryItem*> item) {
Expects(!_sendingPaid);
const auto count = item->startPaidReactionSending(); const auto count = item->startPaidReactionSending();
if (!count) { if (!count) {
return false; return false;
} }
_sendingPaid = item; sendPaidRequest(item, count);
sendPaidRequest(count);
return true; return true;
} }
void Reactions::sendPaidRequest(int count) { void Reactions::sendPaidRequest(not_null<HistoryItem*> item, int count) {
const auto id = _sendingPaid->fullId(); Expects(!_sendingPaid.contains(item));
const auto id = item->fullId();
const auto randomId = base::unixtime::mtproto_msg_id(); const auto randomId = base::unixtime::mtproto_msg_id();
auto &api = _owner->session().api(); auto &api = _owner->session().api();
api.request(MTPmessages_SendPaidReaction( const auto requestId = api.request(MTPmessages_SendPaidReaction(
_sendingPaid->history()->peer->input, item->history()->peer->input,
MTP_int(id.msg), MTP_int(id.msg),
MTP_int(count), MTP_int(count),
MTP_long(randomId) MTP_long(randomId)
)).done([=](const MTPUpdates &result) { )).done([=](const MTPUpdates &result) {
sendPaidFinish(id, count, true); if (const auto item = _owner->message(id)) {
_owner->session().api().applyUpdates(result); if (_sendingPaid.remove(item)) {
}).fail([=](const MTP::Error &error) { sendPaidFinish(item, count, true);
if (!_sendingPaid }
|| (_sendingPaid->fullId() != id)
|| (error.type() != u"RANDOM_ID_EXPIRED"_q)) {
sendPaidFinish(id, count, false);
} else {
sendPaidRequest(count);
} }
_owner->session().api().applyUpdates(result);
checkQuitPreventFinished();
}).fail([=](const MTP::Error &error) {
if (const auto item = _owner->message(id)) {
_sendingPaid.remove(item);
if (error.type() == u"RANDOM_ID_EXPIRED"_q) {
sendPaidRequest(item, count);
} else {
sendPaidFinish(item, count, false);
}
}
checkQuitPreventFinished();
}).send(); }).send();
_sendingPaid[item] = requestId;
} }
void Reactions::sendPaidFinish(FullMsgId id, int count, bool success) { void Reactions::checkQuitPreventFinished() {
if (_sendingPaid && _sendingPaid->fullId() == id) { if (_sendingPaid.empty()) {
base::take(_sendingPaid)->finishPaidReactionSending(count, success); if (Core::Quitting()) {
sendPaid(); LOG(("Reactions doesn't prevent quit any more."));
}
Core::App().quitPreventFinished();
} }
} }
void Reactions::sendPaidFinish(
not_null<HistoryItem*> item,
int count,
bool success) {
item->finishPaidReactionSending(count, success);
sendPaid();
}
MessageReactions::MessageReactions(not_null<HistoryItem*> item) MessageReactions::MessageReactions(not_null<HistoryItem*> item)
: _item(item) { : _item(item) {
} }

View file

@ -144,6 +144,7 @@ public:
[[nodiscard]] rpl::producer<std::vector<Reaction>> myTagsValue( [[nodiscard]] rpl::producer<std::vector<Reaction>> myTagsValue(
SavedSublist *sublist = nullptr); SavedSublist *sublist = nullptr);
[[nodiscard]] bool isQuitPrevent();
void schedulePaid(not_null<HistoryItem*> item); void schedulePaid(not_null<HistoryItem*> item);
void undoScheduledPaid(not_null<HistoryItem*> item); void undoScheduledPaid(not_null<HistoryItem*> item);
[[nodiscard]] crl::time sendingScheduledPaidAt( [[nodiscard]] crl::time sendingScheduledPaidAt(
@ -249,8 +250,12 @@ private:
void sendPaid(); void sendPaid();
bool sendPaid(not_null<HistoryItem*> item); bool sendPaid(not_null<HistoryItem*> item);
void sendPaidRequest(int count); void sendPaidRequest(not_null<HistoryItem*> item, int count);
void sendPaidFinish(FullMsgId id, int count, bool success); void sendPaidFinish(
not_null<HistoryItem*> item,
int count,
bool success);
void checkQuitPreventFinished();
const not_null<Session*> _owner; const not_null<Session*> _owner;
@ -333,7 +338,7 @@ private:
mtpRequestId _pollRequestId = 0; mtpRequestId _pollRequestId = 0;
base::flat_map<not_null<HistoryItem*>, crl::time> _sendPaidItems; base::flat_map<not_null<HistoryItem*>, crl::time> _sendPaidItems;
HistoryItem *_sendingPaid = nullptr; base::flat_map<not_null<HistoryItem*>, mtpRequestId> _sendingPaid;
base::Timer _sendPaidTimer; base::Timer _sendPaidTimer;
mtpRequestId _saveFaveRequestId = 0; mtpRequestId _saveFaveRequestId = 0;