Short poll extended media.

This commit is contained in:
John Preston 2022-09-12 18:18:31 +04:00
parent 379736a7d1
commit 40bdcd7ebc
8 changed files with 146 additions and 3 deletions

View File

@ -20,13 +20,16 @@ namespace {
// Send channel views each second.
constexpr auto kSendViewsTimeout = crl::time(1000);
constexpr auto kPollExtendedMediaPeriod = 30 * crl::time(1000);
constexpr auto kMaxPollPerRequest = 100;
} // namespace
ViewsManager::ViewsManager(not_null<ApiWrap*> api)
: _session(&api->session())
, _api(&api->instance())
, _incrementTimer([=] { viewsIncrement(); }) {
, _incrementTimer([=] { viewsIncrement(); })
, _pollTimer([=] { sendPollRequests(); }) {
}
void ViewsManager::scheduleIncrement(not_null<HistoryItem*> item) {
@ -52,6 +55,25 @@ void ViewsManager::removeIncremented(not_null<PeerData*> peer) {
_incremented.remove(peer);
}
void ViewsManager::pollExtendedMedia(not_null<HistoryItem*> item) {
if (!item->isRegular()) {
return;
}
const auto id = item->id;
const auto peer = item->history()->peer;
auto &request = _pollRequests[peer];
if (request.ids.contains(id) || request.sent.contains(id)) {
return;
}
request.ids.emplace(id);
if (!request.id && !request.when) {
request.when = crl::now() + kPollExtendedMediaPeriod;
}
if (!_pollTimer.isActive()) {
_pollTimer.callOnce(kPollExtendedMediaPeriod);
}
}
void ViewsManager::viewsIncrement() {
for (auto i = _toIncrement.begin(); i != _toIncrement.cend();) {
if (_incrementRequests.contains(i->first)) {
@ -81,6 +103,88 @@ void ViewsManager::viewsIncrement() {
}
}
void ViewsManager::sendPollRequests() {
const auto now = crl::now();
auto toRequest = base::flat_map<not_null<PeerData*>, QVector<MTPint>>();
auto nearest = crl::time();
for (auto &[peer, request] : _pollRequests) {
if (request.id) {
continue;
} else if (request.when <= now) {
Assert(request.sent.empty());
auto &list = toRequest[peer];
const auto count = int(request.ids.size());
if (count < kMaxPollPerRequest) {
request.sent = base::take(request.ids);
} else {
const auto from = begin(request.ids);
const auto end = from + kMaxPollPerRequest;
request.sent = { from, end };
request.ids.erase(from, end);
}
list.reserve(request.sent.size());
for (const auto &id : request.sent) {
list.push_back(MTP_int(id.bare));
}
if (!request.ids.empty()) {
nearest = now;
}
} else if (!nearest || nearest > request.when) {
nearest = request.when;
}
}
sendPollRequests(toRequest);
if (nearest) {
_pollTimer.callOnce(std::max(nearest - now, crl::time(1)));
}
}
void ViewsManager::sendPollRequests(
const base::flat_map<
not_null<PeerData*>,
QVector<MTPint>> &batched) {
for (auto &[peer, list] : batched) {
const auto finish = [=, list = list](mtpRequestId id) {
const auto now = crl::now();
const auto owner = &_session->data();
for (auto i = begin(_pollRequests); i != end(_pollRequests);) {
if (i->second.id == id) {
const auto peer = i->first->id;
for (const auto &itemId : i->second.sent) {
if (const auto item = owner->message(peer, itemId)) {
owner->requestItemRepaint(item);
}
}
i->second.sent.clear();
i->second.id = 0;
if (i->second.ids.empty()) {
i = _pollRequests.erase(i);
} else {
i->second.when = now + kPollExtendedMediaPeriod;
if (!_pollTimer.isActive()) {
_pollTimer.callOnce(kPollExtendedMediaPeriod);
}
++i;
}
} else {
++i;
}
}
};
const auto requestId = _api.request(MTPmessages_GetExtendedMedia(
peer->input,
MTP_vector<MTPint>(list)
)).done([=](const MTPUpdates &result, mtpRequestId id) {
_session->api().applyUpdates(result);
finish(id);
}).fail([=](const MTP::Error &error, mtpRequestId id) {
finish(id);
}).send();
_pollRequests[peer].id = requestId;
}
}
void ViewsManager::done(
QVector<MTPint> ids,
const MTPmessages_MessageViews &result,

View File

@ -26,8 +26,22 @@ public:
void scheduleIncrement(not_null<HistoryItem*> item);
void removeIncremented(not_null<PeerData*> peer);
void pollExtendedMedia(not_null<HistoryItem*> item);
private:
struct PollExtendedMediaRequest {
crl::time when = 0;
mtpRequestId id = 0;
base::flat_set<MsgId> ids;
base::flat_set<MsgId> sent;
};
void viewsIncrement();
void sendPollRequests();
void sendPollRequests(
const base::flat_map<
not_null<PeerData*>,
QVector<MTPint>> &prepared);
void done(
QVector<MTPint> ids,
@ -44,6 +58,11 @@ private:
base::flat_map<mtpRequestId, not_null<PeerData*>> _incrementByRequest;
base::Timer _incrementTimer;
base::flat_map<
not_null<PeerData*>,
PollExtendedMediaRequest> _pollRequests;
base::Timer _pollTimer;
};
} // namespace Api

View File

@ -1611,7 +1611,7 @@ std::unique_ptr<HistoryView::Media> MediaInvoice::createView(
message,
realParent,
replacing);
} else if (!_invoice.extendedPreview.dimensions.isEmpty()) {
} else if (_invoice.extendedPreview) {
return std::make_unique<HistoryView::ExtendedPreview>(
message,
&_invoice);

View File

@ -63,6 +63,13 @@ struct ExtendedPreview {
QByteArray inlineThumbnailBytes;
QSize dimensions;
TimeId videoDuration = -1;
[[nodiscard]] bool empty() const {
return dimensions.isEmpty();
}
explicit operator bool() const {
return !empty();
}
};
class Media;

View File

@ -997,6 +997,9 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
}
}
session().data().reactions().poll(item, now);
if (item->hasExtendedMediaPreview()) {
session().api().views().pollExtendedMedia(item);
}
_reactionsManager->recordCurrentReactionEffect(
item->fullId(),
QPoint(0, top));

View File

@ -1169,6 +1169,15 @@ bool HistoryItem::isRegular() const {
return isHistoryEntry() && !isLocal();
}
bool HistoryItem::hasExtendedMediaPreview() const {
if (const auto media = _media.get()) {
if (const auto invoice = media->invoice()) {
return (invoice->extendedPreview && !invoice->extendedMedia);
}
}
return false;
}
void HistoryItem::sendFailed() {
Expects(_flags & MessageFlag::BeingSent);
Expects(!(_flags & MessageFlag::SendingFailed));

View File

@ -239,6 +239,7 @@ public:
[[nodiscard]] virtual bool externalReply() const {
return false;
}
[[nodiscard]] bool hasExtendedMediaPreview() const;
[[nodiscard]] virtual MsgId repliesInboxReadTill() const {
return MsgId(0);

View File

@ -917,7 +917,7 @@ void HistoryMessageReplyMarkup::updateData(
bool HistoryMessageReplyMarkup::hiddenBy(Data::Media *media) const {
if (media && (data.flags & ReplyMarkupFlag::OnlyBuyButton)) {
if (const auto invoice = media->invoice()) {
if (!invoice->extendedPreview.dimensions.isEmpty()
if (invoice->extendedPreview
&& (!invoice->extendedMedia || !invoice->receiptMsgId)) {
return true;
}