266 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 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
 | |
| */
 | |
| #pragma once
 | |
| 
 | |
| #include <rpl/event_stream.h>
 | |
| #include "storage/storage_facade.h"
 | |
| #include "storage/storage_sparse_ids_list.h"
 | |
| 
 | |
| namespace Storage {
 | |
| 
 | |
| // Allow forward declarations.
 | |
| enum class SharedMediaType : signed char {
 | |
| 	Photo,
 | |
| 	Video,
 | |
| 	PhotoVideo,
 | |
| 	MusicFile,
 | |
| 	File,
 | |
| 	VoiceFile,
 | |
| 	Link,
 | |
| 	ChatPhoto,
 | |
| 	RoundVoiceFile,
 | |
| 	GIF,
 | |
| 	RoundFile,
 | |
| 	Pinned,
 | |
| 
 | |
| 	kCount,
 | |
| };
 | |
| constexpr auto kSharedMediaTypeCount = static_cast<int>(SharedMediaType::kCount);
 | |
| constexpr bool IsValidSharedMediaType(SharedMediaType type) {
 | |
| 	return (static_cast<int>(type) >= 0)
 | |
| 		&& (static_cast<int>(type) < kSharedMediaTypeCount);
 | |
| }
 | |
| 
 | |
| using SharedMediaTypesMask = base::enum_mask<SharedMediaType>;
 | |
| 
 | |
| struct SharedMediaAddNew {
 | |
| 	SharedMediaAddNew(
 | |
| 		PeerId peerId,
 | |
| 		MsgId topicRootId,
 | |
| 		SharedMediaTypesMask types,
 | |
| 		MsgId messageId)
 | |
| 	: peerId(peerId)
 | |
| 	, topicRootId(topicRootId)
 | |
| 	, messageId(messageId)
 | |
| 	, types(types) {
 | |
| 	}
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 	MsgId topicRootId = 0;
 | |
| 	MsgId messageId = 0;
 | |
| 	SharedMediaTypesMask types;
 | |
| 
 | |
| };
 | |
| 
 | |
| struct SharedMediaAddExisting {
 | |
| 	SharedMediaAddExisting(
 | |
| 		PeerId peerId,
 | |
| 		MsgId topicRootId,
 | |
| 		SharedMediaTypesMask types,
 | |
| 		MsgId messageId,
 | |
| 		MsgRange noSkipRange)
 | |
| 	: peerId(peerId)
 | |
| 	, topicRootId(topicRootId)
 | |
| 	, messageId(messageId)
 | |
| 	, noSkipRange(noSkipRange)
 | |
| 	, types(types) {
 | |
| 	}
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 	MsgId topicRootId = 0;
 | |
| 	MsgId messageId = 0;
 | |
| 	MsgRange noSkipRange;
 | |
| 	SharedMediaTypesMask types;
 | |
| 
 | |
| };
 | |
| 
 | |
| struct SharedMediaAddSlice {
 | |
| 	SharedMediaAddSlice(
 | |
| 		PeerId peerId,
 | |
| 		MsgId topicRootId,
 | |
| 		SharedMediaType type,
 | |
| 		std::vector<MsgId> &&messageIds,
 | |
| 		MsgRange noSkipRange,
 | |
| 		std::optional<int> count = std::nullopt)
 | |
| 	: peerId(peerId)
 | |
| 	, topicRootId(topicRootId)
 | |
| 	, messageIds(std::move(messageIds))
 | |
| 	, noSkipRange(noSkipRange)
 | |
| 	, type(type)
 | |
| 	, count(count) {
 | |
| 	}
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 	MsgId topicRootId = 0;
 | |
| 	std::vector<MsgId> messageIds;
 | |
| 	MsgRange noSkipRange;
 | |
| 	SharedMediaType type = SharedMediaType::kCount;
 | |
| 	std::optional<int> count;
 | |
| 
 | |
| };
 | |
| 
 | |
| struct SharedMediaRemoveOne {
 | |
| 	SharedMediaRemoveOne(
 | |
| 		PeerId peerId,
 | |
| 		SharedMediaTypesMask types,
 | |
| 		MsgId messageId)
 | |
| 	: peerId(peerId)
 | |
| 	, messageId(messageId)
 | |
| 	, types(types) {
 | |
| 	}
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 	MsgId messageId = 0;
 | |
| 	SharedMediaTypesMask types;
 | |
| 
 | |
| };
 | |
| 
 | |
| struct SharedMediaRemoveAll {
 | |
| 	SharedMediaRemoveAll(
 | |
| 		PeerId peerId,
 | |
| 		SharedMediaTypesMask types = SharedMediaTypesMask::All())
 | |
| 	: peerId(peerId)
 | |
| 	, types(types) {
 | |
| 	}
 | |
| 	SharedMediaRemoveAll(
 | |
| 		PeerId peerId,
 | |
| 		MsgId topicRootId,
 | |
| 		SharedMediaTypesMask types = SharedMediaTypesMask::All())
 | |
| 	: peerId(peerId)
 | |
| 	, topicRootId(topicRootId)
 | |
| 	, types(types) {
 | |
| 	}
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 	MsgId topicRootId = 0;
 | |
| 	SharedMediaTypesMask types;
 | |
| 
 | |
| };
 | |
| 
 | |
| struct SharedMediaInvalidateBottom {
 | |
| 	SharedMediaInvalidateBottom(PeerId peerId) : peerId(peerId) {
 | |
| 	}
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 
 | |
| };
 | |
| 
 | |
| struct SharedMediaKey {
 | |
| 	SharedMediaKey(
 | |
| 		PeerId peerId,
 | |
| 		MsgId topicRootId,
 | |
| 		SharedMediaType type,
 | |
| 		MsgId messageId)
 | |
| 	: peerId(peerId)
 | |
| 	, topicRootId(topicRootId)
 | |
| 	, type(type)
 | |
| 	, messageId(messageId) {
 | |
| 	}
 | |
| 
 | |
| 	friend inline constexpr auto operator<=>(
 | |
| 		const SharedMediaKey &,
 | |
| 		const SharedMediaKey &) = default;
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 	MsgId topicRootId = 0;
 | |
| 	SharedMediaType type = SharedMediaType::kCount;
 | |
| 	MsgId messageId = 0;
 | |
| 
 | |
| };
 | |
| 
 | |
| struct SharedMediaQuery {
 | |
| 	SharedMediaQuery(
 | |
| 		SharedMediaKey key,
 | |
| 		int limitBefore,
 | |
| 		int limitAfter)
 | |
| 	: key(key)
 | |
| 	, limitBefore(limitBefore)
 | |
| 	, limitAfter(limitAfter) {
 | |
| 	}
 | |
| 
 | |
| 	SharedMediaKey key;
 | |
| 	int limitBefore = 0;
 | |
| 	int limitAfter = 0;
 | |
| 
 | |
| };
 | |
| 
 | |
| using SharedMediaResult = SparseIdsListResult;
 | |
| 
 | |
| struct SharedMediaSliceUpdate {
 | |
| 	SharedMediaSliceUpdate(
 | |
| 		PeerId peerId,
 | |
| 		MsgId topicRootId,
 | |
| 		SharedMediaType type,
 | |
| 		const SparseIdsSliceUpdate &data)
 | |
| 	: peerId(peerId)
 | |
| 	, topicRootId(topicRootId)
 | |
| 	, type(type)
 | |
| 	, data(data) {
 | |
| 	}
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 	MsgId topicRootId = 0;
 | |
| 	SharedMediaType type = SharedMediaType::kCount;
 | |
| 	SparseIdsSliceUpdate data;
 | |
| };
 | |
| 
 | |
| struct SharedMediaUnloadThread {
 | |
| 	SharedMediaUnloadThread(
 | |
| 		PeerId peerId,
 | |
| 		MsgId topicRootId)
 | |
| 	: peerId(peerId)
 | |
| 	, topicRootId(topicRootId) {
 | |
| 	}
 | |
| 
 | |
| 	PeerId peerId = 0;
 | |
| 	MsgId topicRootId = 0;
 | |
| };
 | |
| 
 | |
| class SharedMedia {
 | |
| public:
 | |
| 	using Type = SharedMediaType;
 | |
| 
 | |
| 	void add(SharedMediaAddNew &&query);
 | |
| 	void add(SharedMediaAddExisting &&query);
 | |
| 	void add(SharedMediaAddSlice &&query);
 | |
| 	void remove(SharedMediaRemoveOne &&query);
 | |
| 	void remove(SharedMediaRemoveAll &&query);
 | |
| 	void invalidate(SharedMediaInvalidateBottom &&query);
 | |
| 	void unload(SharedMediaUnloadThread &&query);
 | |
| 
 | |
| 	rpl::producer<SharedMediaResult> query(SharedMediaQuery &&query) const;
 | |
| 	SharedMediaResult snapshot(const SharedMediaQuery &query) const;
 | |
| 	bool empty(const SharedMediaKey &key) const;
 | |
| 	rpl::producer<SharedMediaSliceUpdate> sliceUpdated() const;
 | |
| 	rpl::producer<SharedMediaRemoveOne> oneRemoved() const;
 | |
| 	rpl::producer<SharedMediaRemoveAll> allRemoved() const;
 | |
| 	rpl::producer<SharedMediaInvalidateBottom> bottomInvalidated() const;
 | |
| 
 | |
| private:
 | |
| 	struct Key {
 | |
| 		PeerId peerId = 0;
 | |
| 		MsgId topicRootId = 0;
 | |
| 
 | |
| 		friend inline constexpr auto operator<=>(Key, Key) = default;
 | |
| 	};
 | |
| 	using Lists = std::array<SparseIdsList, kSharedMediaTypeCount>;
 | |
| 
 | |
| 	std::map<Key, Lists>::iterator enforceLists(Key key);
 | |
| 
 | |
| 	std::map<Key, Lists> _lists;
 | |
| 
 | |
| 	rpl::event_stream<SharedMediaSliceUpdate> _sliceUpdated;
 | |
| 	rpl::event_stream<SharedMediaRemoveOne> _oneRemoved;
 | |
| 	rpl::event_stream<SharedMediaRemoveAll> _allRemoved;
 | |
| 	rpl::event_stream<SharedMediaInvalidateBottom> _bottomInvalidated;
 | |
| 
 | |
| 	rpl::lifetime _lifetime;
 | |
| 
 | |
| };
 | |
| 
 | |
| } // namespace Storage
 | 
