/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_group_call.h" #include "data/data_channel.h" #include "data/data_changes.h" #include "data/data_session.h" #include "main/main_session.h" #include "apiwrap.h" namespace Data { namespace { constexpr auto kRequestPerPage = 30; } // namespace GroupCall::GroupCall( not_null channel, uint64 id, uint64 accessHash) : _channel(channel) , _id(id) , _accessHash(accessHash) { } GroupCall::~GroupCall() { _channel->session().api().request(_participantsRequestId).cancel(); _channel->session().api().request(_reloadRequestId).cancel(); } uint64 GroupCall::id() const { return _id; } not_null GroupCall::channel() const { return _channel; } MTPInputGroupCall GroupCall::input() const { return MTP_inputGroupCall(MTP_long(_id), MTP_long(_accessHash)); } auto GroupCall::participants() const -> const std::vector & { return _participants; } void GroupCall::requestParticipants() { if (_participantsRequestId || _reloadRequestId) { return; } else if (_participants.size() >= _fullCount.current() && _allReceived) { return; } else if (_allReceived) { reload(); return; } auto &api = _channel->session().api(); _participantsRequestId = api.request(MTPphone_GetGroupParticipants( input(), MTP_vector(), // ids MTP_vector(), // sources MTP_string(_nextOffset), MTP_int(kRequestPerPage) )).done([=](const MTPphone_GroupParticipants &result) { result.match([&](const MTPDphone_groupParticipants &data) { _nextOffset = qs(data.vnext_offset()); _channel->owner().processUsers(data.vusers()); applyParticipantsSlice(data.vparticipants().v); _fullCount = data.vcount().v; if (!_allReceived && (data.vparticipants().v.size() < kRequestPerPage)) { _allReceived = true; } if (_allReceived) { _fullCount = _participants.size(); } }); _participantsSliceAdded.fire({}); _participantsRequestId = 0; }).fail([=](const RPCError &error) { _fullCount = _participants.size(); _allReceived = true; _participantsRequestId = 0; }).send(); } int GroupCall::fullCount() const { return _fullCount.current(); } rpl::producer GroupCall::fullCountValue() const { return _fullCount.value(); } bool GroupCall::participantsLoaded() const { return _allReceived; } UserData *GroupCall::userBySource(uint32 source) const { const auto i = _userBySource.find(source); return (i != end(_userBySource)) ? i->second.get() : nullptr; } rpl::producer<> GroupCall::participantsSliceAdded() { return _participantsSliceAdded.events(); } auto GroupCall::participantUpdated() const -> rpl::producer { return _participantUpdates.events(); } void GroupCall::applyUpdate(const MTPGroupCall &update) { applyCall(update, false); } void GroupCall::applyCall(const MTPGroupCall &call, bool force) { call.match([&](const MTPDgroupCall &data) { const auto changed = (_version != data.vversion().v) || (_fullCount.current() != data.vparticipants_count().v) || (_joinMuted != data.is_join_muted()) || (_canChangeJoinMuted != data.is_can_change_join_muted()); if (!force && !changed) { return; } else if (!force && _version > data.vversion().v) { reload(); return; } _joinMuted = data.is_join_muted(); _canChangeJoinMuted = data.is_can_change_join_muted(); _version = data.vversion().v; _fullCount = data.vparticipants_count().v; }, [&](const MTPDgroupCallDiscarded &data) { const auto id = _id; const auto channel = _channel; crl::on_main(&channel->session(), [=] { if (channel->call() && channel->call()->id() == id) { channel->clearCall(); } }); }); } void GroupCall::reload() { if (_reloadRequestId) { return; } else if (_participantsRequestId) { _channel->session().api().request(_participantsRequestId).cancel(); _participantsRequestId = 0; } _reloadRequestId = _channel->session().api().request( MTPphone_GetGroupCall(input()) ).done([=](const MTPphone_GroupCall &result) { result.match([&](const MTPDphone_groupCall &data) { _channel->owner().processUsers(data.vusers()); _participants.clear(); applyParticipantsSlice(data.vparticipants().v); applyCall(data.vcall(), true); _allReceived = (_fullCount.current() == _participants.size()); _participantsSliceAdded.fire({}); }); _reloadRequestId = 0; }).fail([=](const RPCError &error) { _reloadRequestId = 0; }).send(); } void GroupCall::applyParticipantsSlice( const QVector &list, bool sendIndividualUpdates) { auto fullCount = _fullCount.current(); for (const auto &participant : list) { participant.match([&](const MTPDgroupCallParticipant &data) { const auto userId = data.vuser_id().v; const auto user = _channel->owner().user(userId); const auto i = ranges::find( _participants, user, &Participant::user); if (data.is_left()) { if (i != end(_participants)) { auto update = ParticipantUpdate{ .participant = *i, .removed = true, }; _userBySource.erase(i->source); _participants.erase(i); if (sendIndividualUpdates) { _participantUpdates.fire(std::move(update)); } } if (fullCount > _participants.size()) { --fullCount; } return; } const auto value = Participant{ .user = user, .date = data.vdate().v, .source = uint32(data.vsource().v), .muted = data.is_muted(), .canSelfUnmute = !data.is_muted() || data.is_can_self_unmute(), }; if (i == end(_participants)) { _userBySource.emplace(value.source, value.user); _participants.push_back(value); ++fullCount; } else { if (i->source != value.source) { _userBySource.erase(i->source); _userBySource.emplace(value.source, value.user); } *i = value; } _participantUpdates.fire({ .participant = value, }); }); } ranges::sort(_participants, std::greater<>(), [](const Participant &p) { return p.lastSpoke ? p.lastSpoke : p.lastActive ? p.lastActive : p.date; }); _fullCount = fullCount; } void GroupCall::applyParticipantsMutes( const MTPDupdateGroupCallParticipants &update) { for (const auto &participant : update.vparticipants().v) { participant.match([&](const MTPDgroupCallParticipant &data) { if (data.is_left()) { return; } const auto userId = data.vuser_id().v; const auto user = _channel->owner().user(userId); const auto i = ranges::find( _participants, user, &Participant::user); if (i != end(_participants)) { i->muted = data.is_muted(); i->canSelfUnmute = !i->muted || data.is_can_self_unmute(); _participantUpdates.fire({ .participant = *i, }); } }); } } void GroupCall::applyUpdate(const MTPDupdateGroupCallParticipants &update) { const auto version = update.vversion().v; if (version < _version) { return; } else if (version == _version) { applyParticipantsMutes(update); return; } else if (version != _version + 1) { applyParticipantsMutes(update); reload(); return; } _version = update.vversion().v; applyUpdateChecked(update); } void GroupCall::applyUpdateChecked( const MTPDupdateGroupCallParticipants &update) { applyParticipantsSlice(update.vparticipants().v, true); } void GroupCall::setJoinMutedLocally(bool muted) { _joinMuted = muted; } bool GroupCall::joinMuted() const { return _joinMuted; } bool GroupCall::canChangeJoinMuted() const { return _canChangeJoinMuted; } } // namespace Data