mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Refactor ProviderRestApi, increase default timeout
This commit is contained in:
parent
8a177be974
commit
a9d3360f7f
@ -20,25 +20,32 @@ enum HttpStatusCode {
|
||||
NoContent = 204,
|
||||
BadRequest = 400,
|
||||
UnAuthorized = 401,
|
||||
Forbidden = 403,
|
||||
NotFound = 404
|
||||
};
|
||||
|
||||
constexpr std::chrono::milliseconds DEFAULT_REST_TIMEOUT{ 400 };
|
||||
|
||||
} //End of constants
|
||||
|
||||
ProviderRestApi::ProviderRestApi(const QString& host, int port, const QString& basePath)
|
||||
:_log(Logger::getInstance("LEDDEVICE"))
|
||||
, _networkManager(nullptr)
|
||||
ProviderRestApi::ProviderRestApi(const QString& scheme, const QString& host, int port, const QString& basePath)
|
||||
: _log(Logger::getInstance("LEDDEVICE"))
|
||||
, _networkManager(nullptr)
|
||||
, _requestTimeout(DEFAULT_REST_TIMEOUT)
|
||||
{
|
||||
_networkManager = new QNetworkAccessManager();
|
||||
_networkManager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
|
||||
_apiUrl.setScheme("http");
|
||||
_apiUrl.setScheme(scheme);
|
||||
_apiUrl.setHost(host);
|
||||
_apiUrl.setPort(port);
|
||||
_basePath = basePath;
|
||||
}
|
||||
|
||||
ProviderRestApi::ProviderRestApi(const QString& scheme, const QString& host, int port)
|
||||
: ProviderRestApi(scheme, host, port, "") {}
|
||||
|
||||
ProviderRestApi::ProviderRestApi(const QString& host, int port, const QString& basePath)
|
||||
: ProviderRestApi("http", host, port, basePath) {}
|
||||
|
||||
ProviderRestApi::ProviderRestApi(const QString& host, int port)
|
||||
: ProviderRestApi(host, port, "") {}
|
||||
|
||||
@ -62,6 +69,12 @@ void ProviderRestApi::setBasePath(const QString& basePath)
|
||||
appendPath(_basePath, basePath);
|
||||
}
|
||||
|
||||
void ProviderRestApi::setPath(const QStringList& pathElements)
|
||||
{
|
||||
_path.clear();
|
||||
appendPath(_path, pathElements.join(ONE_SLASH));
|
||||
}
|
||||
|
||||
void ProviderRestApi::setPath(const QString& path)
|
||||
{
|
||||
_path.clear();
|
||||
@ -73,6 +86,11 @@ void ProviderRestApi::appendPath(const QString& path)
|
||||
appendPath(_path, path);
|
||||
}
|
||||
|
||||
void ProviderRestApi::appendPath(const QStringList& pathElements)
|
||||
{
|
||||
appendPath(_path, pathElements.join(ONE_SLASH));
|
||||
}
|
||||
|
||||
void ProviderRestApi::appendPath ( QString& path, const QString &appendPath)
|
||||
{
|
||||
if (!appendPath.isEmpty() && appendPath != ONE_SLASH)
|
||||
@ -132,40 +150,7 @@ httpResponse ProviderRestApi::get()
|
||||
|
||||
httpResponse ProviderRestApi::get(const QUrl& url)
|
||||
{
|
||||
// Perform request
|
||||
QNetworkRequest request(_networkRequestHeaders);
|
||||
request.setUrl(url);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
_networkManager->setTransferTimeout(DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
QNetworkReply* reply = _networkManager->get(request);
|
||||
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
QEventLoop::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
ReplyTimeout::set(reply, DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
httpResponse response;
|
||||
if (reply->operation() == QNetworkAccessManager::GetOperation)
|
||||
{
|
||||
if(reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
Debug(_log, "GET: [%s]", QSTRING_CSTR( url.toString() ));
|
||||
}
|
||||
response = getResponse(reply );
|
||||
}
|
||||
// Free space.
|
||||
reply->deleteLater();
|
||||
// Return response
|
||||
return response;
|
||||
return executeOperation(QNetworkAccessManager::GetOperation, url);
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::put(const QJsonObject &body)
|
||||
@ -180,40 +165,7 @@ httpResponse ProviderRestApi::put(const QString &body)
|
||||
|
||||
httpResponse ProviderRestApi::put(const QUrl &url, const QByteArray &body)
|
||||
{
|
||||
// Perform request
|
||||
QNetworkRequest request(_networkRequestHeaders);
|
||||
request.setUrl(url);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
_networkManager->setTransferTimeout(DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
QNetworkReply* reply = _networkManager->put(request, body);
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
QEventLoop::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
ReplyTimeout::set(reply, DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
httpResponse response;
|
||||
if (reply->operation() == QNetworkAccessManager::PutOperation)
|
||||
{
|
||||
if(reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url.toString() ),body.constData() );
|
||||
}
|
||||
response = getResponse(reply);
|
||||
}
|
||||
// Free space.
|
||||
reply->deleteLater();
|
||||
|
||||
// Return response
|
||||
return response;
|
||||
return executeOperation(QNetworkAccessManager::PutOperation, url, body);
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::post(const QJsonObject& body)
|
||||
@ -228,76 +180,69 @@ httpResponse ProviderRestApi::post(const QString& body)
|
||||
|
||||
httpResponse ProviderRestApi::post(const QUrl& url, const QByteArray& body)
|
||||
{
|
||||
// Perform request
|
||||
QNetworkRequest request(_networkRequestHeaders);
|
||||
request.setUrl(url);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
_networkManager->setTransferTimeout(DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
QNetworkReply* reply = _networkManager->post(request, body);
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
QEventLoop::connect(reply,&QNetworkReply::finished,&loop,&QEventLoop::quit);
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
ReplyTimeout::set(reply, DEFAULT_REST_TIMEOUT.count());
|
||||
#endif
|
||||
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
httpResponse response;
|
||||
if (reply->operation() == QNetworkAccessManager::PostOperation)
|
||||
{
|
||||
if(reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
Debug(_log, "POST: [%s] [%s]", QSTRING_CSTR( url.toString() ),body.constData() );
|
||||
}
|
||||
response = getResponse(reply);
|
||||
}
|
||||
// Free space.
|
||||
reply->deleteLater();
|
||||
|
||||
// Return response
|
||||
return response;
|
||||
return executeOperation(QNetworkAccessManager::PostOperation, url, body);
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::deleteResource(const QUrl& url)
|
||||
{
|
||||
return executeOperation(QNetworkAccessManager::DeleteOperation, url);
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::executeOperation(QNetworkAccessManager::Operation operation, const QUrl& url, const QByteArray& body)
|
||||
{
|
||||
// Perform request
|
||||
QNetworkRequest request(_networkRequestHeaders);
|
||||
request.setUrl(url);
|
||||
request.setOriginatingObject(this);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
_networkManager->setTransferTimeout(DEFAULT_REST_TIMEOUT.count());
|
||||
_networkManager->setTransferTimeout(_requestTimeout.count());
|
||||
#endif
|
||||
|
||||
QNetworkReply* reply = _networkManager->deleteResource(request);
|
||||
QDateTime start = QDateTime::currentDateTime();
|
||||
QString opCode;
|
||||
QNetworkReply* reply;
|
||||
switch (operation) {
|
||||
case QNetworkAccessManager::GetOperation:
|
||||
opCode = "GET";
|
||||
reply = _networkManager->get(request);
|
||||
break;
|
||||
case QNetworkAccessManager::PutOperation:
|
||||
opCode = "PUT";
|
||||
reply = _networkManager->put(request, body);
|
||||
break;
|
||||
case QNetworkAccessManager::PostOperation:
|
||||
opCode = "POST";
|
||||
reply = _networkManager->post(request, body);
|
||||
break;
|
||||
case QNetworkAccessManager::DeleteOperation:
|
||||
opCode = "DELETE";
|
||||
reply = _networkManager->deleteResource(request);
|
||||
break;
|
||||
default:
|
||||
Error(_log, "Unsupported operation");
|
||||
return httpResponse();
|
||||
}
|
||||
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
QEventLoop::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
|
||||
ReplyTimeout::set(reply, DEFAULT_REST_TIMEOUT.count());
|
||||
ReplyTimeout* timeout = ReplyTimeout::set(reply, _requestTimeout.count());
|
||||
#endif
|
||||
|
||||
httpResponse response;
|
||||
if (reply->operation() == QNetworkAccessManager::DeleteOperation)
|
||||
{
|
||||
if(reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
Debug(_log, "DELETE: [%s]", QSTRING_CSTR(url.toString()));
|
||||
}
|
||||
response = getResponse(reply);
|
||||
}
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
QDateTime end = QDateTime::currentDateTime();
|
||||
|
||||
httpResponse response = (reply->operation() == operation) ? getResponse(reply) : httpResponse();
|
||||
|
||||
Debug(_log, "%s took %lldms, HTTP %d: [%s] [%s]", QSTRING_CSTR(opCode), start.msecsTo(end), response.getHttpStatusCode(), QSTRING_CSTR(url.toString()), body.constData());
|
||||
|
||||
// Free space.
|
||||
reply->deleteLater();
|
||||
|
||||
// Return response
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -338,7 +283,6 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const& reply)
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
|
||||
QString errorReason;
|
||||
if (httpStatusCode > 0) {
|
||||
QString httpReason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||
@ -350,21 +294,30 @@ httpResponse ProviderRestApi::getResponse(QNetworkReply* const& reply)
|
||||
case HttpStatusCode::UnAuthorized:
|
||||
advise = "Check Authentication Token (API Key)";
|
||||
break;
|
||||
case HttpStatusCode::Forbidden:
|
||||
advise = "No permission to access the given resource";
|
||||
break;
|
||||
case HttpStatusCode::NotFound:
|
||||
advise = "Check Resource given";
|
||||
break;
|
||||
default:
|
||||
advise = httpReason;
|
||||
break;
|
||||
}
|
||||
errorReason = QString ("[%3 %4] - %5").arg(httpStatusCode).arg(httpReason, advise);
|
||||
}
|
||||
else
|
||||
{
|
||||
errorReason = reply->errorString();
|
||||
if (reply->error() == QNetworkReply::OperationCanceledError)
|
||||
{
|
||||
response.setError(true);
|
||||
response.setErrorReason(errorReason);
|
||||
errorReason = "Network request timeout error";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorReason = reply->errorString();
|
||||
}
|
||||
response.setError(true);
|
||||
response.setErrorReason(errorReason);
|
||||
}
|
||||
|
||||
// Create valid body which is empty
|
||||
@ -388,3 +341,8 @@ void ProviderRestApi::setHeader(QNetworkRequest::KnownHeaders header, const QVar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProviderRestApi::setHeader(const QByteArray &headerName, const QByteArray &headerValue)
|
||||
{
|
||||
_networkRequestHeaders.setRawHeader(headerName, headerValue);
|
||||
}
|
||||
|
@ -13,15 +13,20 @@
|
||||
#include <QBasicTimer>
|
||||
#include <QTimerEvent>
|
||||
|
||||
constexpr std::chrono::milliseconds DEFAULT_REST_TIMEOUT{ 1000 };
|
||||
|
||||
//Set QNetworkReply timeout without external timer
|
||||
//https://stackoverflow.com/questions/37444539/how-to-set-qnetworkreply-timeout-without-external-timer
|
||||
|
||||
class ReplyTimeout : public QObject {
|
||||
class ReplyTimeout : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum HandleMethod { Abort, Close };
|
||||
|
||||
ReplyTimeout(QNetworkReply* reply, const int timeout, HandleMethod method = Abort) :
|
||||
QObject(reply), m_method(method)
|
||||
QObject(reply), m_method(method), m_timedout(false)
|
||||
{
|
||||
Q_ASSERT(reply);
|
||||
if (reply && reply->isRunning()) {
|
||||
@ -29,20 +34,30 @@ public:
|
||||
connect(reply, &QNetworkReply::finished, this, &QObject::deleteLater);
|
||||
}
|
||||
}
|
||||
static void set(QNetworkReply* reply, const int timeout, HandleMethod method = Abort)
|
||||
|
||||
bool isTimedout() const
|
||||
{
|
||||
new ReplyTimeout(reply, timeout, method);
|
||||
return m_timedout;
|
||||
}
|
||||
|
||||
static ReplyTimeout * set(QNetworkReply* reply, const int timeout, HandleMethod method = Abort)
|
||||
{
|
||||
return new ReplyTimeout(reply, timeout, method);
|
||||
}
|
||||
|
||||
signals:
|
||||
void timedout();
|
||||
|
||||
protected:
|
||||
QBasicTimer m_timer;
|
||||
HandleMethod m_method;
|
||||
|
||||
void timerEvent(QTimerEvent * ev) override {
|
||||
if (!m_timer.isActive() || ev->timerId() != m_timer.timerId())
|
||||
return;
|
||||
auto reply = static_cast<QNetworkReply*>(parent());
|
||||
if (reply->isRunning())
|
||||
{
|
||||
m_timedout = true;
|
||||
emit timedout();
|
||||
if (m_method == Close)
|
||||
reply->close();
|
||||
else if (m_method == Abort)
|
||||
@ -50,6 +65,10 @@ protected:
|
||||
m_timer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
QBasicTimer m_timer;
|
||||
HandleMethod m_method;
|
||||
bool m_timedout;
|
||||
};
|
||||
|
||||
///
|
||||
@ -104,11 +123,12 @@ private:
|
||||
///
|
||||
///@endcode
|
||||
///
|
||||
class ProviderRestApi
|
||||
class ProviderRestApi : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
/// @brief Constructor of the REST-API wrapper
|
||||
///
|
||||
ProviderRestApi();
|
||||
@ -121,6 +141,15 @@ public:
|
||||
///
|
||||
explicit ProviderRestApi(const QString& host, int port);
|
||||
|
||||
///
|
||||
/// @brief Constructor of the REST-API wrapper
|
||||
///
|
||||
/// @param[in] scheme
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
///
|
||||
explicit ProviderRestApi(const QString& scheme, const QString& host, int port);
|
||||
|
||||
///
|
||||
/// @brief Constructor of the REST-API wrapper
|
||||
///
|
||||
@ -130,10 +159,20 @@ public:
|
||||
///
|
||||
explicit ProviderRestApi(const QString& host, int port, const QString& basePath);
|
||||
|
||||
///
|
||||
/// @brief Constructor of the REST-API wrapper
|
||||
///
|
||||
/// @param[in] scheme
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
/// @param[in] API base-path
|
||||
///
|
||||
explicit ProviderRestApi(const QString& scheme, const QString& host, int port, const QString& basePath);
|
||||
|
||||
///
|
||||
/// @brief Destructor of the REST-API wrapper
|
||||
///
|
||||
virtual ~ProviderRestApi();
|
||||
virtual ~ProviderRestApi() override;
|
||||
|
||||
///
|
||||
/// @brief Set an API's host
|
||||
@ -177,6 +216,12 @@ public:
|
||||
///
|
||||
void setPath(const QString& path);
|
||||
|
||||
/// @brief Set an API's path to address resources
|
||||
///
|
||||
/// @param[in] pathElements to form a path, e.g. (lights,1,state) results in "/lights/1/state/"
|
||||
///
|
||||
void setPath(const QStringList& pathElements);
|
||||
|
||||
///
|
||||
/// @brief Append an API's path element to path set before
|
||||
///
|
||||
@ -184,6 +229,13 @@ public:
|
||||
///
|
||||
void appendPath(const QString& appendPath);
|
||||
|
||||
///
|
||||
/// @brief Append API's path elements to path set before
|
||||
///
|
||||
/// @param[in] pathElements
|
||||
///
|
||||
void appendPath(const QStringList& pathElements);
|
||||
|
||||
///
|
||||
/// @brief Set an API's fragment
|
||||
///
|
||||
@ -283,14 +335,28 @@ public:
|
||||
/// @param[in] The type of the header field.
|
||||
/// @param[in] The value of the header field.
|
||||
/// If the header field exists, the value will be combined as comma separated string.
|
||||
|
||||
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant& value);
|
||||
|
||||
///
|
||||
/// Set a header field.
|
||||
///
|
||||
/// @param[in] The type of the header field.
|
||||
/// @param[in] The value of the header field.
|
||||
/// If the header field exists, the value will override the previous setting.
|
||||
void setHeader(const QByteArray &headerName, const QByteArray &headerValue);
|
||||
|
||||
///
|
||||
/// Remove all header fields.
|
||||
///
|
||||
void removeAllHeaders() { _networkRequestHeaders = QNetworkRequest(); }
|
||||
|
||||
///
|
||||
/// Sets the timeout time frame after a request is aborted
|
||||
/// Zero means no timer is set.
|
||||
///
|
||||
/// @param[in] timeout in milliseconds.
|
||||
void setTransferTimeout(std::chrono::milliseconds timeout = DEFAULT_REST_TIMEOUT) { _requestTimeout = timeout; }
|
||||
|
||||
///
|
||||
/// @brief Set the common logger for LED-devices.
|
||||
///
|
||||
@ -308,10 +374,14 @@ private:
|
||||
///
|
||||
static void appendPath (QString &path, const QString &appendPath) ;
|
||||
|
||||
|
||||
httpResponse executeOperation(QNetworkAccessManager::Operation op, const QUrl& url, const QByteArray& body = {});
|
||||
|
||||
Logger* _log;
|
||||
|
||||
// QNetworkAccessManager object for sending REST-requests.
|
||||
QNetworkAccessManager* _networkManager;
|
||||
std::chrono::milliseconds _requestTimeout;
|
||||
|
||||
QUrl _apiUrl;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user