Update API scheme on layer 202.

This commit is contained in:
John Preston 2025-03-28 23:04:14 +05:00
parent 4401ea388c
commit 4eaf03b922
16 changed files with 123 additions and 81 deletions

View file

@ -678,14 +678,14 @@ void Instance::handleGroupCallUpdate(
}, [](const MTPDupdateGroupCallParticipants &data) {
return data.vcall().match([&](const MTPDinputGroupCall &data) {
return data.vid().v;
}, [](const MTPDinputGroupCallSlug &) -> CallId {
Unexpected("slug in Instance::handleGroupCallUpdate");
}, [](const auto &) -> CallId {
Unexpected("slug/msg in Instance::handleGroupCallUpdate");
});
}, [](const MTPDupdateGroupCallChainBlocks &data) {
return data.vcall().match([&](const MTPDinputGroupCall &data) {
return data.vid().v;
}, [](const MTPDinputGroupCallSlug &) -> CallId {
Unexpected("slug in Instance::handleGroupCallUpdate");
}, [](const auto &) -> CallId {
Unexpected("slug/msg in Instance::handleGroupCallUpdate");
});
}, [](const auto &) -> CallId {
Unexpected("Type in Instance::handleGroupCallUpdate.");

View file

@ -715,44 +715,55 @@ void GroupCall::setupConferenceCall() {
sendOutboundBlock(std::move(block));
}, _lifetime);
_conferenceCall->staleParticipantId(
) | rpl::start_with_next([=](UserId staleId) {
removeConferenceParticipant(staleId);
_conferenceCall->staleParticipantIds(
) | rpl::start_with_next([=](const base::flat_set<UserId> &staleIds) {
removeConferenceParticipants(staleIds);
}, _lifetime);
_e2e->participantsSetValue(
) | rpl::start_with_next([=](const TdE2E::ParticipantsSet &set) {
auto users = base::flat_set<UserId>();
users.reserve(set.list.size());
auto ids = QStringList();
for (const auto &id : set.list) {
users.emplace(UserId(id.v));
ids.push_back('"' + _peer->owner().user(UserId(id.v))->name() + '"');
}
LOG(("ACCESS: ") + ids.join(", "));
_conferenceCall->setParticipantsWithAccess(std::move(users));
}, _lifetime);
}
void GroupCall::removeConferenceParticipant(UserId id) {
void GroupCall::removeConferenceParticipants(
const base::flat_set<UserId> userIds) {
Expects(_e2e != nullptr);
Expects(!userIds.empty());
const auto block = _e2e->makeRemoveBlock(TdE2E::MakeUserId(id));
const auto owner = &_peer->owner();
auto inputs = QVector<MTPInputPeer>();
inputs.reserve(userIds.size());
auto ids = base::flat_set<TdE2E::UserId>();
ids.reserve(userIds.size());
for (const auto &id : userIds) {
inputs.push_back(owner->user(id)->input);
ids.emplace(TdE2E::MakeUserId(id));
}
const auto block = _e2e->makeRemoveBlock(ids);
if (block.data.isEmpty()) {
return;
}
_api.request(MTPphone_DeleteConferenceCallParticipant(
_api.request(MTPphone_DeleteConferenceCallParticipants(
inputCall(),
_peer->owner().user(id)->input,
MTP_vector<MTPInputPeer>(std::move(inputs)),
MTP_bytes(block.data)
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
}).fail([=](const MTP::Error &error) {
const auto type = error.type();
if (type == u"GROUPCALL_FORBIDDEN"_q) {
setState(State::Joining);
rejoin();
LOG(("Call Info: "
"Rejoin after error '%1' in delete confcall participants"
).arg(type));
startRejoin();
} else {
LOG(("NOTREMOVED: %1").arg(type));
LOG(("Call Error: Could not remove confcall participants: %1"
).arg(type));
}
}).send();
}
@ -1187,8 +1198,8 @@ void GroupCall::join(const MTPInputGroupCall &inputCall) {
inputCall.match([&](const MTPDinputGroupCall &data) {
_id = data.vid().v;
_accessHash = data.vaccess_hash().v;
}, [&](const MTPDinputGroupCallSlug &) {
Unexpected("inputGroupCallSlug in GroupCall::join.");
}, [&](const auto &) {
Unexpected("slug/msg in GroupCall::join.");
});
setState(_scheduleDate ? State::Waiting : State::Joining);
@ -1391,6 +1402,14 @@ void GroupCall::markTrackPaused(const VideoEndpoint &endpoint, bool paused) {
: Webrtc::VideoState::Active);
}
void GroupCall::startRejoin() {
for (const auto &[task, part] : _broadcastParts) {
_api.request(part.requestId).cancel();
}
setState(State::Joining);
rejoin();
}
void GroupCall::rejoin() {
rejoin(joinAs());
}
@ -1489,10 +1508,7 @@ void GroupCall::sendJoinRequest() {
| (_e2e ? (Flag::f_public_key | Flag::f_block) : Flag());
_api.request(MTPphone_JoinGroupCall(
MTP_flags(flags),
(_conferenceLinkSlug.isEmpty()
? inputCall()
: MTP_inputGroupCallSlug(
MTP_string(_conferenceLinkSlug))),
inputCallSafe(),
joinAs()->input,
MTP_string(_joinHash),
(_e2e ? TdE2E::PublicKeyToMTP(_e2e->myKey()) : MTPint256()),
@ -1573,7 +1589,7 @@ void GroupCall::refreshLastBlockAndJoin() {
return;
}
_api.request(MTPphone_GetGroupCallChainBlocks(
inputCall(),
inputCallSafe(),
MTP_int(0),
MTP_int(-1),
MTP_int(1)
@ -1632,6 +1648,11 @@ void GroupCall::requestSubchainBlocks(int subchain, int height) {
auto &state = _subchains[subchain];
state.requestId = 0;
_e2e->subchainBlocksRequestFinished(subchain);
if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
LOG(("Call Info: Rejoin after error '%1' in get chain blocks."
).arg(error.type()));
startRejoin();
}
}).send();
}
@ -1646,13 +1667,14 @@ void GroupCall::sendOutboundBlock(QByteArray block) {
const auto type = error.type();
if (type == u"GROUPCALL_FORBIDDEN"_q) {
_pendingOutboundBlock = block;
setState(State::Joining);
rejoin();
LOG(("Call Info: Rejoin after error '%1' in send confcall block."
).arg(type));
startRejoin();
} else if (type == u"BLOCK_INVALID"_q
|| type.startsWith(u"CONF_WRITE_CHAIN_INVALID"_q)) {
LOG(("Call Error: Could not broadcast block: %1").arg(type));
} else {
LOG(("HMM"));
LOG(("Call Error: Got '%1' in send confcall block.").arg(type));
sendOutboundBlock(block);
}
}).send();
@ -2196,8 +2218,8 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallParticipants &data) {
const auto callId = data.vcall().match([](
const MTPDinputGroupCall &data) {
return data.vid().v;
}, [](const MTPDinputGroupCallSlug &) -> CallId {
Unexpected("inputGroupCallSlug in GroupCall::handleUpdate.");
}, [](const auto &) -> CallId {
Unexpected("slug/msg in GroupCall::handleUpdate.");
});
if (_id != callId) {
return;
@ -2225,8 +2247,8 @@ void GroupCall::handleUpdate(const MTPDupdateGroupCallChainBlocks &data) {
const auto callId = data.vcall().match([](
const MTPDinputGroupCall &data) {
return data.vid().v;
}, [](const MTPDinputGroupCallSlug &) -> CallId {
Unexpected("inputGroupCallSlug in GroupCall::handleUpdate.");
}, [](const auto &) -> CallId {
Unexpected("slug/msg in GroupCall::handleUpdate.");
});
if (_id != callId || !_e2e) {
return;
@ -2279,8 +2301,7 @@ void GroupCall::applySelfUpdate(const MTPDgroupCallParticipant &data) {
// I was removed from the call, rejoin.
LOG(("Call Info: "
"Rejoin after got 'left' with my ssrc."));
setState(State::Joining);
rejoin();
startRejoin();
}
return;
} else if (data.vsource().v != _joinState.ssrc) {
@ -2307,8 +2328,7 @@ void GroupCall::applySelfUpdate(const MTPDgroupCallParticipant &data) {
: MuteState::ForceMuted);
} else if (_instanceMode == InstanceMode::Stream) {
LOG(("Call Info: Rejoin after unforcemute in stream mode."));
setState(State::Joining);
rejoin();
startRejoin();
} else if (mutedByAdmin()) {
setMuted(MuteState::Muted);
if (!_instanceTransitioning) {
@ -2882,11 +2902,7 @@ void GroupCall::broadcastPartStart(std::shared_ptr<LoadPartTask> task) {
}).fail([=](const MTP::Error &error, const MTP::Response &response) {
if (error.type() == u"GROUPCALL_JOIN_MISSING"_q
|| error.type() == u"GROUPCALL_FORBIDDEN"_q) {
for (const auto &[task, part] : _broadcastParts) {
_api.request(part.requestId).cancel();
}
setState(State::Joining);
rejoin();
startRejoin();
return;
}
const auto status = (MTP::IsFloodError(error)
@ -3005,11 +3021,7 @@ void GroupCall::requestCurrentTimeStart(
if (error.type() == u"GROUPCALL_JOIN_MISSING"_q
|| error.type() == u"GROUPCALL_FORBIDDEN"_q) {
for (const auto &[task, part] : _broadcastParts) {
_api.request(part.requestId).cancel();
}
setState(State::Joining);
rejoin();
startRejoin();
}
}).handleAllErrors().toDC(
MTP::groupCallStreamDcId(_broadcastDcId)
@ -3415,7 +3427,7 @@ void GroupCall::checkJoined() {
}).fail([=](const MTP::Error &error) {
LOG(("Call Info: Full rejoin after error '%1' in checkGroupCall."
).arg(error.type()));
rejoin();
startRejoin();
}).send();
}
@ -3590,7 +3602,7 @@ void GroupCall::sendSelfUpdate(SendUpdateType type) {
if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
LOG(("Call Info: Rejoin after error '%1' in editGroupCallMember."
).arg(error.type()));
rejoin();
startRejoin();
}
}).send();
}
@ -3684,7 +3696,7 @@ void GroupCall::editParticipant(
if (error.type() == u"GROUPCALL_FORBIDDEN"_q) {
LOG(("Call Info: Rejoin after error '%1' in editGroupCallMember."
).arg(error.type()));
rejoin();
startRejoin();
}
}).send();
}
@ -3700,7 +3712,7 @@ std::variant<int, not_null<UserData*>> GroupCall::inviteUsers(
if (_conferenceCall) {
for (const auto &user : users) {
_api.request(MTPphone_InviteConferenceCallParticipant(
inputCall(),
inputCallSafe(),
user->inputUser
)).send();
}
@ -3821,9 +3833,16 @@ auto GroupCall::otherParticipantStateValue() const
MTPInputGroupCall GroupCall::inputCall() const {
Expects(_id != 0);
return MTP_inputGroupCall(
MTP_long(_id),
MTP_long(_accessHash));
return MTP_inputGroupCall(MTP_long(_id), MTP_long(_accessHash));
}
MTPInputGroupCall GroupCall::inputCallSafe() const {
const auto inviteMsgId = _conferenceJoinMessageId.bare;
return inviteMsgId
? MTP_inputGroupCallInviteMessage(MTP_int(inviteMsgId))
: _conferenceLinkSlug.isEmpty()
? inputCall()
: MTP_inputGroupCallSlug(MTP_string(_conferenceLinkSlug));
}
void GroupCall::destroyController() {

View file

@ -281,7 +281,7 @@ public:
void startScheduledNow();
void toggleScheduleStartSubscribed(bool subscribed);
void setNoiseSuppression(bool enabled);
void removeConferenceParticipant(UserId userId);
void removeConferenceParticipants(const base::flat_set<UserId> userIds);
bool emitShareScreenError();
bool emitShareCameraError();
@ -545,6 +545,7 @@ private:
const std::optional<Data::GroupCallParticipant> &was,
const Data::GroupCallParticipant &now);
void applyMeInCallLocally();
void startRejoin();
void rejoin();
void leave();
void rejoin(not_null<PeerData*> as);
@ -615,6 +616,7 @@ private:
[[nodiscard]] int activeVideoSendersCount() const;
[[nodiscard]] MTPInputGroupCall inputCall() const;
[[nodiscard]] MTPInputGroupCall inputCallSafe() const;
const not_null<Delegate*> _delegate;
const std::shared_ptr<Data::GroupCall> _conferenceCall;

View file

@ -1006,7 +1006,7 @@ void ChannelData::setGroupCall(
owner().registerGroupCall(_call.get());
session().changes().peerUpdated(this, UpdateFlag::GroupCall);
addFlags(Flag::CallActive);
}, [&](const MTPDinputGroupCallSlug &) {
}, [&](const auto &) {
clearGroupCall();
});
}

View file

@ -239,7 +239,7 @@ void ChatData::setGroupCall(
owner().registerGroupCall(_call.get());
session().changes().peerUpdated(this, UpdateFlag::GroupCall);
addFlags(Flag::CallActive);
}, [&](const MTPDinputGroupCallSlug &) {
}, [&](const auto &) {
clearGroupCall();
});
}

View file

@ -85,7 +85,7 @@ GroupCall::GroupCall(
}) | rpl::start_with_next([=](const ParticipantUpdate &update) {
if (const auto id = peerToUser(update.was->peer->id)) {
if (_participantsWithAccess.current().contains(id)) {
_staleParticipantId.fire_copy(id);
_staleParticipantIds.fire({ id });
}
}
}, _checkStaleLifetime);
@ -262,12 +262,16 @@ void GroupCall::checkStaleRequest() {
existing.emplace(id);
}
}
auto stale = base::flat_set<UserId>();
for (const auto &id : list) {
if (!existing.contains(id)) {
_staleParticipantId.fire_copy(id);
return;
stale.reserve(list.size());
stale.emplace(id);
}
}
if (!stale.empty()) {
_staleParticipantIds.fire(std::move(stale));
}
}).fail([=] {
_checkStaleRequestId = 0;
}).send();
@ -402,8 +406,9 @@ auto GroupCall::participantsWithAccessValue() const
return _participantsWithAccess.value();
}
rpl::producer<UserId> GroupCall::staleParticipantId() const {
return _staleParticipantId.events();
auto GroupCall::staleParticipantIds() const
-> rpl::producer<base::flat_set<UserId>> {
return _staleParticipantIds.events();
}
void GroupCall::enqueueUpdate(const MTPUpdate &update) {

View file

@ -150,7 +150,8 @@ public:
-> const base::flat_set<UserId> &;
[[nodiscard]] auto participantsWithAccessValue() const
-> rpl::producer<base::flat_set<UserId>>;
[[nodiscard]] rpl::producer<UserId> staleParticipantId() const;
[[nodiscard]] auto staleParticipantIds() const
-> rpl::producer<base::flat_set<UserId>>;
void setParticipantsLoaded();
void checkStaleParticipants();
void checkStaleRequest();
@ -264,7 +265,7 @@ private:
rpl::event_stream<> _participantsReloaded;
rpl::variable<base::flat_set<UserId>> _participantsWithAccess;
rpl::event_stream<UserId> _staleParticipantId;
rpl::event_stream<base::flat_set<UserId>> _staleParticipantIds;
mtpRequestId _checkStaleRequestId = 0;
rpl::lifetime _checkStaleLifetime;

View file

@ -1227,9 +1227,9 @@ void History::applyServiceChanges(
}
}
}, [&](const MTPDmessageActionConferenceCall &data) {
if (!data.is_active() && !data.is_missed()) {
if (!data.is_active() && !data.is_missed() && !item->out()) {
if (const auto window = session().tryResolveWindow()) {
window->resolveConferenceCall(qs(data.vslug()), item->id);
window->resolveConferenceCall(item->id);
}
}
}, [](const auto &) {

View file

@ -5640,13 +5640,12 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
}
const auto id = this->id;
const auto slug = qs(action.vslug());
setCustomServiceLink(std::make_shared<LambdaClickHandler>([=](
ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
const auto weak = my.sessionWindow;
if (const auto strong = weak.get()) {
strong->resolveConferenceCall(slug, id);
strong->resolveConferenceCall(id);
}
}));

View file

@ -915,8 +915,8 @@ MediaCheckResult CheckMessageMedia(const MTPMessageMedia &media) {
[[nodiscard]] CallId CallIdFromInput(const MTPInputGroupCall &data) {
return data.match([&](const MTPDinputGroupCall &data) {
return data.vid().v;
}, [](const MTPDinputGroupCallSlug &) -> CallId {
Unexpected("inputGroupCallSlug in CallIdFromInput.");
}, [](const auto &) -> CallId {
Unexpected("slug/msg in CallIdFromInput.");
});
}

View file

@ -187,7 +187,7 @@ messageActionStarGift#4717e8a4 flags:# name_hidden:flags.0?true saved:flags.2?tr
messageActionStarGiftUnique#acdfcb81 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long = MessageAction;
messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction;
messageActionPaidMessagesPrice#bcd71419 stars:long = MessageAction;
messageActionConferenceCall#ff397dea flags:# missed:flags.0?true active:flags.1?true call_id:long slug:string duration:flags.2?int other_participants:flags.3?Vector<Peer> = MessageAction;
messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true call_id:long duration:flags.2?int other_participants:flags.3?Vector<Peer> = MessageAction;
dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
@ -1346,6 +1346,7 @@ groupCall#d597650c flags:# join_muted:flags.1?true can_change_join_muted:flags.2
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
inputGroupCallSlug#fe06823f slug:string = InputGroupCall;
inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall;
groupCallParticipant#eba636fe flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo = GroupCallParticipant;
@ -2607,7 +2608,7 @@ phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallS
phone.getGroupCallStreamRtmpUrl#deb3abbf peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl;
phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool;
phone.createConferenceCall#fbcefee6 random_id:int = phone.GroupCall;
phone.deleteConferenceCallParticipant#7b8cc2a3 call:InputGroupCall peer:InputPeer block:bytes = Updates;
phone.deleteConferenceCallParticipants#22e547c7 call:InputGroupCall ids:Vector<InputPeer> block:bytes = Updates;
phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates;
phone.inviteConferenceCallParticipant#3e9cf7ee call:InputGroupCall user_id:InputUser = Updates;
phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates;

View file

@ -124,8 +124,8 @@ Block Call::makeJoinBlock() {
};
}
Block Call::makeRemoveBlock(UserId id) {
if (failed() || !_id || id == _myUserId) {
Block Call::makeRemoveBlock(const base::flat_set<UserId> &ids) {
if (failed() || !_id) {
return {};
}
@ -137,11 +137,13 @@ Block Call::makeRemoveBlock(UserId id) {
auto found = false;
auto updated = state.value();
auto &list = updated.participants;
for (auto i = begin(list); i != end(list); ++i) {
if (uint64(i->user_id) == id.v) {
list.erase(i);
for (auto i = begin(list); i != end(list);) {
const auto userId = UserId{ uint64(i->user_id) };
if (userId != _myUserId && ids.contains(userId)) {
i = list.erase(i);
found = true;
break;
} else {
++i;
}
}
if (!found) {

View file

@ -97,7 +97,7 @@ public:
void refreshLastBlock0(std::optional<Block> block);
[[nodiscard]] Block makeJoinBlock();
[[nodiscard]] Block makeRemoveBlock(UserId id);
[[nodiscard]] Block makeRemoveBlock(const base::flat_set<UserId> &ids);
[[nodiscard]] rpl::producer<ParticipantsSet> participantsSetValue() const;

View file

@ -173,7 +173,7 @@ StorageFileLocation::StorageFileLocation(
_id = data.vid().v;
_accessHash = data.vaccess_hash().v;
}, [](const auto &data) {
Unexpected("inputGroupCallSlug in inputGroupCallStream.");
Unexpected("slug/msg in inputGroupCallStream.");
});
_volumeId = data.vtime_ms().v;
_localId = data.vscale().v;

View file

@ -840,6 +840,14 @@ void SessionNavigation::resolveCollectible(
}).send();
}
void SessionNavigation::resolveConferenceCall(const QString &slug) {
resolveConferenceCall(slug, 0);
}
void SessionNavigation::resolveConferenceCall(MsgId inviteMsgId) {
resolveConferenceCall(QString(), inviteMsgId);
}
void SessionNavigation::resolveConferenceCall(
const QString &slug,
MsgId inviteMsgId) {
@ -853,11 +861,14 @@ void SessionNavigation::resolveConferenceCall(
const auto limit = 5;
_conferenceCallRequestId = _api.request(MTPphone_GetGroupCall(
MTP_inputGroupCallSlug(MTP_string(slug)),
(inviteMsgId
? MTP_inputGroupCallInviteMessage(MTP_int(inviteMsgId.bare))
: MTP_inputGroupCallSlug(MTP_string(slug))),
MTP_int(limit)
)).done([=](const MTPphone_GroupCall &result) {
_conferenceCallRequestId = 0;
const auto slug = base::take(_conferenceCallSlug);
const auto inviteMsgId = base::take(_conferenceCallInviteMsgId);
result.data().vcall().match([&](const auto &data) {
const auto call = std::make_shared<Data::GroupCall>(
@ -884,7 +895,7 @@ void SessionNavigation::resolveConferenceCall(
box->boxClosing() | rpl::start_with_next([=] {
if (inviteMsgId && !*confirmed) {
_api.request(MTPphone_DeclineConferenceCallInvite(
MTP_int(inviteMsgId)
MTP_int(inviteMsgId.bare)
)).send();
}
}, box->lifetime());

View file

@ -264,7 +264,8 @@ public:
PeerId ownerId,
const QString &entity,
Fn<void(QString)> fail = nullptr);
void resolveConferenceCall(const QString &slug, MsgId inviteMsgId = 0);
void resolveConferenceCall(const QString &slug);
void resolveConferenceCall(MsgId inviteMsgId);
base::weak_ptr<Ui::Toast::Instance> showToast(
Ui::Toast::Config &&config);
@ -291,6 +292,7 @@ private:
void resolveChannelById(
ChannelId channelId,
Fn<void(not_null<ChannelData*>)> done);
void resolveConferenceCall(const QString &slug, MsgId inviteMsgId);
void resolveDone(
const MTPcontacts_ResolvedPeer &result,