Something went wrong. Try again.
Mixxx DJ software with MCP, Subsonic/Navidrome streaming library support — browse and load tracks from your self-hosted music server mixxx.org
subsonic navidrome streaming audio dj mac linux midi
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238#pragma once
#include <QMimeType>#include <QNetworkReply>#include <QUrl>
#include "network/httpstatuscode.h"#include "network/networktask.h"#include "util/optional.h"#include "util/performancetimer.h"
class QNetworkAccessManager;
namespace mixxx {
namespace network {
class WebResponse final { public: static void registerMetaType();
WebResponse() : m_statusCode(kHttpStatusCodeInvalid) { } explicit WebResponse( QUrl requestUrl, QUrl replyUrl = QUrl(), HttpStatusCode statusCode = kHttpStatusCodeInvalid) : m_requestUrl(std::move(requestUrl)), m_replyUrl(std::move(replyUrl)), m_statusCode(statusCode) { } WebResponse(const WebResponse&) = default; WebResponse(WebResponse&&) = default;
WebResponse& operator=(const WebResponse&) = default; WebResponse& operator=(WebResponse&&) = default;
bool isStatusCodeSuccess() const { return HttpStatusCode_isSuccess(m_statusCode); }
const QUrl& requestUrl() const { return m_requestUrl; }
const QUrl& replyUrl() const { return m_replyUrl; }
HttpStatusCode statusCode() const { return m_statusCode; }
friend QDebug operator<<(QDebug dbg, const WebResponse& arg);
private: QUrl m_requestUrl; QUrl m_replyUrl; HttpStatusCode m_statusCode;};
class WebResponseWithContent final { public: static void registerMetaType();
WebResponseWithContent() = default; WebResponseWithContent( WebResponse&& response, QMimeType&& contentType, QByteArray&& contentData) : m_response(response), m_contentType(contentType), m_contentData(contentData) { } WebResponseWithContent(const WebResponseWithContent&) = default; WebResponseWithContent(WebResponseWithContent&&) = default;
WebResponseWithContent& operator=(const WebResponseWithContent&) = default; WebResponseWithContent& operator=(WebResponseWithContent&&) = default;
bool isStatusCodeSuccess() const { return m_response.isStatusCodeSuccess(); }
HttpStatusCode statusCode() const { return m_response.statusCode(); }
const QUrl& requestUrl() const { return m_response.requestUrl(); }
const QUrl& replyUrl() const { return m_response.replyUrl(); }
const QMimeType& contentType() const { return m_contentType; }
const QByteArray& contentData() const { return m_contentData; }
friend QDebug operator<<(QDebug dbg, const WebResponseWithContent& arg);
private: WebResponse m_response; QMimeType m_contentType; QByteArray m_contentData;};
/// A transient task for performing a single HTTP network request/// asynchronously.class WebTask : public NetworkTask { Q_OBJECT
public: static QMimeType readContentType( const QNetworkReply& reply); static std::optional<QByteArray> readContentData( QNetworkReply* reply);
explicit WebTask( QNetworkAccessManager* networkAccessManager, QObject* parent = nullptr); ~WebTask() override = default;
bool isBusy() const { return state() == State::Starting || state() == State::Pending; }
signals: /// Network or server-side abort/timeout/failure void networkError( QNetworkReply::NetworkError errorCode, const QString& errorString, const mixxx::network::WebResponseWithContent& responseWithContent);
public slots: void slotStart( int timeoutMillis = kNoTimeout, int delayMillis = kNoStartDelay) override; void slotAbort() override;
private slots: void slotNetworkReplyFinished();
protected: void timerEvent(QTimerEvent* event) final;
enum class State { // Initial state Initial, // Timed start Starting, // Pending state Pending, // Terminal states Aborted, TimedOut, Failed, Finished, };
State state() const { return m_state; }
bool hasTerminated() const { return state() == State::Aborted || state() == State::TimedOut || state() == State::Failed || state() == State::Finished; }
/// Send a signal after a failed network response. void emitNetworkError( QNetworkReply::NetworkError errorCode, const QString& errorString, const WebResponseWithContent& responseWithContent);
protected: virtual void onNetworkError( QNetworkReply* pFinishedNetworkReply, HttpStatusCode statusCode);
private: QUrl abortPendingNetworkReply();
/// Try to compose and send the actual network request. /// Return nullptr on failure. virtual QNetworkReply* doStartNetworkRequest( QNetworkAccessManager* networkAccessManager, int parentTimeoutMillis) = 0;
/// Optional: Do something after aborted. virtual void doNetworkReplyAborted( QNetworkReply* abortedNetworkReply) { Q_UNUSED(abortedNetworkReply); }
/// Handle network response. virtual void doNetworkReplyFinished( QNetworkReply* pFinishedNetworkReply, HttpStatusCode statusCode) = 0;
/// Handle the abort and ensure that the task eventually /// gets deleted. The default implementation logs a warning /// and deletes the task. void onNetworkError( QNetworkReply::NetworkError errorCode, const QString& errorString, const WebResponseWithContent& responseWithContent);
/// All member variables must only be accessed from /// the event loop thread!!
State m_state;
PerformanceTimer m_timer;
int m_timeoutTimerId; int m_timeoutMillis;
SafeQPointer<QNetworkReply> m_pendingNetworkReplyWeakPtr;};
} // namespace network
} // namespace mixxx
Q_DECLARE_METATYPE(mixxx::network::WebResponse);
Q_DECLARE_METATYPE(mixxx::network::WebResponseWithContent);