data_changes.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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 "data/data_changes.h"
  8. #include "main/main_session.h"
  9. namespace Data {
  10. template <typename DataType, typename UpdateType>
  11. void Changes::Manager<DataType, UpdateType>::updated(
  12. not_null<DataType*> data,
  13. Flags flags,
  14. bool dropScheduled) {
  15. sendRealtimeNotifications(data, flags);
  16. if (dropScheduled) {
  17. const auto i = _updates.find(data);
  18. if (i != _updates.end()) {
  19. flags |= i->second;
  20. _updates.erase(i);
  21. }
  22. _stream.fire({ data, flags });
  23. } else {
  24. _updates[data] |= flags;
  25. }
  26. }
  27. template <typename DataType, typename UpdateType>
  28. void Changes::Manager<DataType, UpdateType>::sendRealtimeNotifications(
  29. not_null<DataType*> data,
  30. Flags flags) {
  31. for (auto i = 0; i != kCount; ++i) {
  32. const auto flag = static_cast<Flag>(1U << i);
  33. if (flags & flag) {
  34. _realtimeStreams[i].fire({ data, flags });
  35. }
  36. }
  37. }
  38. template <typename DataType, typename UpdateType>
  39. rpl::producer<UpdateType> Changes::Manager<DataType, UpdateType>::updates(
  40. Flags flags) const {
  41. return _stream.events(
  42. ) | rpl::filter([=](const UpdateType &update) {
  43. return (update.flags & flags);
  44. });
  45. }
  46. template <typename DataType, typename UpdateType>
  47. rpl::producer<UpdateType> Changes::Manager<DataType, UpdateType>::updates(
  48. not_null<DataType*> data,
  49. Flags flags) const {
  50. return _stream.events(
  51. ) | rpl::filter([=](const UpdateType &update) {
  52. const auto &[updateData, updateFlags] = update;
  53. return (updateData == data) && (updateFlags & flags);
  54. });
  55. }
  56. template <typename DataType, typename UpdateType>
  57. auto Changes::Manager<DataType, UpdateType>::realtimeUpdates(Flag flag) const
  58. -> rpl::producer<UpdateType> {
  59. return _realtimeStreams[details::CountBit(flag)].events();
  60. }
  61. template <typename DataType, typename UpdateType>
  62. rpl::producer<UpdateType> Changes::Manager<DataType, UpdateType>::flagsValue(
  63. not_null<DataType*> data,
  64. Flags flags) const {
  65. return rpl::single(
  66. UpdateType{ data, flags }
  67. ) | rpl::then(updates(data, flags));
  68. }
  69. template <typename DataType, typename UpdateType>
  70. void Changes::Manager<DataType, UpdateType>::drop(not_null<DataType*> data) {
  71. _updates.remove(data);
  72. }
  73. template <typename DataType, typename UpdateType>
  74. void Changes::Manager<DataType, UpdateType>::sendNotifications() {
  75. for (const auto &[data, flags] : base::take(_updates)) {
  76. _stream.fire({ data, flags });
  77. }
  78. }
  79. Changes::Changes(not_null<Main::Session*> session) : _session(session) {
  80. }
  81. Main::Session &Changes::session() const {
  82. return *_session;
  83. }
  84. void Changes::nameUpdated(
  85. not_null<PeerData*> peer,
  86. base::flat_set<QChar> oldFirstLetters) {
  87. _nameStream.fire({ peer, std::move(oldFirstLetters) });
  88. }
  89. rpl::producer<NameUpdate> Changes::realtimeNameUpdates() const {
  90. return _nameStream.events();
  91. }
  92. rpl::producer<NameUpdate> Changes::realtimeNameUpdates(
  93. not_null<PeerData*> peer) const {
  94. return _nameStream.events() | rpl::filter([=](const NameUpdate &update) {
  95. return (update.peer == peer);
  96. });
  97. }
  98. void Changes::peerUpdated(not_null<PeerData*> peer, PeerUpdate::Flags flags) {
  99. _peerChanges.updated(peer, flags);
  100. scheduleNotifications();
  101. }
  102. rpl::producer<PeerUpdate> Changes::peerUpdates(
  103. PeerUpdate::Flags flags) const {
  104. return _peerChanges.updates(flags);
  105. }
  106. rpl::producer<PeerUpdate> Changes::peerUpdates(
  107. not_null<PeerData*> peer,
  108. PeerUpdate::Flags flags) const {
  109. return _peerChanges.updates(peer, flags);
  110. }
  111. rpl::producer<PeerUpdate> Changes::peerFlagsValue(
  112. not_null<PeerData*> peer,
  113. PeerUpdate::Flags flags) const {
  114. return _peerChanges.flagsValue(peer, flags);
  115. }
  116. rpl::producer<PeerUpdate> Changes::realtimePeerUpdates(
  117. PeerUpdate::Flag flag) const {
  118. return _peerChanges.realtimeUpdates(flag);
  119. }
  120. void Changes::historyUpdated(
  121. not_null<History*> history,
  122. HistoryUpdate::Flags flags) {
  123. _historyChanges.updated(history, flags);
  124. scheduleNotifications();
  125. }
  126. rpl::producer<HistoryUpdate> Changes::historyUpdates(
  127. HistoryUpdate::Flags flags) const {
  128. return _historyChanges.updates(flags);
  129. }
  130. rpl::producer<HistoryUpdate> Changes::historyUpdates(
  131. not_null<History*> history,
  132. HistoryUpdate::Flags flags) const {
  133. return _historyChanges.updates(history, flags);
  134. }
  135. rpl::producer<HistoryUpdate> Changes::historyFlagsValue(
  136. not_null<History*> history,
  137. HistoryUpdate::Flags flags) const {
  138. return _historyChanges.flagsValue(history, flags);
  139. }
  140. rpl::producer<HistoryUpdate> Changes::realtimeHistoryUpdates(
  141. HistoryUpdate::Flag flag) const {
  142. return _historyChanges.realtimeUpdates(flag);
  143. }
  144. void Changes::topicUpdated(
  145. not_null<ForumTopic*> topic,
  146. TopicUpdate::Flags flags) {
  147. const auto drop = (flags & TopicUpdate::Flag::Destroyed);
  148. _topicChanges.updated(topic, flags, drop);
  149. if (!drop) {
  150. scheduleNotifications();
  151. }
  152. }
  153. rpl::producer<TopicUpdate> Changes::topicUpdates(
  154. TopicUpdate::Flags flags) const {
  155. return _topicChanges.updates(flags);
  156. }
  157. rpl::producer<TopicUpdate> Changes::topicUpdates(
  158. not_null<ForumTopic*> topic,
  159. TopicUpdate::Flags flags) const {
  160. return _topicChanges.updates(topic, flags);
  161. }
  162. rpl::producer<TopicUpdate> Changes::topicFlagsValue(
  163. not_null<ForumTopic*> topic,
  164. TopicUpdate::Flags flags) const {
  165. return _topicChanges.flagsValue(topic, flags);
  166. }
  167. rpl::producer<TopicUpdate> Changes::realtimeTopicUpdates(
  168. TopicUpdate::Flag flag) const {
  169. return _topicChanges.realtimeUpdates(flag);
  170. }
  171. void Changes::topicRemoved(not_null<ForumTopic*> topic) {
  172. _topicChanges.drop(topic);
  173. }
  174. void Changes::messageUpdated(
  175. not_null<HistoryItem*> item,
  176. MessageUpdate::Flags flags) {
  177. const auto drop = (flags & MessageUpdate::Flag::Destroyed);
  178. _messageChanges.updated(item, flags, drop);
  179. if (!drop) {
  180. scheduleNotifications();
  181. }
  182. }
  183. rpl::producer<MessageUpdate> Changes::messageUpdates(
  184. MessageUpdate::Flags flags) const {
  185. return _messageChanges.updates(flags);
  186. }
  187. rpl::producer<MessageUpdate> Changes::messageUpdates(
  188. not_null<HistoryItem*> item,
  189. MessageUpdate::Flags flags) const {
  190. return _messageChanges.updates(item, flags);
  191. }
  192. rpl::producer<MessageUpdate> Changes::messageFlagsValue(
  193. not_null<HistoryItem*> item,
  194. MessageUpdate::Flags flags) const {
  195. return _messageChanges.flagsValue(item, flags);
  196. }
  197. rpl::producer<MessageUpdate> Changes::realtimeMessageUpdates(
  198. MessageUpdate::Flag flag) const {
  199. return _messageChanges.realtimeUpdates(flag);
  200. }
  201. void Changes::entryUpdated(
  202. not_null<Dialogs::Entry*> entry,
  203. EntryUpdate::Flags flags) {
  204. const auto drop = (flags & EntryUpdate::Flag::Destroyed);
  205. _entryChanges.updated(entry, flags, drop);
  206. if (!drop) {
  207. scheduleNotifications();
  208. }
  209. }
  210. rpl::producer<EntryUpdate> Changes::entryUpdates(
  211. EntryUpdate::Flags flags) const {
  212. return _entryChanges.updates(flags);
  213. }
  214. rpl::producer<EntryUpdate> Changes::entryUpdates(
  215. not_null<Dialogs::Entry*> entry,
  216. EntryUpdate::Flags flags) const {
  217. return _entryChanges.updates(entry, flags);
  218. }
  219. rpl::producer<EntryUpdate> Changes::entryFlagsValue(
  220. not_null<Dialogs::Entry*> entry,
  221. EntryUpdate::Flags flags) const {
  222. return _entryChanges.flagsValue(entry, flags);
  223. }
  224. rpl::producer<EntryUpdate> Changes::realtimeEntryUpdates(
  225. EntryUpdate::Flag flag) const {
  226. return _entryChanges.realtimeUpdates(flag);
  227. }
  228. void Changes::entryRemoved(not_null<Dialogs::Entry*> entry) {
  229. _entryChanges.drop(entry);
  230. }
  231. void Changes::storyUpdated(
  232. not_null<Story*> story,
  233. StoryUpdate::Flags flags) {
  234. const auto drop = (flags & StoryUpdate::Flag::Destroyed);
  235. _storyChanges.updated(story, flags, drop);
  236. if (!drop) {
  237. scheduleNotifications();
  238. }
  239. }
  240. rpl::producer<StoryUpdate> Changes::storyUpdates(
  241. StoryUpdate::Flags flags) const {
  242. return _storyChanges.updates(flags);
  243. }
  244. rpl::producer<StoryUpdate> Changes::storyUpdates(
  245. not_null<Story*> story,
  246. StoryUpdate::Flags flags) const {
  247. return _storyChanges.updates(story, flags);
  248. }
  249. rpl::producer<StoryUpdate> Changes::storyFlagsValue(
  250. not_null<Story*> story,
  251. StoryUpdate::Flags flags) const {
  252. return _storyChanges.flagsValue(story, flags);
  253. }
  254. rpl::producer<StoryUpdate> Changes::realtimeStoryUpdates(
  255. StoryUpdate::Flag flag) const {
  256. return _storyChanges.realtimeUpdates(flag);
  257. }
  258. void Changes::scheduleNotifications() {
  259. if (!_notify) {
  260. _notify = true;
  261. crl::on_main(&session(), [=] {
  262. sendNotifications();
  263. });
  264. }
  265. }
  266. void Changes::sendNotifications() {
  267. if (!_notify) {
  268. return;
  269. }
  270. _notify = false;
  271. _peerChanges.sendNotifications();
  272. _historyChanges.sendNotifications();
  273. _messageChanges.sendNotifications();
  274. _entryChanges.sendNotifications();
  275. _topicChanges.sendNotifications();
  276. _storyChanges.sendNotifications();
  277. }
  278. } // namespace Data