summaryrefslogtreecommitdiffstats
path: root/src/network/networktask.h
blob: 410b9779770112d9682aade7eb02d84793800a11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#pragma once

#include <QMetaMethod>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QUrl>

#include "util/assert.h"
#include "util/qt.h"

namespace mixxx {

namespace network {

/// A transient task for performing a single generic network request
/// asynchronously.
///
/// The results are transmitted by emitting signals. At least one
/// of the signal receivers is responsible for destroying the task
/// by invoking QObject::deleteLater(). If no receiver is connected
/// at the time the finalization signal is emitted then the task
/// will destroy itself.
class NetworkTask : public QObject {
    Q_OBJECT

  protected:
    explicit NetworkTask(
            QNetworkAccessManager* networkAccessManager,
            QObject* parent = nullptr);
    virtual ~NetworkTask();

    /// Cancel the task by aborting the pending network request.
    ///
    /// This function is NOT thread-safe and must only be called from
    /// the event loop thread.
    void abort();

    // Required to allow derived classes to invoke abort()
    // on other instances of this class.
    void static abortThis(NetworkTask* pThis) {
        DEBUG_ASSERT(pThis);
        pThis->abort();
    }

    template<typename S>
    bool isSignalFuncConnected(
            S signalFunc) {
        const QMetaMethod signal = QMetaMethod::fromSignal(signalFunc);
        return isSignalConnected(signal);
    }

    /// Send an aborted signal with the optional request URL if available.
    void emitAborted(
            const QUrl& requestUrl = QUrl{});

    /// All member variables must only be accessed from
    /// the event loop thread!!
    const SafeQPointer<QNetworkAccessManager> m_networkAccessManagerWeakPtr;

  public:
    static constexpr int kNoTimeout = 0;

    /// Start a new task by sending a network request.
    ///
    /// timeoutMillis <= 0: No timeout (unlimited)
    /// timeoutMillis > 0: Implicitly aborted after timeout expired
    ///
    /// This function is thread-safe and could be invoked from any thread.
    void invokeStart(
            int timeoutMillis = kNoTimeout);

    /// Cancel the task by aborting the pending network request.
    ///
    /// This function is thread-safe and could be invoked from any thread.
    void invokeAbort();

  public slots:
    virtual void slotStart(
            int timeoutMillis) = 0;
    virtual void slotAbort() = 0;

  signals:
    /// The receiver is responsible for deleting the task in the
    /// corresponding slot handler!! Otherwise the task will remain
    /// in memory as a dysfunctional zombie until its parent object
    /// is finally deleted. If no receiver is connected the task
    /// will be deleted implicitly.

    /// Client-side abort
    void aborted(
            const QUrl& requestUrl);
};

} // namespace network

} // namespace mixxx