| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /*
- 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
- */
- #include "api/api_messages_search.h"
- #include "apiwrap.h"
- #include "data/data_channel.h"
- #include "data/data_histories.h"
- #include "data/data_message_reaction_id.h"
- #include "data/data_peer.h"
- #include "data/data_session.h"
- #include "history/history.h"
- #include "history/history_item.h"
- #include "main/main_session.h"
- namespace Api {
- namespace {
- constexpr auto kSearchPerPage = 50;
- [[nodiscard]] MessageIdsList HistoryItemsFromTL(
- not_null<Data::Session*> data,
- const QVector<MTPMessage> &messages) {
- auto result = MessageIdsList();
- for (const auto &message : messages) {
- const auto peerId = PeerFromMessage(message);
- if (const auto peer = data->peerLoaded(peerId)) {
- if (const auto lastDate = DateFromMessage(message)) {
- const auto item = data->addNewMessage(
- message,
- MessageFlags(),
- NewMessageType::Existing);
- result.push_back(item->fullId());
- }
- } else {
- LOG(("API Error: a search results with not loaded peer %1"
- ).arg(peerId.value));
- }
- }
- return result;
- }
- [[nodiscard]] QString RequestToToken(
- const MessagesSearch::Request &request) {
- auto result = request.query;
- if (request.from) {
- result += '\n' + QString::number(request.from->id.value);
- }
- for (const auto &tag : request.tags) {
- result += '\n';
- if (const auto customId = tag.custom()) {
- result += u"custom"_q + QString::number(customId);
- } else {
- result += u"emoji"_q + tag.emoji();
- }
- }
- return result;
- }
- } // namespace
- MessagesSearch::MessagesSearch(not_null<History*> history)
- : _history(history) {
- }
- MessagesSearch::~MessagesSearch() {
- _history->owner().histories().cancelRequest(
- base::take(_searchInHistoryRequest));
- }
- void MessagesSearch::searchMessages(Request request) {
- _request = std::move(request);
- _offsetId = {};
- searchRequest();
- }
- void MessagesSearch::searchMore() {
- if (_searchInHistoryRequest || _requestId) {
- return;
- }
- searchRequest();
- }
- void MessagesSearch::searchRequest() {
- const auto nextToken = RequestToToken(_request);
- if (!_offsetId) {
- const auto it = _cacheOfStartByToken.find(nextToken);
- if (it != end(_cacheOfStartByToken)) {
- _requestId = 0;
- searchReceived(it->second, _requestId, nextToken);
- return;
- }
- }
- auto callback = [=](Fn<void()> finish) {
- using Flag = MTPmessages_Search::Flag;
- const auto from = _request.from;
- const auto fromPeer = _history->peer->isUser() ? nullptr : from;
- const auto savedPeer = _history->peer->isSelf() ? from : nullptr;
- _requestId = _history->session().api().request(MTPmessages_Search(
- MTP_flags((fromPeer ? Flag::f_from_id : Flag())
- | (savedPeer ? Flag::f_saved_peer_id : Flag())
- | (_request.topMsgId ? Flag::f_top_msg_id : Flag())
- | (_request.tags.empty() ? Flag() : Flag::f_saved_reaction)),
- _history->peer->input,
- MTP_string(_request.query),
- (fromPeer ? fromPeer->input : MTP_inputPeerEmpty()),
- (savedPeer ? savedPeer->input : MTP_inputPeerEmpty()),
- MTP_vector_from_range(_request.tags | ranges::views::transform(
- Data::ReactionToMTP
- )),
- MTP_int(_request.topMsgId), // top_msg_id
- MTP_inputMessagesFilterEmpty(),
- MTP_int(0), // min_date
- MTP_int(0), // max_date
- MTP_int(_offsetId), // 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 TLMessages &result, mtpRequestId id) {
- _searchInHistoryRequest = 0;
- searchReceived(result, id, nextToken);
- finish();
- }).fail([=](const MTP::Error &error, mtpRequestId id) {
- _searchInHistoryRequest = 0;
- if (_requestId == id) {
- _requestId = 0;
- }
- if (error.type() == u"SEARCH_QUERY_EMPTY"_q) {
- _messagesFounds.fire({ 0, MessageIdsList(), nextToken });
- }
- finish();
- }).send();
- return _requestId;
- };
- _searchInHistoryRequest = _history->owner().histories().sendRequest(
- _history,
- Data::Histories::RequestType::History,
- std::move(callback));
- }
- void MessagesSearch::searchReceived(
- const TLMessages &result,
- mtpRequestId requestId,
- const QString &nextToken) {
- if (requestId != _requestId) {
- return;
- }
- auto &owner = _history->owner();
- auto found = result.match([&](const MTPDmessages_messages &data) {
- if (_requestId != 0) {
- // Don't apply cached data!
- owner.processUsers(data.vusers());
- owner.processChats(data.vchats());
- }
- auto items = HistoryItemsFromTL(&owner, data.vmessages().v);
- const auto total = int(data.vmessages().v.size());
- return FoundMessages{ total, std::move(items), nextToken };
- }, [&](const MTPDmessages_messagesSlice &data) {
- if (_requestId != 0) {
- // Don't apply cached data!
- owner.processUsers(data.vusers());
- owner.processChats(data.vchats());
- }
- auto items = HistoryItemsFromTL(&owner, data.vmessages().v);
- // data.vnext_rate() is used only in global search.
- const auto total = int(data.vcount().v);
- return FoundMessages{ total, std::move(items), nextToken };
- }, [&](const MTPDmessages_channelMessages &data) {
- if (_requestId != 0) {
- // Don't apply cached data!
- owner.processUsers(data.vusers());
- owner.processChats(data.vchats());
- }
- if (const auto channel = _history->peer->asChannel()) {
- channel->ptsReceived(data.vpts().v);
- if (_requestId != 0) {
- // Don't apply cached data!
- channel->processTopics(data.vtopics());
- }
- } else {
- LOG(("API Error: "
- "received messages.channelMessages when no channel "
- "was passed!"));
- }
- auto items = HistoryItemsFromTL(&owner, data.vmessages().v);
- const auto total = int(data.vcount().v);
- return FoundMessages{ total, std::move(items), nextToken };
- }, [](const MTPDmessages_messagesNotModified &data) {
- return FoundMessages{};
- });
- if (!_offsetId) {
- _cacheOfStartByToken.emplace(nextToken, result);
- }
- _requestId = 0;
- _offsetId = found.messages.empty()
- ? MsgId()
- : found.messages.back().msg;
- _messagesFounds.fire(std::move(found));
- }
- rpl::producer<FoundMessages> MessagesSearch::messagesFounds() const {
- return _messagesFounds.events();
- }
- } // namespace Api
|