/* 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 "main/session/send_as_peers.h" #include "data/data_user.h" #include "data/data_channel.h" #include "data/data_session.h" #include "data/data_changes.h" #include "main/main_session.h" #include "apiwrap.h" namespace Main { namespace { constexpr auto kRequestEach = 30 * crl::time(1000); } // namespace SendAsPeers::SendAsPeers(not_null session) : _session(session) , _onlyMe({ { .peer = session->user(), .premiumRequired = false } }) , _onlyMePaid({ session->user() }) { _session->changes().peerUpdates( Data::PeerUpdate::Flag::Rights ) | rpl::map([=](const Data::PeerUpdate &update) { const auto peer = update.peer; const auto channel = peer->asChannel(); const auto bits = 0 | (peer->amAnonymous() ? (1 << 0) : 0) | ((channel && channel->isPublic()) ? (1 << 1) : 0) | ((channel && channel->addsSignature()) ? (1 << 2) : 0) | ((channel && channel->signatureProfiles()) ? (1 << 3) : 0); return std::tuple(peer, bits); }) | rpl::distinct_until_changed( ) | rpl::filter([=](not_null peer, int) { return _lists.contains(peer) || _lastRequestTime.contains(peer); }) | rpl::on_next([=](not_null peer, int) { refresh(peer, true); }, _lifetime); } bool SendAsPeers::shouldChoose(SendAsKey key) { refresh(key); if (list(key).size() < 2) { return false; } if (key.type == SendAsType::VideoStream) { return true; } const auto channel = key.peer->asBroadcast(); return Data::CanSendAnything(key.peer, false) && (!channel || channel->addsSignature() || channel->signatureProfiles()); } void SendAsPeers::refresh(SendAsKey key, bool force) { if (key.type != SendAsType::VideoStream && !key.peer->isChannel()) { return; } const auto now = crl::now(); const auto i = _lastRequestTime.find(key); const auto when = (i == end(_lastRequestTime)) ? -1 : i->second; if (!force && (when >= 0 && now < when + kRequestEach)) { return; } _lastRequestTime[key] = now; request(key); if (key.type == SendAsType::Message) { request({ key.peer, SendAsType::PaidReaction }); } } const std::vector &SendAsPeers::list(SendAsKey key) const { if (key.type != SendAsType::VideoStream && !key.peer->isChannel()) { return _onlyMe; } const auto i = _lists.find(key); return (i != end(_lists)) ? i->second : _onlyMe; } rpl::producer SendAsPeers::updated() const { return _updates.events(); } void SendAsPeers::saveChosen( not_null peer, not_null chosen) { peer->session().api().request(MTPmessages_SaveDefaultSendAs( peer->input(), chosen->input() )).send(); setChosen(peer, chosen->id); } void SendAsPeers::setChosen(not_null peer, PeerId chosenId) { if (chosen(peer) == chosenId) { return; } const auto fallback = peer->amAnonymous() ? peer : peer->session().user(); if (fallback->id == chosenId) { _chosen.remove(peer); } else { _chosen[peer] = chosenId; } _updates.fire({ peer }); } PeerId SendAsPeers::chosen(not_null peer) const { const auto i = _chosen.find(peer); return (i != end(_chosen)) ? i->second : PeerId(); } not_null SendAsPeers::resolveChosen( not_null peer) const { return ResolveChosen(peer, list({ peer }), chosen(peer)); } not_null SendAsPeers::ResolveChosen( not_null peer, const std::vector &list, PeerId chosen) { const auto fallback = peer->amAnonymous() ? peer : peer->session().user(); if (!chosen) { chosen = fallback->id; } const auto i = ranges::find(list, chosen, [](const SendAsPeer &as) { return as.peer->id; }); return (i != end(list)) ? i->peer : !list.empty() ? list.front().peer : fallback; } void SendAsPeers::request(SendAsKey key) { using Flag = MTPchannels_GetSendAs::Flag; key.peer->session().api().request(MTPchannels_GetSendAs( MTP_flags((key.type == SendAsType::PaidReaction) ? Flag::f_for_paid_reactions : (key.type == SendAsType::VideoStream) ? Flag::f_for_live_stories : Flag()), key.peer->input() )).done([=](const MTPchannels_SendAsPeers &result) { auto parsed = std::vector(); auto &owner = key.peer->owner(); result.match([&](const MTPDchannels_sendAsPeers &data) { owner.processUsers(data.vusers()); owner.processChats(data.vchats()); const auto &list = data.vpeers().v; parsed.reserve(list.size()); for (const auto &as : list) { const auto &data = as.data(); const auto peerId = peerFromMTP(data.vpeer()); if (const auto peer = owner.peerLoaded(peerId)) { parsed.push_back({ .peer = peer, .premiumRequired = data.is_premium_required(), }); } } }); if (parsed.size() > 1) { auto &now = _lists[key]; if (now != parsed) { now = std::move(parsed); _updates.fire_copy(key); } } else if (const auto i = _lists.find(key); i != end(_lists)) { _lists.erase(i); _updates.fire_copy(key); } }).send(); } } // namespace Main