warehouse for ces2019
[apps/onscreenapp.git] / app / src / httpclient.cpp
diff --git a/app/src/httpclient.cpp b/app/src/httpclient.cpp
new file mode 100644 (file)
index 0000000..490fd79
--- /dev/null
@@ -0,0 +1,267 @@
+
+#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();
+  }
+}