Update API scheme on layer 217.

This commit is contained in:
John Preston
2025-10-17 00:04:46 +04:00
parent af8c171b1a
commit 832fb023e8
13 changed files with 233 additions and 47 deletions
+4 -1
View File
@@ -1707,6 +1707,8 @@ void Updates::feedUpdate(const MTPUpdate &update) {
owner.histories().checkTopicCreated(id, newId);
}
session().data().unregisterMessageRandomId(randomId);
} else {
Core::App().calls().handleUpdate(&session(), update);
}
session().data().unregisterMessageSentData(randomId);
} break;
@@ -2143,7 +2145,8 @@ void Updates::feedUpdate(const MTPUpdate &update) {
case mtpc_updateGroupCallConnection:
case mtpc_updateGroupCall:
case mtpc_updateGroupCallMessage:
case mtpc_updateGroupCallEncryptedMessage: {
case mtpc_updateGroupCallEncryptedMessage:
case mtpc_updateDeleteGroupCallMessages: {
Core::App().calls().handleUpdate(&session(), update);
} break;
+15 -1
View File
@@ -600,6 +600,10 @@ void Instance::handleUpdate(
handleGroupCallUpdate(session, update);
}, [&](const MTPDupdateGroupCallEncryptedMessage &data) {
handleGroupCallUpdate(session, update);
}, [&](const MTPDupdateDeleteGroupCallMessages &data) {
handleGroupCallUpdate(session, update);
}, [&](const MTPDupdateMessageID &data) {
handleGroupCallUpdate(session, update);
}, [](const auto &) {
Unexpected("Update type in Calls::Instance::handleUpdate.");
});
@@ -723,6 +727,10 @@ void Instance::handleGroupCallUpdate(
strong->handleIncomingMessage(data);
}, [&](const MTPDupdateGroupCallEncryptedMessage &data) {
strong->handleIncomingMessage(data);
}, [&](const MTPDupdateDeleteGroupCallMessages &data) {
strong->handleDeleteMessages(data);
}, [&](const MTPDupdateMessageID &data) {
strong->handleMessageSent(data);
}, [&](const MTPDupdateGroupCallParticipants &data) {
strong->handleUpdate(update);
}, [&](const MTPDupdateGroupCallChainBlocks &data) {
@@ -748,13 +756,19 @@ void Instance::handleGroupCallUpdate(
groupCall->handleIncomingMessage(data);
}, [&](const MTPDupdateGroupCallEncryptedMessage &data) {
groupCall->handleIncomingMessage(data);
}, [&](const MTPDupdateDeleteGroupCallMessages &data) {
groupCall->handleDeleteMessages(data);
}, [&](const MTPDupdateMessageID &data) {
groupCall->handleMessageSent(data);
}, [](const auto &) {
});
}
if (update.type() == mtpc_updateGroupCallConnection
|| update.type() == mtpc_updateGroupCallMessage
|| update.type() == mtpc_updateGroupCallEncryptedMessage) {
|| update.type() == mtpc_updateGroupCallEncryptedMessage
|| update.type() == mtpc_updateDeleteGroupCallMessages
|| update.type() == mtpc_updateMessageID) {
return;
}
const auto callId = update.match([](const MTPDupdateGroupCall &data) {
@@ -2443,6 +2443,26 @@ void GroupCall::handleIncomingMessage(
_messages->received(data);
}
void GroupCall::handleDeleteMessages(
const MTPDupdateDeleteGroupCallMessages &data) {
const auto id = data.vcall().match([&](const MTPDinputGroupCall &data) {
return data.vid().v;
}, [](const auto &) -> CallId {
Unexpected("slug/msg in GroupCall::handleIncomingMessage");
});
if (id != _id || conference()) {
return;
}
_messages->deleted(data);
}
void GroupCall::handleMessageSent(const MTPDupdateMessageID &data) {
if (conference()) {
return;
}
_messages->sent(data);
}
void GroupCall::handlePossibleDiscarded(const MTPDgroupCallDiscarded &data) {
if (data.vid().v == _id) {
LOG(("Call Info: Hangup after groupCallDiscarded."));
@@ -289,6 +289,8 @@ public:
void handleIncomingMessage(const MTPDupdateGroupCallMessage &data);
void handleIncomingMessage(
const MTPDupdateGroupCallEncryptedMessage &data);
void handleDeleteMessages(const MTPDupdateDeleteGroupCallMessages &data);
void handleMessageSent(const MTPDupdateMessageID &data);
void changeTitle(const QString &title);
void toggleRecording(
bool enabled,
@@ -64,10 +64,13 @@ void Messages::send(TextWithTags text) {
prepared.entities,
Api::ConvertOption::SkipLocal)));
const auto localId = _call->peer()->owner().nextLocalMessageId();
const auto randomId = base::RandomValue<uint64>();
_sendingIdByRandomId.emplace(randomId, localId);
const auto from = _call->messagesFrom();
_messages.push_back({
.randomId = randomId,
.id = localId,
.peer = from,
.text = std::move(prepared),
});
@@ -79,8 +82,10 @@ void Messages::send(TextWithTags text) {
MTP_long(randomId),
serialized,
MTPlong() // allow_paid_stars
)).done([=](const MTPBool &, const MTP::Response &response) {
sent(randomId, response);
)).done([=](
const MTPUpdates &result,
const MTP::Response &response) {
_call->peer()->session().api().applyUpdates(result, randomId);
}).fail([=](const MTP::Error &, const MTP::Response &response) {
failed(randomId, response);
}).send();
@@ -111,7 +116,7 @@ void Messages::received(const MTPDupdateGroupCallMessage &data) {
}
const auto &fields = data.vmessage().data();
received(
fields.vrandom_id().v,
fields.vid().v,
fields.vfrom_id(),
fields.vmessage(),
fields.vdate().v);
@@ -138,8 +143,14 @@ void Messages::received(const MTPDupdateGroupCallEncryptedMessage &data) {
LOG(("API Error: Can't parse decrypted message"));
return;
}
const auto realId = ++_conferenceIdAutoIncrement;
const auto randomId = deserialized->randomId;
if (!_conferenceIdByRandomId.emplace(randomId, realId).second) {
// Already received.
return;
}
received(
deserialized->randomId,
realId,
fromId,
deserialized->message,
base::unixtime::now(),
@@ -147,14 +158,59 @@ void Messages::received(const MTPDupdateGroupCallEncryptedMessage &data) {
pushChanges();
}
void Messages::deleted(const MTPDupdateDeleteGroupCallMessages &data) {
const auto was = _messages.size();
for (const auto &id : data.vmessages().v) {
const auto i = ranges::find(_messages, id.v, &Message::id);
if (i != end(_messages)) {
_messages.erase(i);
}
}
if (_messages.size() < was) {
pushChanges();
}
}
void Messages::sent(const MTPDupdateMessageID &data) {
sent(data.vrandom_id().v, data.vid().v);
}
void Messages::sent(uint64 randomId, const MTP::Response &response) {
const auto realId = ++_conferenceIdAutoIncrement;
_conferenceIdByRandomId.emplace(randomId, realId);
sent(randomId, realId);
const auto i = ranges::find(_messages, realId, &Message::id);
if (i != end(_messages) && !i->date) {
i->date = Api::UnixtimeFromMsgId(response.outerMsgId);
checkDestroying(true);
}
}
void Messages::sent(uint64 randomId, MsgId realId) {
const auto i = _sendingIdByRandomId.find(randomId);
if (i == end(_sendingIdByRandomId)) {
return;
}
const auto localId = i->second;
_sendingIdByRandomId.erase(i);
const auto j = ranges::find(_messages, localId, &Message::id);
if (j == end(_messages)) {
return;
}
j->id = realId;
_idUpdates.fire({ .localId = localId, .realId = realId });
}
void Messages::received(
uint64 randomId,
MsgId id,
const MTPPeer &from,
const MTPTextWithEntities &message,
TimeId date,
bool checkCustomEmoji) {
const auto peer = _call->peer();
const auto i = ranges::find(_messages, randomId, &Message::randomId);
const auto i = ranges::find(_messages, id, &Message::id);
if (i != end(_messages)) {
if (peerFromMTP(from) == peer->session().userPeerId() && !i->date) {
i->date = date;
@@ -176,7 +232,7 @@ void Messages::received(
allowedEntityTypes.pop_back();
}
_messages.push_back({
.randomId = randomId,
.id = id,
.date = date,
.peer = peer->owner().peer(peerFromMTP(from)),
.text = Ui::Text::Filtered(
@@ -194,7 +250,11 @@ void Messages::checkDestroying(bool afterChanges) {
for (auto i = begin(_messages); i != end(_messages);) {
const auto date = i->date;
if (!date) {
++i;
if (i->id < 0) {
++i;
} else {
i = _messages.erase(i);
}
} else if (date <= destroyTime) {
i = _messages.erase(i);
} else if (!next) {
@@ -222,6 +282,10 @@ rpl::producer<std::vector<Message>> Messages::listValue() const {
return _changes.events_starting_with_copy(_messages);
}
rpl::producer<MessageIdUpdate> Messages::idUpdates() const {
return _idUpdates.events();
}
void Messages::sendPending() {
Expects(_real != nullptr);
@@ -234,19 +298,18 @@ void Messages::pushChanges() {
_changes.fire_copy(_messages);
}
void Messages::sent(uint64 randomId, const MTP::Response &response) {
const auto i = ranges::find(_messages, randomId, &Message::randomId);
if (i != end(_messages) && !i->date) {
i->date = Api::UnixtimeFromMsgId(response.outerMsgId);
checkDestroying(true);
}
}
void Messages::failed(uint64 randomId, const MTP::Response &response) {
const auto i = ranges::find(_messages, randomId, &Message::randomId);
if (i != end(_messages) && !i->date) {
i->date = Api::UnixtimeFromMsgId(response.outerMsgId);
i->failed = true;
const auto i = _sendingIdByRandomId.find(randomId);
if (i == end(_sendingIdByRandomId)) {
return;
}
const auto localId = i->second;
_sendingIdByRandomId.erase(i);
const auto j = ranges::find(_messages, localId, &Message::id);
if (j != end(_messages) && !j->date) {
j->date = Api::UnixtimeFromMsgId(response.outerMsgId);
j->failed = true;
checkDestroying(true);
}
}
@@ -25,13 +25,18 @@ struct Response;
namespace Calls::Group {
struct Message {
uint64 randomId = 0;
MsgId id = 0;
TimeId date = 0;
not_null<PeerData*> peer;
TextWithEntities text;
bool failed = false;
};
struct MessageIdUpdate {
MsgId localId = 0;
MsgId realId = 0;
};
class Messages final {
public:
Messages(not_null<GroupCall*> call, not_null<MTP::Sender*> api);
@@ -40,8 +45,11 @@ public:
void received(const MTPDupdateGroupCallMessage &data);
void received(const MTPDupdateGroupCallEncryptedMessage &data);
void deleted(const MTPDupdateDeleteGroupCallMessages &data);
void sent(const MTPDupdateMessageID &data);
[[nodiscard]] rpl::producer<std::vector<Message>> listValue() const;
[[nodiscard]] rpl::producer<MessageIdUpdate> idUpdates() const;
private:
[[nodiscard]] bool ready() const;
@@ -50,17 +58,23 @@ private:
void checkDestroying(bool afterChanges = false);
void received(
uint64 randomId,
MsgId id,
const MTPPeer &from,
const MTPTextWithEntities &message,
TimeId date,
bool checkCustomEmoji = false);
void sent(uint64 randomId, const MTP::Response &response);
void sent(uint64 randomId, MsgId realId);
void failed(uint64 randomId, const MTP::Response &response);
const not_null<GroupCall*> _call;
const not_null<MTP::Sender*> _api;
MsgId _conferenceIdAutoIncrement = 0;
base::flat_map<uint64, MsgId> _conferenceIdByRandomId;
base::flat_map<uint64, MsgId> _sendingIdByRandomId;
Data::GroupCall *_real = nullptr;
std::vector<TextWithTags> _pending;
@@ -68,6 +82,7 @@ private:
base::Timer _destroyTimer;
std::vector<Message> _messages;
rpl::event_stream<std::vector<Message>> _changes;
rpl::event_stream<MessageIdUpdate> _idUpdates;
TimeId _ttl = 0;
@@ -139,7 +139,8 @@ void ReceiveSomeMouseEvents(
} // namespace
struct MessagesUi::MessageView {
uint64 id = 0;
MsgId id = 0;
MsgId sendingId = 0;
PeerData *from = nullptr;
ClickHandlerPtr fromLink;
Ui::Animations::Simple toggleAnimation;
@@ -165,6 +166,7 @@ MessagesUi::MessagesUi(
not_null<QWidget*> parent,
std::shared_ptr<ChatHelpers::Show> show,
rpl::producer<std::vector<Message>> messages,
rpl::producer<MessageIdUpdate> idUpdates,
rpl::producer<bool> shown)
: _parent(parent)
, _show(std::move(show))
@@ -176,6 +178,7 @@ MessagesUi::MessagesUi(
, _messageBgRect(CountMessageRadius(), _messageBg.color())
, _fadeHeight(st::normalFont->height) {
setupList(std::move(messages), std::move(shown));
handleIdUpdates(std::move(idUpdates));
}
MessagesUi::~MessagesUi() = default;
@@ -199,7 +202,7 @@ void MessagesUi::setupList(
from,
till,
id,
&Message::randomId);
&Message::id);
if (i == till) {
toggleMessage(entry, false);
continue;
@@ -217,7 +220,7 @@ void MessagesUi::setupList(
}
auto addedSendingToBottom = false;
for (auto i = from; i != till; ++i) {
if (!ranges::contains(_views, i->randomId, &MessageView::id)) {
if (!ranges::contains(_views, i->id, &MessageView::id)) {
if (i + 1 == till && !i->date) {
addedSendingToBottom = true;
}
@@ -234,6 +237,25 @@ void MessagesUi::setupList(
}, _lifetime);
}
void MessagesUi::handleIdUpdates(rpl::producer<MessageIdUpdate> idUpdates) {
std::move(
idUpdates
) | rpl::start_with_next([=](MessageIdUpdate update) {
const auto i = ranges::find(
_views,
update.localId,
&MessageView::id);
if (i == end(_views)) {
return;
}
i->sendingId = update.localId;
i->id = update.realId;
if (_revealedSpoilerId == update.localId) {
_revealedSpoilerId = update.realId;
}
}, _lifetime);
}
void MessagesUi::animateMessageSent(MessageView &entry) {
const auto id = entry.id;
entry.sending = false;
@@ -345,8 +367,11 @@ void MessagesUi::toggleMessage(MessageView &entry, bool shown) {
repaintMessage(id);
}
void MessagesUi::repaintMessage(uint64 id) {
void MessagesUi::repaintMessage(MsgId id) {
auto i = ranges::find(_views, id, &MessageView::id);
if (i == end(_views) && id < 0) {
i = ranges::find(_views, id, &MessageView::sendingId);
}
if (i == end(_views)) {
return;
} else if (i->removed && !i->toggleAnimation.animating()) {
@@ -395,7 +420,7 @@ void MessagesUi::appendMessage(const Message &data) {
}
auto &entry = _views.emplace_back();
const auto id = entry.id = data.randomId;
const auto id = entry.id = data.id;
const auto repaint = [=] {
repaintMessage(id);
};
@@ -32,6 +32,7 @@ class RpWidget;
namespace Calls::Group {
struct Message;
struct MessageIdUpdate;
class MessagesUi final {
public:
@@ -39,6 +40,7 @@ public:
not_null<QWidget*> parent,
std::shared_ptr<ChatHelpers::Show> show,
rpl::producer<std::vector<Message>> messages,
rpl::producer<MessageIdUpdate> idUpdates,
rpl::producer<bool> shown);
~MessagesUi();
@@ -53,13 +55,14 @@ private:
void setupList(
rpl::producer<std::vector<Message>> messages,
rpl::producer<bool> shown);
void handleIdUpdates(rpl::producer<MessageIdUpdate> idUpdates);
void toggleMessage(MessageView &entry, bool shown);
void setContentFailed(MessageView &entry);
void setContent(MessageView &entry, const TextWithEntities &text);
void updateMessageSize(MessageView &entry);
bool updateMessageHeight(MessageView &entry);
void animateMessageSent(MessageView &entry);
void repaintMessage(uint64 id);
void repaintMessage(MsgId id);
void recountHeights(std::vector<MessageView>::iterator i, int top);
void appendMessage(const Message &data);
void checkReactionContent(
@@ -99,7 +102,7 @@ private:
int _width = 0;
int _availableHeight = 0;
uint64 _revealedSpoilerId = 0;
MsgId _revealedSpoilerId = 0;
rpl::lifetime _lifetime;
@@ -242,6 +242,7 @@ Panel::Panel(not_null<GroupCall*> call, ConferencePanelMigration info)
widget(),
uiShow(),
_call->messages()->listValue(),
_call->messages()->idUpdates(),
_call->messagesEnabledValue()))
, _toasts(std::make_unique<Toasts>(this))
, _controlsBackgroundColor([] {
@@ -97,6 +97,7 @@ VideoStream::VideoStream(
parent,
_show,
_call->messages()->listValue(),
_call->messages()->idUpdates(),
_call->messagesEnabledValue())) {
Core::App().calls().registerVideoStream(_call.get());
setupMembers();
+5 -2
View File
@@ -447,6 +447,7 @@ updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = U
updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update;
updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update;
updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector<int> = Update;
updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector<int> = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@@ -2046,7 +2047,7 @@ inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme;
starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice;
groupCallMessage#87b51be0 flags:# from_id:Peer date:int random_id:long message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage;
groupCallMessage#1a8afc7e flags:# id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage;
---functions---
@@ -2725,8 +2726,10 @@ phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Upd
phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates;
phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates;
phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates;
phone.sendGroupCallMessage#7e9b9c0d flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long = Bool;
phone.sendGroupCallMessage#1a8d41cf flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long = Updates;
phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool;
phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector<int> = Updates;
phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates;
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
+37 -1
View File
@@ -127,6 +127,20 @@ private:
};
class CallThumbnail final : public DynamicImage {
public:
CallThumbnail();
std::shared_ptr<DynamicImage> clone() override;
QImage image(int size) override;
void subscribeToUpdates(Fn<void()> callback) override;
private:
QImage _prepared;
};
class EmptyThumbnail final : public DynamicImage {
public:
std::shared_ptr<DynamicImage> clone() override;
@@ -430,6 +444,28 @@ void VideoThumbnail::clear() {
_media = nullptr;
}
CallThumbnail::CallThumbnail() = default;
std::shared_ptr<DynamicImage> CallThumbnail::clone() {
return std::make_shared<CallThumbnail>();
}
QImage CallThumbnail::image(int size) {
const auto ratio = style::DevicePixelRatio();
const auto full = QSize(size, size) * ratio;
if (_prepared.size() != full) {
_prepared = QImage(full, QImage::Format_ARGB32_Premultiplied);
_prepared.fill(Qt::black);
_prepared.setDevicePixelRatio(ratio);
_prepared = Images::Circle(std::move(_prepared));
}
return _prepared;
}
void CallThumbnail::subscribeToUpdates(Fn<void()> callback) {
}
std::shared_ptr<DynamicImage> EmptyThumbnail::clone() {
return std::make_shared<EmptyThumbnail>();
}
@@ -662,7 +698,7 @@ std::shared_ptr<DynamicImage> MakeStoryThumbnail(
return v::match(story->media().data, [](v::null_t) -> Result {
return std::make_shared<EmptyThumbnail>();
}, [](const std::shared_ptr<Data::GroupCall> &call) -> Result {
return std::make_shared<EmptyThumbnail>();
return std::make_shared<CallThumbnail>();
}, [&](not_null<PhotoData*> photo) -> Result {
return std::make_shared<PhotoThumbnail>(photo, id, true);
}, [&](not_null<DocumentData*> video) -> Result {
@@ -981,18 +981,18 @@ void SessionNavigation::resolveConferenceCall(
if (call->fullCount() >= conferenceLimit) {
showToast(tr::lng_confcall_participants_limit(tr::now));
} else {
parentController()->window().openInMediaView(
Media::View::OpenRequest(
parentController(),
call,
slug,
inviteMsgId));
AssertIsDebug();
//Core::App().calls().startOrJoinConferenceCall({
// .call = call,
// .linkSlug = slug,
// .joinMessageId = inviteMsgId,
//});
//parentController()->window().openInMediaView(
// Media::View::OpenRequest(
// parentController(),
// call,
// slug,
// inviteMsgId));
//AssertIsDebug();
Core::App().calls().startOrJoinConferenceCall({
.call = call,
.linkSlug = slug,
.joinMessageId = inviteMsgId,
});
close();
}
};