1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "data/data_abstract_sparse_ids.h"
11 #include "data/data_messages.h"
12 
13 namespace Storage {
14 struct SparseIdsListResult;
15 struct SparseIdsSliceUpdate;
16 } // namespace Storage
17 
18 class SparseIdsSlice final : public AbstractSparseIds<base::flat_set<MsgId>> {
19 public:
20 	using Key = MsgId;
21 	using AbstractSparseIds<base::flat_set<MsgId>>::AbstractSparseIds;
22 
23 };
24 
25 using SparseUnsortedIdsSlice = AbstractSparseIds<std::vector<MsgId>>;
26 
27 class SparseIdsMergedSlice {
28 public:
29 	using UniversalMsgId = MsgId;
30 	struct Key {
31 		Key(
32 			PeerId peerId,
33 			PeerId migratedPeerId,
34 			UniversalMsgId universalId,
35 			bool scheduled = false)
peerIdKey36 		: peerId(peerId)
37 		, scheduled(scheduled)
38 		, migratedPeerId(scheduled ? 0 : migratedPeerId)
39 		, universalId(universalId) {
40 		}
41 
42 		bool operator==(const Key &other) const {
43 			return (peerId == other.peerId)
44 				&& (migratedPeerId == other.migratedPeerId)
45 				&& (universalId == other.universalId);
46 		}
47 		bool operator!=(const Key &other) const {
48 			return !(*this == other);
49 		}
50 
51 		PeerId peerId = 0;
52 		bool scheduled = false;
53 		PeerId migratedPeerId = 0;
54 		UniversalMsgId universalId = 0;
55 
56 	};
57 
58 	SparseIdsMergedSlice(Key key);
59 	SparseIdsMergedSlice(
60 		Key key,
61 		SparseIdsSlice part,
62 		std::optional<SparseIdsSlice> migrated);
63 	SparseIdsMergedSlice(
64 		Key key,
65 		SparseUnsortedIdsSlice scheduled);
66 
67 	std::optional<int> fullCount() const;
68 	std::optional<int> skippedBefore() const;
69 	std::optional<int> skippedAfter() const;
70 	std::optional<int> indexOf(FullMsgId fullId) const;
71 	int size() const;
72 	FullMsgId operator[](int index) const;
73 	std::optional<int> distance(const Key &a, const Key &b) const;
74 	std::optional<FullMsgId> nearest(UniversalMsgId id) const;
75 
76 	using SimpleViewerFunction = rpl::producer<SparseIdsSlice>(
77 		PeerId peerId,
78 		SparseIdsSlice::Key simpleKey,
79 		int limitBefore,
80 		int limitAfter);
81 	static rpl::producer<SparseIdsMergedSlice> CreateViewer(
82 		SparseIdsMergedSlice::Key key,
83 		int limitBefore,
84 		int limitAfter,
85 		Fn<SimpleViewerFunction> simpleViewer);
86 
87 private:
PartKey(const Key & key)88 	static SparseIdsSlice::Key PartKey(const Key &key) {
89 		return (key.universalId < 0) ? 1 : key.universalId;
90 	}
MigratedKey(const Key & key)91 	static SparseIdsSlice::Key MigratedKey(const Key &key) {
92 		return (key.universalId < 0)
93 			? (ServerMaxMsgId + key.universalId)
94 			: (key.universalId > 0) ? (ServerMaxMsgId - 1) : 0;
95 	}
MigratedSlice(const Key & key)96 	static std::optional<SparseIdsSlice> MigratedSlice(const Key &key) {
97 		return key.migratedPeerId
98 			? base::make_optional(SparseIdsSlice())
99 			: std::nullopt;
100 	}
101 
IsFromSlice(PeerId peerId,FullMsgId fullId)102 	static bool IsFromSlice(PeerId peerId, FullMsgId fullId) {
103 		return peerIsChannel(peerId)
104 			? (peerId == peerFromChannel(fullId.channel))
105 			: !fullId.channel;
106 	}
ComputeId(PeerId peerId,MsgId msgId)107 	static FullMsgId ComputeId(PeerId peerId, MsgId msgId) {
108 		return FullMsgId(peerToChannel(peerId), msgId);
109 	}
ComputeId(const Key & key)110 	static FullMsgId ComputeId(const Key &key) {
111 		return (key.universalId >= 0)
112 			? ComputeId(key.peerId, key.universalId)
113 			: ComputeId(key.migratedPeerId, ServerMaxMsgId + key.universalId);
114 	}
Add(const std::optional<int> & a,const std::optional<int> & b)115 	static std::optional<int> Add(
116 			const std::optional<int> &a,
117 			const std::optional<int> &b) {
118 		return (a && b) ? base::make_optional(*a + *b) : std::nullopt;
119 	}
120 
isFromPart(FullMsgId fullId)121 	bool isFromPart(FullMsgId fullId) const {
122 		return IsFromSlice(_key.peerId, fullId);
123 	}
isFromMigrated(FullMsgId fullId)124 	bool isFromMigrated(FullMsgId fullId) const {
125 		return _migrated
126 			? IsFromSlice(_key.migratedPeerId, fullId)
127 			: false;
128 	}
migratedSize()129 	int migratedSize() const {
130 		return isolatedInPart() ? 0 : _migrated->size();
131 	}
isolatedInPart()132 	bool isolatedInPart() const {
133 		return IsServerMsgId(_key.universalId)
134 			&& (!_migrated || _part.skippedBefore() != 0);
135 	}
isolatedInMigrated()136 	bool isolatedInMigrated() const {
137 		return IsServerMsgId(ServerMaxMsgId + _key.universalId)
138 			&& (_migrated->skippedAfter() != 0);
139 	}
140 
141 	Key _key;
142 	SparseIdsSlice _part;
143 	std::optional<SparseIdsSlice> _migrated;
144 	std::optional<SparseUnsortedIdsSlice> _scheduled;
145 
146 };
147 
148 class SparseIdsSliceBuilder {
149 public:
150 	using Key = SparseIdsSlice::Key;
151 
152 	SparseIdsSliceBuilder(Key key, int limitBefore, int limitAfter);
153 
154 	bool applyInitial(const Storage::SparseIdsListResult &result);
155 	bool applyUpdate(const Storage::SparseIdsSliceUpdate &update);
156 	bool removeOne(MsgId messageId);
157 	bool removeAll();
158 	bool invalidateBottom();
159 
160 	void checkInsufficient();
161 	struct AroundData {
162 		MsgId aroundId = 0;
163 		Data::LoadDirection direction = Data::LoadDirection::Around;
164 
165 		inline bool operator<(const AroundData &other) const {
166 			return (aroundId < other.aroundId)
167 				|| ((aroundId == other.aroundId)
168 					&& (direction < other.direction));
169 		}
170 	};
insufficientAround()171 	auto insufficientAround() const {
172 		return _insufficientAround.events();
173 	}
174 
175 	SparseIdsSlice snapshot() const;
176 
177 private:
178 	enum class RequestDirection {
179 		Before,
180 		After,
181 	};
182 	void requestMessages(RequestDirection direction);
183 	void requestMessagesCount();
184 	void fillSkippedAndSliceToLimits();
185 	void sliceToLimits();
186 
187 	void mergeSliceData(
188 		std::optional<int> count,
189 		const base::flat_set<MsgId> &messageIds,
190 		std::optional<int> skippedBefore = std::nullopt,
191 		std::optional<int> skippedAfter = std::nullopt);
192 
193 	Key _key;
194 	base::flat_set<MsgId> _ids;
195 	std::optional<int> _fullCount;
196 	std::optional<int> _skippedBefore;
197 	std::optional<int> _skippedAfter;
198 	int _limitBefore = 0;
199 	int _limitAfter = 0;
200 
201 	rpl::event_stream<AroundData> _insufficientAround;
202 
203 };
204