From 3d8f962c211da715b52c126c6b8be80ceb075eab Mon Sep 17 00:00:00 2001 From: Arseny Bochkarev Date: Thu, 7 Nov 2024 02:35:51 +0300 Subject: [PATCH] [Search] Add search prototype --- .../dialogs/dialogs_inner_widget.cpp | 60 +++++++ .../dialogs/dialogs_inner_widget.h | 6 + .../SourceFiles/dialogs/dialogs_widget.cpp | 168 ++++++++++++++++++ Telegram/SourceFiles/dialogs/dialogs_widget.h | 6 + Telegram/SourceFiles/history/history_item.h | 4 + 5 files changed, 244 insertions(+) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 7d63bb5978967a..82786b5ef64dd3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -82,6 +82,8 @@ For license and copyright information please follow this link: #include +#include + namespace Dialogs { namespace { @@ -3209,6 +3211,7 @@ void InnerWidget::searchReceived( } } } + if (type.migrated) { _searchedMigratedCount = fullCount; } else if (!withPreview || !toPreview) { @@ -3220,6 +3223,63 @@ void InnerWidget::searchReceived( refresh(); } +void InnerWidget::encryptedSearchReceived( + std::vector> messages, + HistoryItem *inject, + SearchRequestType type, + const QString &searchQuery, + int fullCount) { + _searchWaiting = false; + _searchLoading = false; + + // We need to decrypt message here + // And push it if we match + + const auto uniquePeers = uniqueSearchResults(); + const auto withPreview = _searchWithPostsPreview; + const auto toPreview = withPreview && type.posts; + + const auto key = (!_openedForum || _searchState.inChat.topic()) + ? _searchState.inChat + : Key(_openedForum->history()); + if (inject + && (!_searchState.inChat + || inject->history() == _searchState.inChat.history())) { + Assert(!toPreview); + const auto index = int(_searchResults.size()); + // TODO: Check if we need to set predicate for push_back below + _searchResults.push_back( + std::make_unique( + key, + inject, + [=] { repaintSearchResult(index); })); + trackResultsHistory(inject->history()); + ++fullCount; + } + auto &results = toPreview ? _previewResults : _searchResults; + for (const auto &item : messages) { + const auto history = item->history(); + if (toPreview || !uniquePeers || !hasHistoryInResults(history)) { + const auto index = int(results.size()); + const auto repaint = toPreview + ? Fn([=] { repaintSearchResult(index); }) + : [=] { repaintPreviewResult(index); }; + QString pred = "the"; + if (item.get()->getText().text == pred) { + // if (decrypt(item.getText().text) == searchQuery) { + results.push_back( + std::make_unique(key, item, repaint)); + trackResultsHistory(history); + if (!toPreview && uniquePeers && !history->unreadCountKnown()) { + history->owner().histories().requestDialogEntry(history); + } else if (toPreview && results.size() >= kPreviewPostsLimit) { + break; + } + } + } + } +} + void InnerWidget::peerSearchReceived( const QString &query, const QVector &my, diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index a284cca11b000a..bbc77f0f4e8fbf 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -113,6 +113,12 @@ class InnerWidget final : public Ui::RpWidget { HistoryItem *inject, SearchRequestType type, int fullCount); + void encryptedSearchReceived( + std::vector> result, + HistoryItem *inject, + SearchRequestType type, + const QString &searchQuery, + int fullCount); void peerSearchReceived( const QString &query, const QVector &my, diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 73f8f598efba96..22a2eff8d2c6ef 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -2217,6 +2217,54 @@ bool Widget::search(bool inCache, SearchRequestDelay delay) { process->queries.emplace(process->requestId, _searchQuery); return process->requestId; }); + + // ANOTHER request to get all messages with encryption prefix + auto encryptionPrefixQuery = QString("the"); + histories.sendRequest(history, type, [=]( + Fn finish) { + const auto type = SearchRequestType{ + .start = true, + .peer = true, + }; + using Flag = MTPmessages_Search::Flag; + process->requestId = session().api().request( + MTPmessages_Search( + MTP_flags((topic ? Flag::f_top_msg_id : Flag()) + | (fromPeer ? Flag::f_from_id : Flag()) + | (savedPeer ? Flag::f_saved_peer_id : Flag()) + | (_searchQueryTags.empty() + ? Flag() + : Flag::f_saved_reaction)), + inPeer->input, + MTP_string(encryptionPrefixQuery), + (fromPeer ? fromPeer->input : MTP_inputPeerEmpty()), + (savedPeer ? savedPeer->input : MTP_inputPeerEmpty()), + MTP_vector_from_range( + _searchQueryTags | ranges::views::transform( + Data::ReactionToMTP + )), + MTP_int(topic ? topic->rootId() : 0), + MTP_inputMessagesFilterEmpty(), + MTP_int(0), // min_date + MTP_int(0), // max_date + MTP_int(0), // offset_id + MTP_int(0), // add_offset + MTP_int(kSearchPerPage), + MTP_int(0), // max_id + MTP_int(0), // min_id + MTP_long(0)) // hash + ).done([=](const MTPmessages_Messages &result) { + _historiesRequest = 0; + encryptedSearchReceived(type, result, process, _searchQuery); + finish(); + }).fail([=](const MTP::Error &error) { + _historiesRequest = 0; + searchFailed(type, error, process); + finish(); + }).send(); + process->queries.emplace(process->requestId, encryptionPrefixQuery); + return process->requestId; + }); } else if (_searchState.tab == ChatSearchTab::PublicPosts) { requestPublicPosts(true); } else { @@ -2669,6 +2717,126 @@ void Widget::searchReceived( update(); } +void Widget::encryptedSearchReceived( + SearchRequestType type, + const MTPmessages_Messages &result, + not_null process, + const QString &searchQuery, + bool cacheResults) { + const auto state = _inner->state(); + if (!cacheResults + && (state == WidgetState::Filtered) + && type.start) { + const auto i = process->queries.find(process->requestId); + if (i != process->queries.end()) { + process->cache[i->second] = result; + process->queries.erase(i); + } + } + const auto inject = (type.start && !type.posts) + ? *_singleMessageSearch.lookup(_searchQuery) + : nullptr; + if (cacheResults && process->requestId) { + return; + } + if (type.start) { + process->lastPeer = nullptr; + process->lastId = 0; + } + const auto processList = [&](const MTPVector &messages) { + auto result = std::vector>(); + for (const auto &message : messages.v) { + const auto msgId = IdFromMessage(message); + const auto peerId = PeerFromMessage(message); + const auto lastDate = DateFromMessage(message); + if (const auto peer = session().data().peerLoaded(peerId)) { + if (lastDate) { + const auto item = session().data().addNewMessage( + message, + MessageFlags(), + NewMessageType::Existing); + result.push_back(item); + } + process->lastPeer = peer; + } else { + LOG(("API Error: a search results with not loaded peer %1" + ).arg(peerId.value)); + } + process->lastId = msgId; + } + return result; + }; + auto fullCount = 0; + auto messages = result.match([&](const MTPDmessages_messages &data) { + if (!cacheResults) { + // Don't apply cached data! + session().data().processUsers(data.vusers()); + session().data().processChats(data.vchats()); + } + process->full = true; + auto list = processList(data.vmessages()); + fullCount = list.size(); + return list; + }, [&](const MTPDmessages_messagesSlice &data) { + if (!cacheResults) { + // Don't apply cached data! + session().data().processUsers(data.vusers()); + session().data().processChats(data.vchats()); + } + auto list = processList(data.vmessages()); + const auto nextRate = data.vnext_rate(); + const auto rateUpdated = nextRate + && (nextRate->v != process->nextRate); + const auto finished = (type.peer || type.migrated || type.posts) + ? list.empty() + : !rateUpdated; + if (rateUpdated) { + process->nextRate = nextRate->v; + } + if (finished) { + process->full = true; + } + fullCount = data.vcount().v; + return list; + }, [&](const MTPDmessages_channelMessages &data) { + if (const auto peer = searchInPeer()) { + if (const auto channel = peer->asChannel()) { + channel->ptsReceived(data.vpts().v); + channel->processTopics(data.vtopics()); + } else { + LOG(("API Error: " + "received messages.channelMessages when no channel " + "was passed! (Widget::searchReceived)")); + } + } else { + LOG(("API Error: " + "received messages.channelMessages when no channel " + "was passed! (Widget::searchReceived)")); + } + if (!cacheResults) { + // Don't apply cached data! + session().data().processUsers(data.vusers()); + session().data().processChats(data.vchats()); + } + auto list = processList(data.vmessages()); + if (list.empty()) { + process->full = true; + } + fullCount = data.vcount().v; + return list; + }, [&](const MTPDmessages_messagesNotModified &) { + LOG(("API Error: received messages.messagesNotModified! " + "(Widget::searchReceived)")); + process->full = true; + return std::vector>(); + }); + _inner->encryptedSearchReceived(messages, inject, type, searchQuery, fullCount); + + process->requestId = 0; + listScrollUpdated(); + update(); +} + void Widget::peerSearchReceived( const MTPcontacts_Found &result, mtpRequestId requestId) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index ff751c714270e7..be3193efefac77 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -186,6 +186,12 @@ class Widget final : public Window::AbstractSectionWidget { const MTPmessages_Messages &result, not_null process, bool cacheResults = false); + void encryptedSearchReceived( + SearchRequestType type, + const MTPmessages_Messages &result, + not_null process, + const QString &searchQuery, + bool cacheResults = false); void peerSearchReceived( const MTPcontacts_Found &result, mtpRequestId requestId); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 9a17be15fd4239..00c35b25f7ce4c 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -419,6 +419,10 @@ class HistoryItem final : public RuntimeComposer { void incrementReplyToTopCounter(); void applyEffectWatchedOnUnreadKnown(); + TextWithEntities getText() const { + return _text; + } + [[nodiscard]] bool emptyText() const { return _text.empty(); }