1 | /* |
2 | SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleixpol@kde.org> |
3 | |
4 | SPDX-License-Identifier: LGPL-2.1-or-later |
5 | */ |
6 | |
7 | #include "resultsstream.h" |
8 | #include "enginebase_p.h" |
9 | #include "knewstuffcore_debug.h" |
10 | |
11 | #include <QTimer> |
12 | |
13 | using namespace KNSCore; |
14 | |
15 | class KNSCore::ResultsStreamPrivate |
16 | { |
17 | public: |
18 | QList<QSharedPointer<KNSCore::Provider>> providers; |
19 | EngineBase const *engine; |
20 | Provider::SearchRequest request; |
21 | }; |
22 | |
23 | ResultsStream::ResultsStream(const Provider::SearchRequest &request, EngineBase *base) |
24 | : d(new ResultsStreamPrivate{ |
25 | .providers = base->d->providers.values(), |
26 | .engine = base, |
27 | .request = request, |
28 | }) |
29 | { |
30 | auto finished = [this](const KNSCore::Provider::SearchRequest &request, const KNSCore::Entry::List &entries) { |
31 | if (request != d->request) { |
32 | return; |
33 | } |
34 | |
35 | if (d->providers.removeAll(t: qobject_cast<Provider *>(object: sender())) <= 0) { |
36 | qCDebug(KNEWSTUFFCORE) << "Request finished twice, check your provider" << sender() << d->engine << entries.size(); |
37 | return; |
38 | } |
39 | |
40 | if (entries.isEmpty() && d->providers.isEmpty()) { |
41 | finish(); |
42 | } |
43 | if (!entries.isEmpty()) { |
44 | Q_EMIT entriesFound(entries); |
45 | } |
46 | }; |
47 | auto failed = [this](const KNSCore::Provider::SearchRequest &request) { |
48 | if (request == d->request) { |
49 | finish(); |
50 | } |
51 | }; |
52 | for (const auto &provider : d->providers) { |
53 | connect(sender: provider.data(), signal: &Provider::loadingFinished, context: this, slot&: finished); |
54 | connect(sender: provider.data(), signal: &Provider::entryDetailsLoaded, context: this, slot: [this](const KNSCore::Entry &entry) { |
55 | if (d->request.filter == KNSCore::Provider::ExactEntryId && d->request.searchTerm == entry.uniqueId()) { |
56 | if (entry.isValid()) { |
57 | Q_EMIT entriesFound(entries: {entry}); |
58 | } |
59 | finish(); |
60 | } |
61 | }); |
62 | connect(sender: provider.data(), signal: &Provider::loadingFailed, context: this, slot&: failed); |
63 | } |
64 | } |
65 | |
66 | ResultsStream::~ResultsStream() = default; |
67 | |
68 | void ResultsStream::fetch() |
69 | { |
70 | if (d->request.filter != Provider::Installed) { |
71 | // when asking for installed entries, never use the cache |
72 | Entry::List cacheEntries = d->engine->cache()->requestFromCache(d->request); |
73 | if (!cacheEntries.isEmpty()) { |
74 | Q_EMIT entriesFound(entries: cacheEntries); |
75 | return; |
76 | } |
77 | } |
78 | |
79 | for (const QSharedPointer<KNSCore::Provider> &p : std::as_const(t&: d->providers)) { |
80 | if (p->isInitialized()) { |
81 | QTimer::singleShot(interval: 0, receiver: this, slot: [this, p] { |
82 | p->loadEntries(request: d->request); |
83 | }); |
84 | } else { |
85 | connect(sender: p.get(), signal: &KNSCore::Provider::providerInitialized, context: this, slot: [this, p] { |
86 | disconnect(sender: p.get(), signal: &KNSCore::Provider::providerInitialized, receiver: this, zero: nullptr); |
87 | p->loadEntries(request: d->request); |
88 | }); |
89 | } |
90 | } |
91 | } |
92 | |
93 | void ResultsStream::fetchMore() |
94 | { |
95 | d->request.page++; |
96 | fetch(); |
97 | } |
98 | |
99 | void ResultsStream::finish() |
100 | { |
101 | Q_EMIT finished(); |
102 | deleteLater(); |
103 | } |
104 | |
105 | #include "moc_resultsstream.cpp" |
106 | |