/* 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 "api/api_blocked_peers.h" #include "apiwrap.h" #include "base/unixtime.h" #include "data/data_changes.h" #include "data/data_peer.h" #include "data/data_peer_id.h" #include "data/data_session.h" #include "main/main_session.h" namespace Api { namespace { constexpr auto kBlockedFirstSlice = 16; constexpr auto kBlockedPerPage = 40; BlockedPeers::Slice TLToSlice( const MTPcontacts_Blocked &blocked, Data::Session &owner) { const auto create = [&](int count, const QVector &list) { auto slice = BlockedPeers::Slice(); slice.total = std::max(count, int(list.size())); slice.list.reserve(list.size()); for (const auto &contact : list) { contact.match([&](const MTPDpeerBlocked &data) { slice.list.push_back({ .id = peerFromMTP(data.vpeer_id()), .date = data.vdate().v, }); }); } return slice; }; return blocked.match([&](const MTPDcontacts_blockedSlice &data) { owner.processUsers(data.vusers()); owner.processChats(data.vchats()); return create(data.vcount().v, data.vblocked().v); }, [&](const MTPDcontacts_blocked &data) { owner.processUsers(data.vusers()); owner.processChats(data.vchats()); return create(0, data.vblocked().v); }); } } // namespace BlockedPeers::BlockedPeers(not_null api) : _session(&api->session()) , _api(&api->instance()) { } bool BlockedPeers::Slice::Item::operator==(const Item &other) const { return (id == other.id) && (date == other.date); } bool BlockedPeers::Slice::Item::operator!=(const Item &other) const { return !(*this == other); } bool BlockedPeers::Slice::operator==(const BlockedPeers::Slice &other) const { return (total == other.total) && (list == other.list); } bool BlockedPeers::Slice::operator!=(const BlockedPeers::Slice &other) const { return !(*this == other); } void BlockedPeers::block(not_null peer) { if (peer->isBlocked()) { _session->changes().peerUpdated( peer, Data::PeerUpdate::Flag::IsBlocked); return; } else if (blockAlreadySent(peer, true)) { return; } const auto requestId = _api.request(MTPcontacts_Block( MTP_flags(0), peer->input )).done([=] { const auto data = _blockRequests.take(peer); peer->setIsBlocked(true); if (_slice) { _slice->list.insert( _slice->list.begin(), { peer->id, base::unixtime::now() }); ++_slice->total; _changes.fire_copy(*_slice); } if (data) { for (const auto &callback : data->callbacks) { callback(false); } } }).fail([=] { if (const auto data = _blockRequests.take(peer)) { for (const auto &callback : data->callbacks) { callback(false); } } }).send(); _blockRequests.emplace(peer, Request{ .requestId = requestId, .blocking = true, }); } void BlockedPeers::unblock( not_null peer, Fn done, bool force) { if (!force && !peer->isBlocked()) { _session->changes().peerUpdated( peer, Data::PeerUpdate::Flag::IsBlocked); return; } else if (blockAlreadySent(peer, false, done)) { return; } const auto requestId = _api.request(MTPcontacts_Unblock( MTP_flags(0), peer->input )).done([=] { const auto data = _blockRequests.take(peer); peer->setIsBlocked(false); if (_slice) { auto &list = _slice->list; for (auto i = list.begin(); i != list.end(); ++i) { if (i->id == peer->id) { list.erase(i); break; } } if (_slice->total > list.size()) { --_slice->total; } _changes.fire_copy(*_slice); } if (data) { for (const auto &callback : data->callbacks) { callback(true); } } }).fail([=] { if (const auto data = _blockRequests.take(peer)) { for (const auto &callback : data->callbacks) { callback(false); } } }).send(); const auto i = _blockRequests.emplace(peer, Request{ .requestId = requestId, .blocking = false, }).first; if (done) { i->second.callbacks.push_back(std::move(done)); } } bool BlockedPeers::blockAlreadySent( not_null peer, bool blocking, Fn done) { const auto i = _blockRequests.find(peer); if (i == end(_blockRequests)) { return false; } else if (i->second.blocking == blocking) { if (done) { i->second.callbacks.push_back(std::move(done)); } return true; } const auto callbacks = base::take(i->second.callbacks); _blockRequests.erase(i); for (const auto &callback : callbacks) { callback(false); } return false; } void BlockedPeers::reload() { if (_requestId) { return; } request(0, [=](Slice &&slice) { if (!_slice || *_slice != slice) { _slice = slice; _changes.fire(std::move(slice)); } }); } auto BlockedPeers::slice() -> rpl::producer { if (!_slice) { reload(); } return _slice ? _changes.events_starting_with_copy(*_slice) : (_changes.events() | rpl::type_erased()); } void BlockedPeers::request(int offset, Fn done) { if (_requestId) { return; } _requestId = _api.request(MTPcontacts_GetBlocked( MTP_flags(0), MTP_int(offset), MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice) )).done([=](const MTPcontacts_Blocked &result) { _requestId = 0; done(TLToSlice(result, _session->data())); }).fail([=] { _requestId = 0; }).send(); } } // namespace Api