warehouse for ces2019
[apps/onscreenapp.git] / app / src / httpclient.cpp
1
2 #include "httpclient.h"
3
4 #include <QDebug>
5 #include <QFile>
6 #include <QHash>
7 #include <QHttpMultiPart>
8 #include <QHttpPart>
9 #include <QNetworkAccessManager>
10 #include <QNetworkReply>
11 #include <QNetworkRequest>
12 #include <QUrlQuery>
13
14 class HttpClientPrivate {
15  public:
16   HttpClientPrivate(const QString& url);
17
18   QString url;
19   QUrlQuery params;
20   QHash<QString, QString> headers;
21   QNetworkAccessManager* manager;
22
23   bool debug;
24
25   enum HttpMethod { GET, POST, PUT, DELETE };
26
27   static QNetworkAccessManager* getManager(HttpClientPrivate* d,
28                                            bool* internal);
29
30   static QNetworkRequest createRequest(HttpClientPrivate* d, HttpMethod method);
31
32   static void get(HttpClientPrivate* d,
33                   HttpMethod method,
34                   std::function<void(const QString&)> successHandler,
35                   std::function<void(const QString&)> errorHandler,
36                   const char* encoding);
37
38   static QString readReply(QNetworkReply* reply,
39                            const char* encoding = "UTF-8");
40
41   static void handleFinish(bool debug,
42                            const QString& successMessage,
43                            const QString& errorMessage,
44                            std::function<void(const QString&)> successHandler,
45                            std::function<void(const QString&)> errorHandler,
46                            QNetworkReply* reply,
47                            QNetworkAccessManager* manager);
48 };
49
50 HttpClientPrivate::HttpClientPrivate(const QString& url)
51     : url(url), manager(NULL), debug(false) {}
52
53 HttpClient::HttpClient(const QString& url) : d(new HttpClientPrivate(url)) {}
54
55 HttpClient::~HttpClient() {
56   delete d;
57 }
58
59 HttpClient& HttpClient::manager(QNetworkAccessManager* manager) {
60   d->manager = manager;
61   return *this;
62 }
63
64 HttpClient& HttpClient::debug(bool debug) {
65   d->debug = debug;
66   return *this;
67 }
68
69 HttpClient& HttpClient::param(const QString& name, const QString& value) {
70   d->params.addQueryItem(name, value);
71   return *this;
72 }
73
74 HttpClient& HttpClient::header(const QString& header, const QString& value) {
75   d->headers[header] = value;
76   return *this;
77 }
78
79 void HttpClient::get(std::function<void(const QString&)> successHandler,
80                      std::function<void(const QString&)> errorHandler,
81                      const char* encoding) {
82   HttpClientPrivate::get(d, HttpClientPrivate::GET, successHandler,
83                          errorHandler, encoding);
84 }
85
86 void HttpClient::download(
87     const QString& savePath,
88     std::function<void(const QString&)> successHandler,
89     std::function<void(const QString&)> errorHandler,
90     std::function<void(const qint64, const qint64)> progressHandler) {
91   bool debug = d->debug;
92   QFile* file = new QFile(savePath);
93
94   if (file->open(QIODevice::WriteOnly)) {
95     download(
96         [=](const QByteArray& data) { file->write(data); },
97         [=](const QString&) {
98           file->flush();
99           file->close();
100           file->deleteLater();
101
102           if (debug) {
103             qDebug().noquote()
104                 << QString("download finished, save to: %1").arg(savePath);
105           }
106
107           if (NULL != successHandler) {
108             successHandler(
109                 QString("download finished, save to: %1").arg(savePath));
110           }
111         },
112         errorHandler, progressHandler);
113   } else {
114     if (debug) {
115       qDebug().noquote() << QString("open file error: %1").arg(savePath);
116     }
117
118     if (NULL != errorHandler) {
119       errorHandler(QString("open file error: %1").arg(savePath));
120     }
121   }
122 }
123
124 void HttpClient::download(
125     std::function<void(const QByteArray&)> readyRead,
126     std::function<void(const QString&)> successHandler,
127     std::function<void(const QString&)> errorHandler,
128     std::function<void(const qint64, const qint64)> progressHandler) {
129   bool debug = d->debug;
130   bool internal;
131
132   QNetworkAccessManager* manager = HttpClientPrivate::getManager(d, &internal);
133   QNetworkRequest request =
134       HttpClientPrivate::createRequest(d, HttpClientPrivate::GET);
135   QNetworkReply* reply = manager->get(request);
136
137   QObject::connect(reply, &QNetworkReply::readyRead,
138                    [=] { readyRead(reply->readAll()); });
139
140   QObject::connect(reply, &QNetworkReply::finished, [=] {
141     QString successMessage = "download finished";
142     QString errorMessage = reply->errorString();
143     HttpClientPrivate::handleFinish(debug, successMessage, errorMessage,
144                                     successHandler, errorHandler, reply,
145                                     internal ? manager : NULL);
146   });
147
148   QObject::connect(reply, &QNetworkReply::downloadProgress,
149                    [=](qint64 bytesReceived, qint64 bytesTotal) {
150                      if (NULL != progressHandler) {
151                        progressHandler(bytesReceived, bytesTotal);
152                      }
153                    });
154 }
155
156 void HttpClientPrivate::get(HttpClientPrivate* d,
157                             HttpMethod method,
158                             std::function<void(const QString&)> successHandler,
159                             std::function<void(const QString&)> errorHandler,
160                             const char* encoding) {
161   bool internal;
162
163   QNetworkAccessManager* manager = HttpClientPrivate::getManager(d, &internal);
164   QNetworkRequest request =
165       HttpClientPrivate::createRequest(d, HttpClientPrivate::GET);
166   QNetworkReply* reply = NULL;
167
168   switch (method) {
169     case HttpClientPrivate::GET:
170       reply = manager->get(request);
171       break;
172
173     default:
174       break;
175   }
176
177   QObject::connect(reply, &QNetworkReply::finished, [=] {
178     QString successMessage = HttpClientPrivate::readReply(reply, encoding);
179     QString errorMessage = reply->errorString();
180     HttpClientPrivate::handleFinish(d->debug, successMessage, errorMessage,
181                                     successHandler, errorHandler, reply,
182                                     internal ? manager : NULL);
183   });
184 }
185
186 QNetworkAccessManager* HttpClientPrivate::getManager(HttpClientPrivate* d,
187                                                      bool* internal) {
188   *internal = d->manager == NULL;
189   return *internal ? new QNetworkAccessManager() : d->manager;
190 }
191
192 QNetworkRequest HttpClientPrivate::createRequest(HttpClientPrivate* d,
193                                                  HttpMethod method) {
194   if (!d->params.isEmpty()) {
195     d->url += "?" + d->params.toString(QUrl::FullyEncoded);
196   }
197
198   if (d->debug) {
199     qDebug().noquote() << "url:" << d->url;
200
201     QList<QPair<QString, QString> > paramItems = d->params.queryItems();
202     for (int i = 0; i < paramItems.size(); ++i) {
203       QString name = paramItems.at(i).first;
204       QString value = paramItems.at(i).second;
205       if (0 == i) {
206         qDebug().noquote() << QString("params: %1=%2").arg(name).arg(value);
207       } else {
208         qDebug().noquote() << QString("     %1=%2").arg(name).arg(value);
209       }
210     }
211   }
212
213   QNetworkRequest request(QUrl(d->url));
214   QHashIterator<QString, QString> iter(d->headers);
215   while (iter.hasNext()) {
216     iter.next();
217     request.setRawHeader(iter.key().toUtf8(), iter.value().toUtf8());
218   }
219
220   return request;
221 }
222
223 QString HttpClientPrivate::readReply(QNetworkReply* reply,
224                                      const char* encoding) {
225   QTextStream in(reply);
226   QString result;
227   in.setCodec(encoding);
228
229   while (!in.atEnd()) {
230     result += in.readLine();
231   }
232
233   return result;
234 }
235
236 void HttpClientPrivate::handleFinish(
237     bool debug,
238     const QString& successMessage,
239     const QString& errorMessage,
240     std::function<void(const QString&)> successHandler,
241     std::function<void(const QString&)> errorHandler,
242     QNetworkReply* reply,
243     QNetworkAccessManager* manager) {
244   if (reply->error() == QNetworkReply::NoError) {
245     if (debug) {
246       qDebug().noquote()
247           << QString("request successed: %1").arg(successMessage);
248     }
249
250     if (NULL != successHandler) {
251       successHandler(successMessage);
252     }
253   } else {
254     if (debug) {
255       qDebug().noquote() << QString("request failed: %1").arg(errorMessage);
256     }
257
258     if (NULL != errorHandler) {
259       errorHandler(errorMessage);
260     }
261   }
262
263   reply->deleteLater();
264   if (NULL != manager) {
265     manager->deleteLater();
266   }
267 }