234 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
	
		
			6.2 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 "base/timer.h"
 | 
						|
 | 
						|
class History;
 | 
						|
class HistoryItem;
 | 
						|
 | 
						|
namespace Main {
 | 
						|
class Session;
 | 
						|
} // namespace Main
 | 
						|
 | 
						|
namespace MTP {
 | 
						|
class Error;
 | 
						|
struct Response;
 | 
						|
} // namespace MTP
 | 
						|
 | 
						|
namespace Data {
 | 
						|
 | 
						|
class Session;
 | 
						|
class Folder;
 | 
						|
 | 
						|
[[nodiscard]] MTPInputReplyTo ReplyToForMTP(
 | 
						|
	not_null<Session*> owner,
 | 
						|
	FullReplyTo replyTo);
 | 
						|
 | 
						|
class Histories final {
 | 
						|
public:
 | 
						|
	enum class RequestType : uchar {
 | 
						|
		None,
 | 
						|
		History,
 | 
						|
		ReadInbox,
 | 
						|
		Delete,
 | 
						|
		Send,
 | 
						|
	};
 | 
						|
 | 
						|
	explicit Histories(not_null<Session*> owner);
 | 
						|
 | 
						|
	[[nodiscard]] Session &owner() const;
 | 
						|
	[[nodiscard]] Main::Session &session() const;
 | 
						|
 | 
						|
	[[nodiscard]] History *find(PeerId peerId);
 | 
						|
	[[nodiscard]] not_null<History*> findOrCreate(PeerId peerId);
 | 
						|
 | 
						|
	void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
 | 
						|
 | 
						|
	void unloadAll();
 | 
						|
	void clearAll();
 | 
						|
 | 
						|
	void readInbox(not_null<History*> history);
 | 
						|
	void readInboxTill(not_null<HistoryItem*> item);
 | 
						|
	void readInboxTill(not_null<History*> history, MsgId tillId);
 | 
						|
	void readInboxOnNewMessage(not_null<HistoryItem*> item);
 | 
						|
	void readClientSideMessage(not_null<HistoryItem*> item);
 | 
						|
	void sendPendingReadInbox(not_null<History*> history);
 | 
						|
 | 
						|
	void requestDialogEntry(not_null<Data::Folder*> folder);
 | 
						|
	void requestDialogEntry(
 | 
						|
		not_null<History*> history,
 | 
						|
		Fn<void()> callback = nullptr);
 | 
						|
	void dialogEntryApplied(not_null<History*> history);
 | 
						|
	void changeDialogUnreadMark(not_null<History*> history, bool unread);
 | 
						|
	void requestFakeChatListMessage(not_null<History*> history);
 | 
						|
 | 
						|
	void requestGroupAround(not_null<HistoryItem*> item);
 | 
						|
 | 
						|
	void deleteMessages(
 | 
						|
		not_null<History*> history,
 | 
						|
		const QVector<MTPint> &ids,
 | 
						|
		bool revoke);
 | 
						|
	void deleteAllMessages(
 | 
						|
		not_null<History*> history,
 | 
						|
		MsgId deleteTillId,
 | 
						|
		bool justClear,
 | 
						|
		bool revoke);
 | 
						|
 | 
						|
	void deleteMessagesByDates(
 | 
						|
		not_null<History*> history,
 | 
						|
		QDate firstDayToDelete,
 | 
						|
		QDate lastDayToDelete,
 | 
						|
		bool revoke);
 | 
						|
	void deleteMessagesByDates(
 | 
						|
		not_null<History*> history,
 | 
						|
		TimeId minDate,
 | 
						|
		TimeId maxDate,
 | 
						|
		bool revoke);
 | 
						|
 | 
						|
	void deleteMessages(const MessageIdsList &ids, bool revoke);
 | 
						|
 | 
						|
	int sendRequest(
 | 
						|
		not_null<History*> history,
 | 
						|
		RequestType type,
 | 
						|
		Fn<mtpRequestId(Fn<void()> finish)> generator);
 | 
						|
	void cancelRequest(int id);
 | 
						|
 | 
						|
	using PreparedMessage = std::variant<
 | 
						|
		MTPmessages_SendMessage,
 | 
						|
		MTPmessages_SendMedia,
 | 
						|
		MTPmessages_SendInlineBotResult,
 | 
						|
		MTPmessages_SendMultiMedia>;
 | 
						|
	int sendPreparedMessage(
 | 
						|
		not_null<History*> history,
 | 
						|
		FullReplyTo replyTo,
 | 
						|
		uint64 randomId,
 | 
						|
		Fn<PreparedMessage(not_null<Session*>, FullReplyTo)> message,
 | 
						|
		Fn<void(const MTPUpdates&, const MTP::Response&)> done,
 | 
						|
		Fn<void(const MTP::Error&, const MTP::Response&)> fail);
 | 
						|
 | 
						|
	struct ReplyToPlaceholder {
 | 
						|
	};
 | 
						|
	template <typename RequestType, typename ...Args>
 | 
						|
	static auto PrepareMessage(const Args &...args)
 | 
						|
	-> Fn<Histories::PreparedMessage(not_null<Session*>, FullReplyTo)> {
 | 
						|
		return [=](not_null<Session*> owner, FullReplyTo replyTo)
 | 
						|
		-> RequestType {
 | 
						|
			return { ReplaceReplyIds(owner, args, replyTo)... };
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	void checkTopicCreated(FullMsgId rootId, MsgId realRoot);
 | 
						|
	[[nodiscard]] MsgId convertTopicReplyToId(
 | 
						|
		not_null<History*> history,
 | 
						|
		MsgId replyToId) const;
 | 
						|
 | 
						|
private:
 | 
						|
	struct PostponedHistoryRequest {
 | 
						|
		Fn<mtpRequestId(Fn<void()> finish)> generator;
 | 
						|
	};
 | 
						|
	struct SentRequest {
 | 
						|
		Fn<mtpRequestId(Fn<void()> finish)> generator;
 | 
						|
		mtpRequestId id = 0;
 | 
						|
		RequestType type = RequestType::None;
 | 
						|
	};
 | 
						|
	struct State {
 | 
						|
		base::flat_map<int, PostponedHistoryRequest> postponed;
 | 
						|
		base::flat_map<int, SentRequest> sent;
 | 
						|
		MsgId willReadTill = 0;
 | 
						|
		MsgId sentReadTill = 0;
 | 
						|
		crl::time willReadWhen = 0;
 | 
						|
		bool sentReadDone = false;
 | 
						|
		bool postponedRequestEntry = false;
 | 
						|
	};
 | 
						|
	struct ChatListGroupRequest {
 | 
						|
		MsgId aroundId = 0;
 | 
						|
		mtpRequestId requestId = 0;
 | 
						|
	};
 | 
						|
	struct DelayedByTopicMessage {
 | 
						|
		uint64 randomId = 0;
 | 
						|
		MsgId replyTo = 0;
 | 
						|
		Fn<PreparedMessage(not_null<Session*>, FullReplyTo)> message;
 | 
						|
		Fn<void(const MTPUpdates&, const MTP::Response&)> done;
 | 
						|
		Fn<void(const MTP::Error&, const MTP::Response&)> fail;
 | 
						|
		int requestId = 0;
 | 
						|
	};
 | 
						|
	struct GroupRequestKey {
 | 
						|
		not_null<History*> history;
 | 
						|
		MsgId rootId = 0;
 | 
						|
 | 
						|
		friend inline auto operator<=>(
 | 
						|
			GroupRequestKey,
 | 
						|
			GroupRequestKey) = default;
 | 
						|
	};
 | 
						|
 | 
						|
	template <typename Arg>
 | 
						|
	static auto ReplaceReplyIds(
 | 
						|
			not_null<Session*> owner,
 | 
						|
			Arg arg,
 | 
						|
			FullReplyTo replyTo) {
 | 
						|
		if constexpr (std::is_same_v<Arg, ReplyToPlaceholder>) {
 | 
						|
			return ReplyToForMTP(owner, replyTo);
 | 
						|
		} else {
 | 
						|
			return arg;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	void readInboxTill(not_null<History*> history, MsgId tillId, bool force);
 | 
						|
	void sendReadRequests();
 | 
						|
	void sendReadRequest(not_null<History*> history, State &state);
 | 
						|
	[[nodiscard]] State *lookup(not_null<History*> history);
 | 
						|
	void checkEmptyState(not_null<History*> history);
 | 
						|
	void checkPostponed(not_null<History*> history, int id);
 | 
						|
	void finishSentRequest(
 | 
						|
		not_null<History*> history,
 | 
						|
		not_null<State*> state,
 | 
						|
		int id);
 | 
						|
	[[nodiscard]] bool postponeHistoryRequest(const State &state) const;
 | 
						|
	[[nodiscard]] bool postponeEntryRequest(const State &state) const;
 | 
						|
	void postponeRequestDialogEntries();
 | 
						|
 | 
						|
	void sendDialogRequests();
 | 
						|
 | 
						|
	[[nodiscard]] bool isCreatingTopic(
 | 
						|
		not_null<History*> history,
 | 
						|
		MsgId rootId) const;
 | 
						|
	void sendCreateTopicRequest(not_null<History*> history, MsgId rootId);
 | 
						|
	void cancelDelayedByTopicRequest(int id);
 | 
						|
 | 
						|
	const not_null<Session*> _owner;
 | 
						|
 | 
						|
	std::unordered_map<PeerId, std::unique_ptr<History>> _map;
 | 
						|
	base::flat_map<not_null<History*>, State> _states;
 | 
						|
	base::flat_map<int, not_null<History*>> _historyByRequest;
 | 
						|
	int _requestAutoincrement = 0;
 | 
						|
	base::Timer _readRequestsTimer;
 | 
						|
 | 
						|
	base::flat_set<not_null<Data::Folder*>> _dialogFolderRequests;
 | 
						|
	base::flat_map<
 | 
						|
		not_null<History*>,
 | 
						|
		std::vector<Fn<void()>>> _dialogRequests;
 | 
						|
	base::flat_map<
 | 
						|
		not_null<History*>,
 | 
						|
		std::vector<Fn<void()>>> _dialogRequestsPending;
 | 
						|
 | 
						|
	base::flat_set<not_null<History*>> _fakeChatListRequests;
 | 
						|
 | 
						|
	base::flat_map<
 | 
						|
		GroupRequestKey,
 | 
						|
		ChatListGroupRequest> _chatListGroupRequests;
 | 
						|
 | 
						|
	base::flat_map<
 | 
						|
		FullMsgId,
 | 
						|
		std::vector<DelayedByTopicMessage>> _creatingTopics;
 | 
						|
	base::flat_map<FullMsgId, MsgId> _createdTopicIds;
 | 
						|
	base::flat_set<mtpRequestId> _creatingTopicRequests;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
} // namespace Data
 |