1 /*
2     This file is part of Akregator.
3 
4     SPDX-FileCopyrightText: 2004 Sashmit Bhaduri <smt@vfemail.net>
5     SPDX-FileCopyrightText: 2005 Frank Osterfeld <osterfeld@kde.org>
6 
7     SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
8 */
9 
10 #include "fetchqueue.h"
11 #include "akregatorconfig.h"
12 #include "feed.h"
13 #include "treenode.h"
14 
15 using namespace Akregator;
16 
FetchQueue(QObject * parent)17 FetchQueue::FetchQueue(QObject *parent)
18     : QObject(parent)
19 {
20 }
21 
~FetchQueue()22 FetchQueue::~FetchQueue()
23 {
24     slotAbort();
25 }
26 
slotAbort()27 void FetchQueue::slotAbort()
28 {
29     for (Feed *const i : std::as_const(m_fetchingFeeds)) {
30         disconnectFromFeed(i);
31         i->slotAbortFetch();
32     }
33     m_fetchingFeeds.clear();
34 
35     for (Feed *const i : std::as_const(m_queuedFeeds)) {
36         disconnectFromFeed(i);
37     }
38     m_queuedFeeds.clear();
39 
40     Q_EMIT signalStopped();
41 }
42 
addFeed(Feed * f)43 void FetchQueue::addFeed(Feed *f)
44 {
45     if (!m_queuedFeeds.contains(f) && !m_fetchingFeeds.contains(f)) {
46         connectToFeed(f);
47         m_queuedFeeds.append(f);
48         fetchNextFeed();
49     }
50 }
51 
fetchNextFeed()52 void FetchQueue::fetchNextFeed()
53 {
54     if (!m_queuedFeeds.isEmpty() && m_fetchingFeeds.count() < Settings::concurrentFetches()) {
55         if (m_fetchingFeeds.isEmpty() && m_queuedFeeds.count() == 1) {
56             Q_EMIT signalStarted();
57         }
58         Feed *f = *(m_queuedFeeds.begin());
59         m_queuedFeeds.pop_front();
60         m_fetchingFeeds.append(f);
61         f->fetch(false);
62     }
63 }
64 
slotFeedFetched(Feed * f)65 void FetchQueue::slotFeedFetched(Feed *f)
66 {
67     Q_EMIT fetched(f);
68     feedDone(f);
69 }
70 
slotFetchError(Feed * f)71 void FetchQueue::slotFetchError(Feed *f)
72 {
73     Q_EMIT fetchError(f);
74     feedDone(f);
75 }
76 
slotFetchAborted(Feed * f)77 void FetchQueue::slotFetchAborted(Feed *f)
78 {
79     Q_EMIT fetched(f); // FIXME: better use a signal like signalAborted(Feed*)
80     feedDone(f);
81 }
82 
isEmpty() const83 bool FetchQueue::isEmpty() const
84 {
85     return m_queuedFeeds.isEmpty() && m_fetchingFeeds.isEmpty();
86 }
87 
feedDone(Feed * f)88 void FetchQueue::feedDone(Feed *f)
89 {
90     disconnectFromFeed(f);
91     m_fetchingFeeds.removeAll(f);
92     if (isEmpty()) {
93         Q_EMIT signalStopped();
94     } else {
95         fetchNextFeed();
96     }
97 }
98 
connectToFeed(Feed * feed)99 void FetchQueue::connectToFeed(Feed *feed)
100 {
101     connect(feed, &Feed::fetched, this, &FetchQueue::slotFeedFetched);
102     connect(feed, &Feed::fetchError, this, &FetchQueue::slotFetchError);
103     connect(feed, &Feed::fetchAborted, this, &FetchQueue::slotFetchAborted);
104     connect(feed, &TreeNode::signalDestroyed, this, &FetchQueue::slotNodeDestroyed);
105 }
106 
disconnectFromFeed(Feed * feed)107 void FetchQueue::disconnectFromFeed(Feed *feed)
108 {
109     feed->disconnect(this);
110 }
111 
slotNodeDestroyed(TreeNode * node)112 void FetchQueue::slotNodeDestroyed(TreeNode *node)
113 {
114     Feed *const feed = qobject_cast<Feed *>(node);
115     Q_ASSERT(feed);
116 
117     m_fetchingFeeds.removeAll(feed);
118     m_queuedFeeds.removeAll(feed);
119 }
120