19#ifndef JELLYFIN_SUPPORT_LOADER_H
20#define JELLYFIN_SUPPORT_LOADER_H
22#include <initializer_list>
28#include <QJsonDocument>
33#include <QtConcurrent/QtConcurrent>
45 : m_message(message.toStdString()) {}
50 virtual const char *
what() const noexcept override;
52 virtual QException *
clone() const override;
53 virtual
void raise() const override;
55 std::
string m_message;
58static const
int HTTP_TIMEOUT = 30000;
67 : m_apiClient(apiClient) {}
102 void error(QString message = QString());
109 bool m_isRunning =
false;
113 emit this->error(message);
133template <
typename R,
typename P>
146 return m_result.value();
160 m_parameters = parameters;
172 return std::make_optional<R>(result);
176 return fromJsonValue<R>(QJsonValue());
201 m_parameters = parameters;
219template<
typename R,
typename P>
226 QJsonParseError error;
227 QJsonDocument document = QJsonDocument::fromJson(response, &error);
228 if (error.error != QJsonParseError::NoError) {
229 qWarning() << response;
230 this->stopWithError(error.errorString().toLocal8Bit().constData());
232 if (document.isNull() || document.isEmpty()) {
233 this->stopWithError(QStringLiteral(
"Unexpected empty JSON response"));
234 return this->createFailureResult();
235 }
else if (document.isArray()) {
236 return this->createSuccessResult(fromJsonValue<R>(document.array()));
237 }
else if (document.isObject()){
238 return this->createSuccessResult(fromJsonValue<R>(document.object()));
240 this->stopWithError(QStringLiteral(
"Unexpected JSON response"));
241 return this->createFailureResult();
252 :
Loader<void, P> (apiClient) {}
255 return statusCode == 204;
264 :
Loader<bool, P> (apiClient) {}
267 QString text = QString::fromUtf8(response);
269 if (text == QStringLiteral(
"true")) {
271 }
else if (text == QStringLiteral(
"false")) {
274 this->stopWithError(QStringLiteral(
"Could not parse boolean response: %1").arg(text));
284template <
typename R,
typename P>
293 if (m_reply !=
nullptr) {
294 this->m_reply->deleteLater();
296 if (!this->m_parameters) {
297 this->stopWithError(
"No parameters set");
299 this->m_isRunning =
true;
300 switch(operation()) {
301 case QNetworkAccessManager::GetOperation:
302 m_reply = this->m_apiClient->
get(path(this->m_parameters.value()), query(this->m_parameters.value()));
304 case QNetworkAccessManager::PostOperation:
305 m_reply = this->m_apiClient->
post(path(this->m_parameters.value()), body(this->m_parameters.value()), query(this->m_parameters.value()));
308 this->stopWithError(QStringLiteral(
"Unsupported network okperation %1").arg(operation()));
317 if (m_reply ==
nullptr)
return;
318 if (m_reply->isRunning()) {
320 m_reply->deleteLater();
326 if (this->m_apiClient ==
nullptr) {
329 return this->m_apiClient->
online();
338 virtual QString
path(
const P ¶meters)
const = 0;
339 virtual QUrlQuery
query(
const P ¶meters)
const = 0;
340 virtual QByteArray
body(
const P ¶meters)
const = 0;
341 virtual QNetworkAccessManager::Operation
operation()
const = 0;
343 QNetworkReply *m_reply =
nullptr;
344 QFutureWatcher<typename Loader<R, P>::ResultType> m_parsedWatcher;
346 void onRequestFinished() {
347 if (m_reply->error() != QNetworkReply::NoError) {
348 m_reply->deleteLater();
349 m_parsedWatcher.cancel();
351 this->stopWithError(QStringLiteral(
"HTTP error: %1").arg(m_reply->errorString()));
354 QByteArray array = m_reply->readAll();
355 int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
356 m_reply->deleteLater();
358 m_parsedWatcher.setFuture(
362 QByteArray, QByteArray>
367 void onResponseParsed() {
368 Q_ASSERT(m_parsedWatcher.isFinished());
373 if (m_parsedWatcher.result()) {
374 this->m_result = m_parsedWatcher.result();
375 this->m_isRunning =
false;
378 this->m_isRunning =
false;
380 }
catch (QException &e) {
381 this->stopWithError(e.what());
An Api client for Jellyfin. Handles requests and authentication.
Definition apiclient.h:90
QNetworkReply * get(const QString &path, const QUrlQuery ¶ms=QUrlQuery())
Definition apiclient.cpp:262
QNetworkReply * post(const QString &path, const QJsonDocument &data, const QUrlQuery ¶ms=QUrlQuery())
Definition apiclient.cpp:268
bool online
Definition apiclient.h:116
HttpLoaderBase(Jellyfin::ApiClient *apiClient)
Definition loader.h:263
Loader< bool, P >::ResultType parseResponse(int statusCode, QByteArray response)
Definition loader.h:266
Loader< void, P >::ResultType parseResponse(int statusCode, QByteArray response)
Definition loader.h:254
HttpLoaderBase(Jellyfin::ApiClient *apiClient)
Definition loader.h:251
Loader< R, P >::ResultType parseResponse(int, QByteArray response)
Definition loader.h:225
HttpLoaderBase(Jellyfin::ApiClient *apiClient)
Definition loader.h:222
virtual QString path(const P ¶meters) const =0
Subclasses should override this method to return the path to this endpoint, with all path parameters ...
HttpLoader(Jellyfin::ApiClient *apiClient)
Definition loader.h:287
virtual QByteArray body(const P ¶meters) const =0
virtual void cancel() override
Definition loader.h:316
virtual QNetworkAccessManager::Operation operation() const =0
bool isAvailable() const override
Heuristic to determine if this resource can be loaded via this loaded.
Definition loader.h:325
virtual QUrlQuery query(const P ¶meters) const =0
virtual void load() override
load Loads the given resource asynchronously.
Definition loader.h:292
virtual const char * what() const noexcept override
Definition loader.cpp:24
virtual QException * clone() const override
Definition loader.cpp:28
virtual void raise() const override
Definition loader.cpp:32
LoadException(const QString &message)
Definition loader.h:44
Base class for loaders that defines available signals.
Definition loader.h:63
LoaderBase(ApiClient *apiClient)
Definition loader.h:66
void setApiClient(ApiClient *newApiClient)
Definition loader.h:94
virtual bool isAvailable() const
Heuristic to determine if this resource can be loaded via this loaded.
Definition loader.h:93
virtual void cancel()
Definition loader.h:80
void stopWithError(QString message=QString())
Definition loader.h:111
void error(QString message=QString())
Emitted when an error has occurred during loading and no result is available.
ApiClient * apiClient() const
Definition loader.h:95
virtual void load()
load Loads the given resource asynchronously.
Definition loader.h:73
Jellyfin::ApiClient * m_apiClient
Definition loader.h:108
bool isRunning() const
Definition loader.h:82
void ready()
Emitted when data was successfully loaded.
Loader(ApiClient *apiClient)
Definition loader.h:185
ResultType createFailureResult()
Definition loader.h:208
static void createDummyResponse()
Definition loader.h:216
ResultType createSuccessResult(void)
Definition loader.h:212
std::optional< P > m_parameters
Definition loader.h:205
bool hasResult() const
Definition loader.h:190
ResultType m_result
Definition loader.h:206
bool ResultType
Definition loader.h:184
void setParameters(const P ¶meters)
Sets the parameters for this loader.
Definition loader.h:200
void result() const
Definition loader.h:188
ResultType m_result
Definition loader.h:165
std::optional< R > ResultType
Definition loader.h:136
static R createDummyResponse()
Definition loader.h:175
ResultType createFailureResult()
Definition loader.h:167
R result() const
Retrieves the loaded resource. Only valid after the ready signal has been emitted.
Definition loader.h:145
ResultType createSuccessResult(R &&result)
Definition loader.h:171
bool hasResult() const
Definition loader.h:149
Loader(ApiClient *apiClient)
Definition loader.h:137
void setParameters(const P ¶meters)
Sets the parameters for this loader.
Definition loader.h:159
std::optional< P > m_parameters
Definition loader.h:164
void writeRequestTypesFile R(File headerFile, File implementationFile, R endpoints) if(is(ElementType!R
Definition openapigenerator.d:278