/* 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 "data/data_sparse_ids.h" #include "storage/storage_sparse_ids_list.h" #include "storage/storage_shared_media.h" #include "base/timer.h" #include "base/qt/qt_compare.h" namespace Main { class Session; } // namespace Main namespace Data { enum class LoadDirection : char; } // namespace Data namespace Api { struct SearchResult { std::vector messageIds; MsgRange noSkipRange; int fullCount = 0; }; using SearchRequest = MTPmessages_Search; using SearchRequestResult = MTPmessages_Messages; using HistoryResult = SearchResult; using HistoryRequest = MTPmessages_GetHistory; using HistoryRequestResult = MTPmessages_Messages; [[nodiscard]] std::optional PrepareSearchRequest( not_null peer, MsgId topicRootId, Storage::SharedMediaType type, const QString &query, MsgId messageId, Data::LoadDirection direction); [[nodiscard]] SearchResult ParseSearchResult( not_null peer, Storage::SharedMediaType type, MsgId messageId, Data::LoadDirection direction, const SearchRequestResult &data); [[nodiscard]] HistoryRequest PrepareHistoryRequest( not_null peer, MsgId messageId, Data::LoadDirection direction); [[nodiscard]] HistoryResult ParseHistoryResult( not_null peer, MsgId messageId, Data::LoadDirection direction, const HistoryRequestResult &data); class SearchController final { public: using IdsList = Storage::SparseIdsList; struct Query { using MediaType = Storage::SharedMediaType; PeerId peerId = 0; MsgId topicRootId = 0; PeerId migratedPeerId = 0; MediaType type = MediaType::kCount; QString query; // from_id, min_date, max_date friend inline std::strong_ordering operator<=>( const Query &a, const Query &b) noexcept = default; }; struct SavedState { Query query; IdsList peerList; std::optional migratedList; }; explicit SearchController(not_null session); void setQuery(const Query &query); bool hasInCache(const Query &query) const; Query query() const { Expects(_current != _cache.cend()); return _current->first; } rpl::producer idsSlice( SparseIdsMergedSlice::UniversalMsgId aroundId, int limitBefore, int limitAfter); SavedState saveState(); void restoreState(SavedState &&state); private: struct Data { explicit Data(not_null peer) : peer(peer) { } not_null peer; IdsList list; base::flat_map< SparseIdsSliceBuilder::AroundData, rpl::lifetime> requests; }; using SliceUpdate = Storage::SparseIdsSliceUpdate; struct CacheEntry { CacheEntry(not_null session, const Query &query); Data peerData; std::optional migratedData; }; using Cache = base::flat_map>; rpl::producer simpleIdsSlice( PeerId peerId, MsgId topicRootId, MsgId aroundId, const Query &query, int limitBefore, int limitAfter); void requestMore( const SparseIdsSliceBuilder::AroundData &key, const Query &query, Data *listData); const not_null _session; Cache _cache; Cache::iterator _current = _cache.end(); }; class DelayedSearchController { public: explicit DelayedSearchController(not_null session); using Query = SearchController::Query; using SavedState = SearchController::SavedState; void setQuery(const Query &query); void setQuery(const Query &query, crl::time delay); void setQueryFast(const Query &query); Query currentQuery() const { return _controller.query(); } rpl::producer idsSlice( SparseIdsMergedSlice::UniversalMsgId aroundId, int limitBefore, int limitAfter) { return _controller.idsSlice( aroundId, limitBefore, limitAfter); } rpl::producer currentQueryValue() const { return _currentQueryChanges.events_starting_with( currentQuery().query); } SavedState saveState() { return _controller.saveState(); } void restoreState(SavedState &&state) { _controller.restoreState(std::move(state)); } private: SearchController _controller; Query _nextQuery; base::Timer _timer; rpl::event_stream _currentQueryChanges; }; } // namespace Api