api_blocked_peers.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "api/api_blocked_peers.h"
  8. #include "apiwrap.h"
  9. #include "base/unixtime.h"
  10. #include "data/data_changes.h"
  11. #include "data/data_peer.h"
  12. #include "data/data_peer_id.h"
  13. #include "data/data_session.h"
  14. #include "main/main_session.h"
  15. namespace Api {
  16. namespace {
  17. constexpr auto kBlockedFirstSlice = 16;
  18. constexpr auto kBlockedPerPage = 40;
  19. BlockedPeers::Slice TLToSlice(
  20. const MTPcontacts_Blocked &blocked,
  21. Data::Session &owner) {
  22. const auto create = [&](int count, const QVector<MTPPeerBlocked> &list) {
  23. auto slice = BlockedPeers::Slice();
  24. slice.total = std::max(count, int(list.size()));
  25. slice.list.reserve(list.size());
  26. for (const auto &contact : list) {
  27. contact.match([&](const MTPDpeerBlocked &data) {
  28. slice.list.push_back({
  29. .id = peerFromMTP(data.vpeer_id()),
  30. .date = data.vdate().v,
  31. });
  32. });
  33. }
  34. return slice;
  35. };
  36. return blocked.match([&](const MTPDcontacts_blockedSlice &data) {
  37. owner.processUsers(data.vusers());
  38. owner.processChats(data.vchats());
  39. return create(data.vcount().v, data.vblocked().v);
  40. }, [&](const MTPDcontacts_blocked &data) {
  41. owner.processUsers(data.vusers());
  42. owner.processChats(data.vchats());
  43. return create(0, data.vblocked().v);
  44. });
  45. }
  46. } // namespace
  47. BlockedPeers::BlockedPeers(not_null<ApiWrap*> api)
  48. : _session(&api->session())
  49. , _api(&api->instance()) {
  50. }
  51. bool BlockedPeers::Slice::Item::operator==(const Item &other) const {
  52. return (id == other.id) && (date == other.date);
  53. }
  54. bool BlockedPeers::Slice::Item::operator!=(const Item &other) const {
  55. return !(*this == other);
  56. }
  57. bool BlockedPeers::Slice::operator==(const BlockedPeers::Slice &other) const {
  58. return (total == other.total) && (list == other.list);
  59. }
  60. bool BlockedPeers::Slice::operator!=(const BlockedPeers::Slice &other) const {
  61. return !(*this == other);
  62. }
  63. void BlockedPeers::block(not_null<PeerData*> peer) {
  64. if (peer->isBlocked()) {
  65. _session->changes().peerUpdated(
  66. peer,
  67. Data::PeerUpdate::Flag::IsBlocked);
  68. return;
  69. } else if (blockAlreadySent(peer, true)) {
  70. return;
  71. }
  72. const auto requestId = _api.request(MTPcontacts_Block(
  73. MTP_flags(0),
  74. peer->input
  75. )).done([=] {
  76. const auto data = _blockRequests.take(peer);
  77. peer->setIsBlocked(true);
  78. if (_slice) {
  79. _slice->list.insert(
  80. _slice->list.begin(),
  81. { peer->id, base::unixtime::now() });
  82. ++_slice->total;
  83. _changes.fire_copy(*_slice);
  84. }
  85. if (data) {
  86. for (const auto &callback : data->callbacks) {
  87. callback(false);
  88. }
  89. }
  90. }).fail([=] {
  91. if (const auto data = _blockRequests.take(peer)) {
  92. for (const auto &callback : data->callbacks) {
  93. callback(false);
  94. }
  95. }
  96. }).send();
  97. _blockRequests.emplace(peer, Request{
  98. .requestId = requestId,
  99. .blocking = true,
  100. });
  101. }
  102. void BlockedPeers::unblock(
  103. not_null<PeerData*> peer,
  104. Fn<void(bool success)> done,
  105. bool force) {
  106. if (!force && !peer->isBlocked()) {
  107. _session->changes().peerUpdated(
  108. peer,
  109. Data::PeerUpdate::Flag::IsBlocked);
  110. return;
  111. } else if (blockAlreadySent(peer, false, done)) {
  112. return;
  113. }
  114. const auto requestId = _api.request(MTPcontacts_Unblock(
  115. MTP_flags(0),
  116. peer->input
  117. )).done([=] {
  118. const auto data = _blockRequests.take(peer);
  119. peer->setIsBlocked(false);
  120. if (_slice) {
  121. auto &list = _slice->list;
  122. for (auto i = list.begin(); i != list.end(); ++i) {
  123. if (i->id == peer->id) {
  124. list.erase(i);
  125. break;
  126. }
  127. }
  128. if (_slice->total > list.size()) {
  129. --_slice->total;
  130. }
  131. _changes.fire_copy(*_slice);
  132. }
  133. if (data) {
  134. for (const auto &callback : data->callbacks) {
  135. callback(true);
  136. }
  137. }
  138. }).fail([=] {
  139. if (const auto data = _blockRequests.take(peer)) {
  140. for (const auto &callback : data->callbacks) {
  141. callback(false);
  142. }
  143. }
  144. }).send();
  145. const auto i = _blockRequests.emplace(peer, Request{
  146. .requestId = requestId,
  147. .blocking = false,
  148. }).first;
  149. if (done) {
  150. i->second.callbacks.push_back(std::move(done));
  151. }
  152. }
  153. bool BlockedPeers::blockAlreadySent(
  154. not_null<PeerData*> peer,
  155. bool blocking,
  156. Fn<void(bool success)> done) {
  157. const auto i = _blockRequests.find(peer);
  158. if (i == end(_blockRequests)) {
  159. return false;
  160. } else if (i->second.blocking == blocking) {
  161. if (done) {
  162. i->second.callbacks.push_back(std::move(done));
  163. }
  164. return true;
  165. }
  166. const auto callbacks = base::take(i->second.callbacks);
  167. _blockRequests.erase(i);
  168. for (const auto &callback : callbacks) {
  169. callback(false);
  170. }
  171. return false;
  172. }
  173. void BlockedPeers::reload() {
  174. if (_requestId) {
  175. return;
  176. }
  177. request(0, [=](Slice &&slice) {
  178. if (!_slice || *_slice != slice) {
  179. _slice = slice;
  180. _changes.fire(std::move(slice));
  181. }
  182. });
  183. }
  184. auto BlockedPeers::slice() -> rpl::producer<BlockedPeers::Slice> {
  185. if (!_slice) {
  186. reload();
  187. }
  188. return _slice
  189. ? _changes.events_starting_with_copy(*_slice)
  190. : (_changes.events() | rpl::type_erased());
  191. }
  192. void BlockedPeers::request(int offset, Fn<void(BlockedPeers::Slice)> done) {
  193. if (_requestId) {
  194. return;
  195. }
  196. _requestId = _api.request(MTPcontacts_GetBlocked(
  197. MTP_flags(0),
  198. MTP_int(offset),
  199. MTP_int(offset ? kBlockedPerPage : kBlockedFirstSlice)
  200. )).done([=](const MTPcontacts_Blocked &result) {
  201. _requestId = 0;
  202. done(TLToSlice(result, _session->data()));
  203. }).fail([=] {
  204. _requestId = 0;
  205. }).send();
  206. }
  207. } // namespace Api