Add API timeout handling (#3078)

This commit is contained in:
sunn 2019-06-12 20:16:12 +02:00 committed by GitHub
parent 314f18a2c1
commit a864ae90de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 147 additions and 38 deletions

View File

@ -45,18 +45,29 @@ void {{prefix}}HttpRequestInput::add_file(QString variable_name, QString local_f
: QObject(parent), manager(nullptr)
{
qsrand(QDateTime::currentDateTime().toTime_t());
timeout = 0;
timer = new QTimer();
manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &{{prefix}}HttpRequestWorker::on_manager_finished);
}
{{prefix}}HttpRequestWorker::~{{prefix}}HttpRequestWorker() {
if(timer != nullptr){
if(timer->isActive()){
timer->stop();
}
timer->deleteLater();
}
}
QMap<QByteArray, QByteArray> {{prefix}}HttpRequestWorker::getResponseHeaders() const {
return headers;
}
void {{prefix}}HttpRequestWorker::setTimeOut(int tout){
timeout = tout;
}
QString {{prefix}}HttpRequestWorker::http_attribute_encode(QString attribute_name, QString input) {
// result structure follows RFC 5987
bool need_utf_encoding = false;
@ -108,7 +119,7 @@ QString {{prefix}}HttpRequestWorker::http_attribute_encode(QString attribute_nam
void {{prefix}}HttpRequestWorker::execute({{prefix}}HttpRequestInput *input) {
// reset variables
QNetworkReply* reply = nullptr;
QByteArray request_content = "";
response = "";
error_type = QNetworkReply::NoError;
@ -276,19 +287,19 @@ void {{prefix}}HttpRequestWorker::execute({{prefix}}HttpRequestInput *input) {
}
if (input->http_method == "GET") {
manager->get(request);
reply = manager->get(request);
}
else if (input->http_method == "POST") {
manager->post(request, request_content);
reply = manager->post(request, request_content);
}
else if (input->http_method == "PUT") {
manager->put(request, request_content);
reply = manager->put(request, request_content);
}
else if (input->http_method == "HEAD") {
manager->head(request);
reply = manager->head(request);
}
else if (input->http_method == "DELETE") {
manager->deleteResource(request);
reply = manager->deleteResource(request);
}
else {
#if (QT_VERSION >= 0x050800)
@ -298,11 +309,16 @@ void {{prefix}}HttpRequestWorker::execute({{prefix}}HttpRequestInput *input) {
buffer->setData(request_content);
buffer->open(QIODevice::ReadOnly);
QNetworkReply* reply = manager->sendCustomRequest(request, input->http_method.toLatin1(), buffer);
reply = manager->sendCustomRequest(request, input->http_method.toLatin1(), buffer);
buffer->setParent(reply);
#endif
}
if(timeout > 0){
timer->setSingleShot(true);
timer->setInterval(timeout);
connect(timer, &QTimer::timeout, this, [=](){ on_manager_timeout(reply); });
timer->start();
}
}
void {{prefix}}HttpRequestWorker::on_manager_finished(QNetworkReply *reply) {
@ -318,6 +334,16 @@ void {{prefix}}HttpRequestWorker::on_manager_finished(QNetworkReply *reply) {
emit on_execution_finished(this);
}
void {{prefix}}HttpRequestWorker::on_manager_timeout(QNetworkReply *reply) {
error_type = QNetworkReply::TimeoutError;
response = "";
error_str = "Timed out waiting for response";
disconnect(manager, nullptr, nullptr, nullptr);
reply->abort();
reply->deleteLater();
emit on_execution_finished(this);
}
QSslConfiguration* {{prefix}}HttpRequestWorker::sslDefaultConfiguration;

View File

@ -10,6 +10,7 @@
#include <QObject>
#include <QString>
#include <QTimer>
#include <QMap>
#include <QNetworkAccessManager>
#include <QNetworkReply>
@ -60,7 +61,7 @@ public:
QByteArray response;
QNetworkReply::NetworkError error_type;
QString error_str;
QTimer *timer;
explicit {{prefix}}HttpRequestWorker(QObject *parent = nullptr);
virtual ~{{prefix}}HttpRequestWorker();
@ -68,16 +69,17 @@ public:
QString http_attribute_encode(QString attribute_name, QString input);
void execute({{prefix}}HttpRequestInput *input);
static QSslConfiguration* sslDefaultConfiguration;
void setTimeOut(int tout);
signals:
void on_execution_finished({{prefix}}HttpRequestWorker *worker);
private:
QNetworkAccessManager *manager;
QMap<QByteArray, QByteArray> headers;
int timeout;
void on_manager_timeout(QNetworkReply *reply);
private slots:
void on_manager_finished(QNetworkReply *reply);
void on_manager_finished(QNetworkReply *reply);
};
{{#cppNamespaceDeclarations}}

View File

@ -10,7 +10,8 @@ namespace {{this}} {
{{/cppNamespaceDeclarations}}
{{classname}}::{{classname}}() : basePath("{{{basePathWithoutHost}}}"),
host("{{#serverHost}}{{#scheme}}{{scheme}}://{{/scheme}}{{serverHost}}{{#serverPort}}:{{serverPort}}{{/serverPort}}{{/serverHost}}") {
host("{{#serverHost}}{{#scheme}}{{scheme}}://{{/scheme}}{{serverHost}}{{#serverPort}}:{{serverPort}}{{/serverPort}}{{/serverHost}}"),
timeout(0){
}
@ -18,9 +19,10 @@ namespace {{this}} {
}
{{classname}}::{{classname}}(const QString& host, const QString& basePath) {
{{classname}}::{{classname}}(const QString& host, const QString& basePath, const int tout) {
this->host = host;
this->basePath = basePath;
this->timeout = tout;
}
void {{classname}}::setBasePath(const QString& basePath){
@ -31,6 +33,10 @@ void {{classname}}::setHost(const QString& host){
this->host = host;
}
void {{classname}}::setApiTimeOutMs(const int tout){
timeout = tout;
}
void {{classname}}::addHeaders(const QString& key, const QString& value){
defaultHeaders.insert(key, value);
}
@ -97,6 +103,7 @@ void
}
{{/collectionFormat}}{{/queryParams}}
{{prefix}}HttpRequestWorker *worker = new {{prefix}}HttpRequestWorker();
worker->setTimeOut(timeout);
{{prefix}}HttpRequestInput input(fullPath, "{{httpMethod}}");
{{#formParams}}
if ({{paramName}} != nullptr) {

View File

@ -18,11 +18,12 @@ class {{classname}}: public QObject {
public:
{{classname}}();
{{classname}}(const QString& host, const QString& basePath);
{{classname}}(const QString& host, const QString& basePath, const int toutMs = 0);
~{{classname}}();
void setBasePath(const QString& basePath);
void setHost(const QString& host);
void setApiTimeOutMs(const int tout);
void addHeaders(const QString& key, const QString& value);
{{#operations}}{{#operation}}void {{nickname}}({{#allParams}}const {{{dataType}}}& {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}});
@ -30,6 +31,7 @@ public:
private:
QString basePath;
QString host;
int timeout;
QMap<QString, QString> defaultHeaders;
{{#operations}}{{#operation}}void {{nickname}}Callback ({{prefix}}HttpRequestWorker * worker);
{{/operation}}{{/operations}}

View File

@ -54,18 +54,29 @@ OAIHttpRequestWorker::OAIHttpRequestWorker(QObject *parent)
: QObject(parent), manager(nullptr)
{
qsrand(QDateTime::currentDateTime().toTime_t());
timeout = 0;
timer = new QTimer();
manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &OAIHttpRequestWorker::on_manager_finished);
}
OAIHttpRequestWorker::~OAIHttpRequestWorker() {
if(timer != nullptr){
if(timer->isActive()){
timer->stop();
}
timer->deleteLater();
}
}
QMap<QByteArray, QByteArray> OAIHttpRequestWorker::getResponseHeaders() const {
return headers;
}
void OAIHttpRequestWorker::setTimeOut(int tout){
timeout = tout;
}
QString OAIHttpRequestWorker::http_attribute_encode(QString attribute_name, QString input) {
// result structure follows RFC 5987
bool need_utf_encoding = false;
@ -117,7 +128,7 @@ QString OAIHttpRequestWorker::http_attribute_encode(QString attribute_name, QStr
void OAIHttpRequestWorker::execute(OAIHttpRequestInput *input) {
// reset variables
QNetworkReply* reply = nullptr;
QByteArray request_content = "";
response = "";
error_type = QNetworkReply::NoError;
@ -285,19 +296,19 @@ void OAIHttpRequestWorker::execute(OAIHttpRequestInput *input) {
}
if (input->http_method == "GET") {
manager->get(request);
reply = manager->get(request);
}
else if (input->http_method == "POST") {
manager->post(request, request_content);
reply = manager->post(request, request_content);
}
else if (input->http_method == "PUT") {
manager->put(request, request_content);
reply = manager->put(request, request_content);
}
else if (input->http_method == "HEAD") {
manager->head(request);
reply = manager->head(request);
}
else if (input->http_method == "DELETE") {
manager->deleteResource(request);
reply = manager->deleteResource(request);
}
else {
#if (QT_VERSION >= 0x050800)
@ -307,11 +318,16 @@ void OAIHttpRequestWorker::execute(OAIHttpRequestInput *input) {
buffer->setData(request_content);
buffer->open(QIODevice::ReadOnly);
QNetworkReply* reply = manager->sendCustomRequest(request, input->http_method.toLatin1(), buffer);
reply = manager->sendCustomRequest(request, input->http_method.toLatin1(), buffer);
buffer->setParent(reply);
#endif
}
if(timeout > 0){
timer->setSingleShot(true);
timer->setInterval(timeout);
connect(timer, &QTimer::timeout, this, [=](){ on_manager_timeout(reply); });
timer->start();
}
}
void OAIHttpRequestWorker::on_manager_finished(QNetworkReply *reply) {
@ -327,6 +343,16 @@ void OAIHttpRequestWorker::on_manager_finished(QNetworkReply *reply) {
emit on_execution_finished(this);
}
void OAIHttpRequestWorker::on_manager_timeout(QNetworkReply *reply) {
error_type = QNetworkReply::TimeoutError;
response = "";
error_str = "Timed out waiting for response";
disconnect(manager, nullptr, nullptr, nullptr);
reply->abort();
reply->deleteLater();
emit on_execution_finished(this);
}
QSslConfiguration* OAIHttpRequestWorker::sslDefaultConfiguration;

View File

@ -21,6 +21,7 @@
#include <QObject>
#include <QString>
#include <QTimer>
#include <QMap>
#include <QNetworkAccessManager>
#include <QNetworkReply>
@ -69,7 +70,7 @@ public:
QByteArray response;
QNetworkReply::NetworkError error_type;
QString error_str;
QTimer *timer;
explicit OAIHttpRequestWorker(QObject *parent = nullptr);
virtual ~OAIHttpRequestWorker();
@ -77,16 +78,17 @@ public:
QString http_attribute_encode(QString attribute_name, QString input);
void execute(OAIHttpRequestInput *input);
static QSslConfiguration* sslDefaultConfiguration;
void setTimeOut(int tout);
signals:
void on_execution_finished(OAIHttpRequestWorker *worker);
private:
QNetworkAccessManager *manager;
QMap<QByteArray, QByteArray> headers;
int timeout;
void on_manager_timeout(QNetworkReply *reply);
private slots:
void on_manager_finished(QNetworkReply *reply);
void on_manager_finished(QNetworkReply *reply);
};
}

View File

@ -19,7 +19,8 @@
namespace OpenAPI {
OAIPetApi::OAIPetApi() : basePath("/v2"),
host("petstore.swagger.io") {
host("petstore.swagger.io"),
timeout(0){
}
@ -27,9 +28,10 @@ OAIPetApi::~OAIPetApi() {
}
OAIPetApi::OAIPetApi(const QString& host, const QString& basePath) {
OAIPetApi::OAIPetApi(const QString& host, const QString& basePath, const int tout) {
this->host = host;
this->basePath = basePath;
this->timeout = tout;
}
void OAIPetApi::setBasePath(const QString& basePath){
@ -40,6 +42,10 @@ void OAIPetApi::setHost(const QString& host){
this->host = host;
}
void OAIPetApi::setApiTimeOutMs(const int tout){
timeout = tout;
}
void OAIPetApi::addHeaders(const QString& key, const QString& value){
defaultHeaders.insert(key, value);
}
@ -51,6 +57,7 @@ OAIPetApi::addPet(const OAIPet& body) {
fullPath.append(this->host).append(this->basePath).append("/pet");
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "POST");
@ -102,6 +109,7 @@ OAIPetApi::deletePet(const qint64& pet_id, const QString& api_key) {
fullPath.replace(pet_idPathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(pet_id)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "DELETE");
if (api_key != nullptr) {
@ -189,6 +197,7 @@ OAIPetApi::findPetsByStatus(const QList<QString>& status) {
}
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "GET");
@ -283,6 +292,7 @@ OAIPetApi::findPetsByTags(const QList<QString>& tags) {
}
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "GET");
@ -340,6 +350,7 @@ OAIPetApi::getPetById(const qint64& pet_id) {
fullPath.replace(pet_idPathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(pet_id)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "GET");
@ -385,6 +396,7 @@ OAIPetApi::updatePet(const OAIPet& body) {
fullPath.append(this->host).append(this->basePath).append("/pet");
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "PUT");
@ -436,6 +448,7 @@ OAIPetApi::updatePetWithForm(const qint64& pet_id, const QString& name, const QS
fullPath.replace(pet_idPathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(pet_id)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "POST");
if (name != nullptr) {
input.add_var("name", name);
@ -489,6 +502,7 @@ OAIPetApi::uploadFile(const qint64& pet_id, const QString& additional_metadata,
fullPath.replace(pet_idPathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(pet_id)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "POST");
if (additional_metadata != nullptr) {
input.add_var("additionalMetadata", additional_metadata);

View File

@ -29,11 +29,12 @@ class OAIPetApi: public QObject {
public:
OAIPetApi();
OAIPetApi(const QString& host, const QString& basePath);
OAIPetApi(const QString& host, const QString& basePath, const int toutMs = 0);
~OAIPetApi();
void setBasePath(const QString& basePath);
void setHost(const QString& host);
void setApiTimeOutMs(const int tout);
void addHeaders(const QString& key, const QString& value);
void addPet(const OAIPet& body);
@ -48,6 +49,7 @@ public:
private:
QString basePath;
QString host;
int timeout;
QMap<QString, QString> defaultHeaders;
void addPetCallback (OAIHttpRequestWorker * worker);
void deletePetCallback (OAIHttpRequestWorker * worker);

View File

@ -19,7 +19,8 @@
namespace OpenAPI {
OAIStoreApi::OAIStoreApi() : basePath("/v2"),
host("petstore.swagger.io") {
host("petstore.swagger.io"),
timeout(0){
}
@ -27,9 +28,10 @@ OAIStoreApi::~OAIStoreApi() {
}
OAIStoreApi::OAIStoreApi(const QString& host, const QString& basePath) {
OAIStoreApi::OAIStoreApi(const QString& host, const QString& basePath, const int tout) {
this->host = host;
this->basePath = basePath;
this->timeout = tout;
}
void OAIStoreApi::setBasePath(const QString& basePath){
@ -40,6 +42,10 @@ void OAIStoreApi::setHost(const QString& host){
this->host = host;
}
void OAIStoreApi::setApiTimeOutMs(const int tout){
timeout = tout;
}
void OAIStoreApi::addHeaders(const QString& key, const QString& value){
defaultHeaders.insert(key, value);
}
@ -54,6 +60,7 @@ OAIStoreApi::deleteOrder(const QString& order_id) {
fullPath.replace(order_idPathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(order_id)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "DELETE");
@ -98,6 +105,7 @@ OAIStoreApi::getInventory() {
fullPath.append(this->host).append(this->basePath).append("/store/inventory");
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "GET");
@ -155,6 +163,7 @@ OAIStoreApi::getOrderById(const qint64& order_id) {
fullPath.replace(order_idPathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(order_id)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "GET");
@ -200,6 +209,7 @@ OAIStoreApi::placeOrder(const OAIOrder& body) {
fullPath.append(this->host).append(this->basePath).append("/store/order");
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "POST");

View File

@ -28,11 +28,12 @@ class OAIStoreApi: public QObject {
public:
OAIStoreApi();
OAIStoreApi(const QString& host, const QString& basePath);
OAIStoreApi(const QString& host, const QString& basePath, const int toutMs = 0);
~OAIStoreApi();
void setBasePath(const QString& basePath);
void setHost(const QString& host);
void setApiTimeOutMs(const int tout);
void addHeaders(const QString& key, const QString& value);
void deleteOrder(const QString& order_id);
@ -43,6 +44,7 @@ public:
private:
QString basePath;
QString host;
int timeout;
QMap<QString, QString> defaultHeaders;
void deleteOrderCallback (OAIHttpRequestWorker * worker);
void getInventoryCallback (OAIHttpRequestWorker * worker);

View File

@ -19,7 +19,8 @@
namespace OpenAPI {
OAIUserApi::OAIUserApi() : basePath("/v2"),
host("petstore.swagger.io") {
host("petstore.swagger.io"),
timeout(0){
}
@ -27,9 +28,10 @@ OAIUserApi::~OAIUserApi() {
}
OAIUserApi::OAIUserApi(const QString& host, const QString& basePath) {
OAIUserApi::OAIUserApi(const QString& host, const QString& basePath, const int tout) {
this->host = host;
this->basePath = basePath;
this->timeout = tout;
}
void OAIUserApi::setBasePath(const QString& basePath){
@ -40,6 +42,10 @@ void OAIUserApi::setHost(const QString& host){
this->host = host;
}
void OAIUserApi::setApiTimeOutMs(const int tout){
timeout = tout;
}
void OAIUserApi::addHeaders(const QString& key, const QString& value){
defaultHeaders.insert(key, value);
}
@ -51,6 +57,7 @@ OAIUserApi::createUser(const OAIUser& body) {
fullPath.append(this->host).append(this->basePath).append("/user");
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "POST");
@ -99,6 +106,7 @@ OAIUserApi::createUsersWithArrayInput(const QList<OAIUser>& body) {
fullPath.append(this->host).append(this->basePath).append("/user/createWithArray");
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "POST");
@ -148,6 +156,7 @@ OAIUserApi::createUsersWithListInput(const QList<OAIUser>& body) {
fullPath.append(this->host).append(this->basePath).append("/user/createWithList");
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "POST");
@ -200,6 +209,7 @@ OAIUserApi::deleteUser(const QString& username) {
fullPath.replace(usernamePathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(username)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "DELETE");
@ -247,6 +257,7 @@ OAIUserApi::getUserByName(const QString& username) {
fullPath.replace(usernamePathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(username)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "GET");
@ -308,6 +319,7 @@ OAIUserApi::loginUser(const QString& username, const QString& password) {
.append(QUrl::toPercentEncoding(::OpenAPI::toStringValue(password)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "GET");
@ -354,6 +366,7 @@ OAIUserApi::logoutUser() {
fullPath.append(this->host).append(this->basePath).append("/user/logout");
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "GET");
@ -401,6 +414,7 @@ OAIUserApi::updateUser(const QString& username, const OAIUser& body) {
fullPath.replace(usernamePathParam, QUrl::toPercentEncoding(::OpenAPI::toStringValue(username)));
OAIHttpRequestWorker *worker = new OAIHttpRequestWorker();
worker->setTimeOut(timeout);
OAIHttpRequestInput input(fullPath, "PUT");

View File

@ -28,11 +28,12 @@ class OAIUserApi: public QObject {
public:
OAIUserApi();
OAIUserApi(const QString& host, const QString& basePath);
OAIUserApi(const QString& host, const QString& basePath, const int toutMs = 0);
~OAIUserApi();
void setBasePath(const QString& basePath);
void setHost(const QString& host);
void setApiTimeOutMs(const int tout);
void addHeaders(const QString& key, const QString& value);
void createUser(const OAIUser& body);
@ -47,6 +48,7 @@ public:
private:
QString basePath;
QString host;
int timeout;
QMap<QString, QString> defaultHeaders;
void createUserCallback (OAIHttpRequestWorker * worker);
void createUsersWithArrayInputCallback (OAIHttpRequestWorker * worker);