diff options
Diffstat (limited to 'app/src/httpclient.cpp')
-rw-r--r-- | app/src/httpclient.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/app/src/httpclient.cpp b/app/src/httpclient.cpp new file mode 100644 index 0000000..c9bad50 --- /dev/null +++ b/app/src/httpclient.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2018-2019 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "httpclient.h" + +#include <QDebug> +#include <QFile> +#include <QHash> +#include <QHttpMultiPart> +#include <QHttpPart> +#include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QUrlQuery> + +class HttpClientPrivate { + public: + HttpClientPrivate(const QString& url); + + QString url; + QUrlQuery params; + QHash<QString, QString> headers; + QNetworkAccessManager* manager; + + bool debug; + + enum HttpMethod { GET, POST, PUT, DELETE }; + + static QNetworkAccessManager* getManager(HttpClientPrivate* d, + bool* internal); + + static QNetworkRequest createRequest(HttpClientPrivate* d, HttpMethod method); + + static void get(HttpClientPrivate* d, + HttpMethod method, + std::function<void(const QString&)> successHandler, + std::function<void(const QString&)> errorHandler, + const char* encoding); + + static QString readReply(QNetworkReply* reply, + const char* encoding = "UTF-8"); + + static void handleFinish(bool debug, + const QString& successMessage, + const QString& errorMessage, + std::function<void(const QString&)> successHandler, + std::function<void(const QString&)> errorHandler, + QNetworkReply* reply, + QNetworkAccessManager* manager); +}; + +HttpClientPrivate::HttpClientPrivate(const QString& url) + : url(url), manager(NULL), debug(false) {} + +HttpClient::HttpClient(const QString& url) : d(new HttpClientPrivate(url)) {} + +HttpClient::~HttpClient() { + delete d; +} + +HttpClient& HttpClient::manager(QNetworkAccessManager* manager) { + d->manager = manager; + return *this; +} + +HttpClient& HttpClient::debug(bool debug) { + d->debug = debug; + return *this; +} + +HttpClient& HttpClient::param(const QString& name, const QString& value) { + d->params.addQueryItem(name, value); + return *this; +} + +HttpClient& HttpClient::header(const QString& header, const QString& value) { + d->headers[header] = value; + return *this; +} + +void HttpClient::get(std::function<void(const QString&)> successHandler, + std::function<void(const QString&)> errorHandler, + const char* encoding) { + HttpClientPrivate::get(d, HttpClientPrivate::GET, successHandler, + errorHandler, encoding); +} + +void HttpClient::download( + const QString& savePath, + std::function<void(const QString&)> successHandler, + std::function<void(const QString&)> errorHandler, + std::function<void(const qint64, const qint64)> progressHandler) { + bool debug = d->debug; + QFile* file = new QFile(savePath); + + if (file->open(QIODevice::WriteOnly)) { + download( + [=](const QByteArray& data) { file->write(data); }, + [=](const QString&) { + file->flush(); + file->close(); + file->deleteLater(); + + if (debug) { + qDebug().noquote() + << QString("download finished, save to: %1").arg(savePath); + } + + if (NULL != successHandler) { + successHandler( + QString("download finished, save to: %1").arg(savePath)); + } + }, + errorHandler, progressHandler); + } else { + if (debug) { + qDebug().noquote() << QString("open file error: %1").arg(savePath); + } + + if (NULL != errorHandler) { + errorHandler(QString("open file error: %1").arg(savePath)); + } + } +} + +void HttpClient::download( + std::function<void(const QByteArray&)> readyRead, + std::function<void(const QString&)> successHandler, + std::function<void(const QString&)> errorHandler, + std::function<void(const qint64, const qint64)> progressHandler) { + bool debug = d->debug; + bool internal; + + QNetworkAccessManager* manager = HttpClientPrivate::getManager(d, &internal); + QNetworkRequest request = + HttpClientPrivate::createRequest(d, HttpClientPrivate::GET); + QNetworkReply* reply = manager->get(request); + + QObject::connect(reply, &QNetworkReply::readyRead, + [=] { readyRead(reply->readAll()); }); + + QObject::connect(reply, &QNetworkReply::finished, [=] { + QString successMessage = "download finished"; + QString errorMessage = reply->errorString(); + HttpClientPrivate::handleFinish(debug, successMessage, errorMessage, + successHandler, errorHandler, reply, + internal ? manager : NULL); + }); + + QObject::connect(reply, &QNetworkReply::downloadProgress, + [=](qint64 bytesReceived, qint64 bytesTotal) { + if (NULL != progressHandler) { + progressHandler(bytesReceived, bytesTotal); + } + }); +} + +void HttpClientPrivate::get(HttpClientPrivate* d, + HttpMethod method, + std::function<void(const QString&)> successHandler, + std::function<void(const QString&)> errorHandler, + const char* encoding) { + bool internal; + + QNetworkAccessManager* manager = HttpClientPrivate::getManager(d, &internal); + QNetworkRequest request = + HttpClientPrivate::createRequest(d, HttpClientPrivate::GET); + QNetworkReply* reply = NULL; + + switch (method) { + case HttpClientPrivate::GET: + reply = manager->get(request); + break; + + default: + break; + } + + QObject::connect(reply, &QNetworkReply::finished, [=] { + QString successMessage = HttpClientPrivate::readReply(reply, encoding); + QString errorMessage = reply->errorString(); + HttpClientPrivate::handleFinish(d->debug, successMessage, errorMessage, + successHandler, errorHandler, reply, + internal ? manager : NULL); + }); +} + +QNetworkAccessManager* HttpClientPrivate::getManager(HttpClientPrivate* d, + bool* internal) { + *internal = d->manager == NULL; + return *internal ? new QNetworkAccessManager() : d->manager; +} + +QNetworkRequest HttpClientPrivate::createRequest(HttpClientPrivate* d, + HttpMethod method) { + if (!d->params.isEmpty()) { + d->url += "?" + d->params.toString(QUrl::FullyEncoded); + } + + if (d->debug) { + qDebug().noquote() << "url:" << d->url; + + QList<QPair<QString, QString> > paramItems = d->params.queryItems(); + for (int i = 0; i < paramItems.size(); ++i) { + QString name = paramItems.at(i).first; + QString value = paramItems.at(i).second; + if (0 == i) { + qDebug().noquote() << QString("params: %1=%2").arg(name).arg(value); + } else { + qDebug().noquote() << QString(" %1=%2").arg(name).arg(value); + } + } + } + + QNetworkRequest request(QUrl(d->url)); + QHashIterator<QString, QString> iter(d->headers); + while (iter.hasNext()) { + iter.next(); + request.setRawHeader(iter.key().toUtf8(), iter.value().toUtf8()); + } + + return request; +} + +QString HttpClientPrivate::readReply(QNetworkReply* reply, + const char* encoding) { + QTextStream in(reply); + QString result; + in.setCodec(encoding); + + while (!in.atEnd()) { + result += in.readLine(); + } + + return result; +} + +void HttpClientPrivate::handleFinish( + bool debug, + const QString& successMessage, + const QString& errorMessage, + std::function<void(const QString&)> successHandler, + std::function<void(const QString&)> errorHandler, + QNetworkReply* reply, + QNetworkAccessManager* manager) { + if (reply->error() == QNetworkReply::NoError) { + if (debug) { + qDebug().noquote() + << QString("request successed: %1").arg(successMessage); + } + + if (NULL != successHandler) { + successHandler(successMessage); + } + } else { + if (debug) { + qDebug().noquote() << QString("request failed: %1").arg(errorMessage); + } + + if (NULL != errorHandler) { + errorHandler(errorMessage); + } + } + + reply->deleteLater(); + if (NULL != manager) { + manager->deleteLater(); + } +} |