1 /*
2 * Copyright (c) 2023 Unionman Technology Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "JQNet.h"
17
18 // Qt lib import
19 #include <QEventLoop>
20 #include <QHostInfo>
21 #include <QTimer>
22 #include <QUrl>
23
24 // JQLibrary lib import
25 #ifdef JQFOUNDATION_LIB
26 #include "JQFoundation.h"
27 #endif
28
getNetworkAddressEntry()29 QNetworkAddressEntry JQNet::getNetworkAddressEntry()
30 {
31 return getNetworkAddressEntryWithNetworkInterface().first;
32 }
33
getNetworkAddressEntryWithNetworkInterface(const bool & ridVm)34 QPair<QNetworkAddressEntry, QNetworkInterface> JQNet::getNetworkAddressEntryWithNetworkInterface(const bool& ridVm)
35 {
36 for (const auto& interface : static_cast<const QList<QNetworkInterface>>(QNetworkInterface::allInterfaces())) {
37 if (interface.flags()
38 != (QNetworkInterface::IsUp | QNetworkInterface::IsRunning | QNetworkInterface::CanBroadcast
39 | QNetworkInterface::CanMulticast)) {
40 continue;
41 }
42
43 if (ridVm && interface.humanReadableName().startsWith("vm")) {
44 continue;
45 }
46
47 for (const auto& entry : static_cast<QList<QNetworkAddressEntry>>(interface.addressEntries())) {
48 entry.ip().toIPv6Address();
49 }
50 }
51
52 return {};
53 }
54
getHostName()55 QString JQNet::getHostName()
56 {
57 #if (defined Q_OS_MAC)
58 return QHostInfo::localHostName().replace(".local", "");
59 #else
60 return QHostInfo::localHostName();
61 #endif
62 }
63
64 #ifdef JQFOUNDATION_LIB
pingIp(const QHostAddress & hostAddress)65 bool JQNet::pingIp(const QHostAddress& hostAddress)
66 {
67 QPair<int, QByteArray> pingResult = { -1, {} };
68
69 #ifdef Q_OS_MAC
70 pingResult = JQFoundation::startProcessAndReadOutput("ping", { "-c1", "-W300", hostAddress.toString() });
71 #endif
72
73 #ifdef Q_OS_WIN
74 pingResult = JQFoundation::startProcessAndReadOutput("ping", { "-n", "1", "-w", "300", hostAddress.toString() });
75 #endif
76
77 return (pingResult.first == 0) && (pingResult.second.size() > 20L)
78 && (pingResult.second.count(hostAddress.toString().toUtf8()) > 1);
79 }
80 #endif
81
82 // HTTP
get(const QNetworkRequest & request,QByteArray & target,const int & timeout)83 bool JQNet::HTTP::get(const QNetworkRequest& request, QByteArray& target, const int& timeout)
84 {
85 target.clear();
86
87 QEventLoop eventLoop;
88 auto reply = manage_.get(request);
89 bool failFlag = false;
90
91 this->handle(
92 reply, timeout,
93 [&](const QByteArray& data) {
94 target = data;
95 eventLoop.exit(1);
96 },
97 [&](const QNetworkReply::NetworkError&, const QByteArray& data) {
98 target = data;
99 eventLoop.exit(0);
100 },
101 [&]() {
102 failFlag = true;
103 eventLoop.exit(0);
104 });
105
106 return eventLoop.exec() && !failFlag;
107 }
108
get(const QNetworkRequest & request,const std::function<void (const QByteArray &)> & onFinished,const std::function<void (const QNetworkReply::NetworkError &,const QByteArray &)> & onError,const int & timeout)109 void JQNet::HTTP::get(const QNetworkRequest& request, const std::function<void(const QByteArray&)>& onFinished,
110 const std::function<void(const QNetworkReply::NetworkError&, const QByteArray&)>& onError, const int& timeout)
111 {
112 auto reply = manage_.get(request);
113
114 this->handle(reply, timeout, onFinished, onError, [onError]() { onError(QNetworkReply::TimeoutError, {}); });
115 }
116
deleteResource(const QNetworkRequest & request,QByteArray & target,const int & timeout)117 bool JQNet::HTTP::deleteResource(const QNetworkRequest& request, QByteArray& target, const int& timeout)
118 {
119 target.clear();
120
121 QEventLoop eventLoop;
122 auto reply = manage_.deleteResource(request);
123 bool failFlag = false;
124
125 this->handle(
126 reply, timeout,
127 [&](const QByteArray& data) {
128 target = data;
129 eventLoop.exit(1);
130 },
131 [&](const QNetworkReply::NetworkError&, const QByteArray& data) {
132 target = data;
133 eventLoop.exit(0);
134 },
135 [&]() {
136 failFlag = true;
137 eventLoop.exit(0);
138 });
139
140 return eventLoop.exec() && !failFlag;
141 }
142
deleteResource(const QNetworkRequest & request,const std::function<void (const QByteArray &)> & onFinished,const std::function<void (const QNetworkReply::NetworkError &,const QByteArray &)> & onError,const int & timeout)143 void JQNet::HTTP::deleteResource(const QNetworkRequest& request,
144 const std::function<void(const QByteArray&)>& onFinished,
145 const std::function<void(const QNetworkReply::NetworkError&, const QByteArray&)>& onError, const int& timeout)
146 {
147 auto reply = manage_.deleteResource(request);
148
149 this->handle(reply, timeout, onFinished, onError, [onError]() { onError(QNetworkReply::TimeoutError, {}); });
150 }
151
post(const QNetworkRequest & request,const QByteArray & body,QByteArray & target,const int & timeout)152 bool JQNet::HTTP::post(const QNetworkRequest& request, const QByteArray& body, QByteArray& target, const int& timeout)
153 {
154 target.clear();
155
156 QEventLoop eventLoop;
157 auto reply = manage_.post(request, body);
158 bool failFlag = false;
159
160 this->handle(
161 reply, timeout,
162 [&target, &eventLoop](const QByteArray& data) {
163 target = data;
164 eventLoop.exit(true);
165 },
166 [&target, &eventLoop](const QNetworkReply::NetworkError&, const QByteArray& data) {
167 target = data;
168 eventLoop.exit(false);
169 },
170 [&failFlag, &eventLoop]() {
171 failFlag = true;
172 eventLoop.exit(false);
173 });
174
175 return eventLoop.exec() && !failFlag;
176 }
177
post(const QNetworkRequest & request,const QSharedPointer<QHttpMultiPart> & multiPart,QByteArray & target,const int & timeout)178 bool JQNet::HTTP::post(const QNetworkRequest& request, const QSharedPointer<QHttpMultiPart>& multiPart,
179 QByteArray& target, const int& timeout)
180 {
181 target.clear();
182
183 QEventLoop eventLoop;
184 auto reply = manage_.post(request, multiPart.data());
185 bool failFlag = false;
186
187 this->handle(
188 reply, timeout,
189 [&target, &eventLoop](const QByteArray& data) {
190 target = data;
191 eventLoop.exit(true);
192 },
193 [&target, &eventLoop](const QNetworkReply::NetworkError&, const QByteArray& data) {
194 target = data;
195 eventLoop.exit(false);
196 },
197 [&failFlag, &eventLoop]() {
198 failFlag = true;
199 eventLoop.exit(false);
200 });
201
202 return eventLoop.exec() && !failFlag;
203 }
204
post(const QNetworkRequest & request,const QByteArray & body,const std::function<void (const QByteArray &)> & onFinished,const std::function<void (const QNetworkReply::NetworkError &,const QByteArray &)> & onError,const int & timeout)205 void JQNet::HTTP::post(const QNetworkRequest& request, const QByteArray& body,
206 const std::function<void(const QByteArray&)>& onFinished,
207 const std::function<void(const QNetworkReply::NetworkError&, const QByteArray&)>& onError, const int& timeout)
208 {
209 auto reply = manage_.post(request, body);
210
211 this->handle(reply, timeout, onFinished, onError, [onError]() { onError(QNetworkReply::TimeoutError, {}); });
212 }
213
put(const QNetworkRequest & request,const QByteArray & body,QByteArray & target,const int & timeout)214 bool JQNet::HTTP::put(const QNetworkRequest& request, const QByteArray& body, QByteArray& target, const int& timeout)
215 {
216 target.clear();
217
218 QEventLoop eventLoop;
219 auto reply = manage_.put(request, body);
220 bool failFlag = false;
221
222 this->handle(
223 reply, timeout,
224 [&target, &eventLoop](const QByteArray& data) {
225 target = data;
226 eventLoop.exit(true);
227 },
228 [&target, &eventLoop](const QNetworkReply::NetworkError&, const QByteArray& data) {
229 target = data;
230 eventLoop.exit(false);
231 },
232 [&failFlag, &eventLoop]() {
233 failFlag = true;
234 eventLoop.exit(false);
235 });
236
237 return eventLoop.exec() && !failFlag;
238 }
239
put(const QNetworkRequest & request,const QSharedPointer<QHttpMultiPart> & multiPart,QByteArray & target,const int & timeout)240 bool JQNet::HTTP::put(const QNetworkRequest& request, const QSharedPointer<QHttpMultiPart>& multiPart,
241 QByteArray& target, const int& timeout)
242 {
243 target.clear();
244
245 QEventLoop eventLoop;
246 auto reply = manage_.put(request, multiPart.data());
247 bool failFlag = false;
248
249 this->handle(
250 reply, timeout,
251 [&target, &eventLoop](const QByteArray& data) {
252 target = data;
253 eventLoop.exit(true);
254 },
255 [&target, &eventLoop](const QNetworkReply::NetworkError& e, const QByteArray& data) {
256 qDebug() << e;
257 target = data;
258 eventLoop.exit(false);
259 },
260 [&failFlag, &eventLoop]() {
261 failFlag = true;
262 eventLoop.exit(false);
263 });
264
265 return eventLoop.exec() && !failFlag;
266 }
267
put(const QNetworkRequest & request,const QByteArray & body,const std::function<void (const QByteArray &)> & onFinished,const std::function<void (const QNetworkReply::NetworkError &,const QByteArray &)> & onError,const int & timeout)268 void JQNet::HTTP::put(const QNetworkRequest& request, const QByteArray& body,
269 const std::function<void(const QByteArray&)>& onFinished,
270 const std::function<void(const QNetworkReply::NetworkError&, const QByteArray&)>& onError, const int& timeout)
271 {
272 auto reply = manage_.put(request, body);
273
274 this->handle(reply, timeout, onFinished, onError, [onError]() { onError(QNetworkReply::TimeoutError, {}); });
275 }
276
277 #if !(defined Q_OS_LINUX) && (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
patch(const QNetworkRequest & request,const QByteArray & body,QByteArray & target,const int & timeout)278 bool JQNet::HTTP::patch(const QNetworkRequest& request, const QByteArray& body, QByteArray& target, const int& timeout)
279 {
280 target.clear();
281
282 QEventLoop eventLoop;
283 auto reply = manage_.sendCustomRequest(request, "PATCH", body);
284 bool failFlag = false;
285
286 this->handle(
287 reply, timeout,
288 [&target, &eventLoop](const QByteArray& data) {
289 target = data;
290 eventLoop.exit(true);
291 },
292 [&target, &eventLoop](const QNetworkReply::NetworkError&, const QByteArray& data) {
293 target = data;
294 eventLoop.exit(false);
295 },
296 [&failFlag, &eventLoop]() {
297 failFlag = true;
298 eventLoop.exit(false);
299 });
300
301 return eventLoop.exec() && !failFlag;
302 }
303
patch(const QNetworkRequest & request,const QByteArray & body,const std::function<void (const QByteArray &)> & onFinished,const std::function<void (const QNetworkReply::NetworkError &,const QByteArray &)> & onError,const int & timeout)304 void JQNet::HTTP::patch(const QNetworkRequest& request, const QByteArray& body,
305 const std::function<void(const QByteArray&)>& onFinished,
306 const std::function<void(const QNetworkReply::NetworkError&, const QByteArray&)>& onError, const int& timeout)
307 {
308 auto reply = manage_.sendCustomRequest(request, "PATCH", body);
309
310 this->handle(reply, timeout, onFinished, onError, [onError]() { onError(QNetworkReply::TimeoutError, {}); });
311 }
312 #endif
313
get(const QString & url,const int & timeout)314 QPair<bool, QByteArray> JQNet::HTTP::get(const QString& url, const int& timeout)
315 {
316 QNetworkRequest networkRequest((QUrl(url)));
317 QByteArray buf;
318
319 const auto && flag = HTTP().get(networkRequest, buf, timeout);
320
321 return { flag, buf };
322 }
323
get(const QNetworkRequest & request,const int & timeout)324 QPair<bool, QByteArray> JQNet::HTTP::get(const QNetworkRequest& request, const int& timeout)
325 {
326 QByteArray buf;
327 HTTP http;
328
329 const auto && flag = http.get(request, buf, timeout);
330
331 return { flag, buf };
332 }
333
deleteResource(const QString & url,const int & timeout)334 QPair<bool, QByteArray> JQNet::HTTP::deleteResource(const QString& url, const int& timeout)
335 {
336 QNetworkRequest networkRequest((QUrl(url)));
337 QByteArray buf;
338
339 const auto && flag = HTTP().deleteResource(networkRequest, buf, timeout);
340
341 return { flag, buf };
342 }
343
deleteResource(const QNetworkRequest & request,const int & timeout)344 QPair<bool, QByteArray> JQNet::HTTP::deleteResource(const QNetworkRequest& request, const int& timeout)
345 {
346 QByteArray buf;
347 HTTP http;
348
349 const auto && flag = http.deleteResource(request, buf, timeout);
350
351 return { flag, buf };
352 }
353
post(const QString & url,const QByteArray & body,const int & timeout)354 QPair<bool, QByteArray> JQNet::HTTP::post(const QString& url, const QByteArray& body, const int& timeout)
355 {
356 QNetworkRequest networkRequest((QUrl(url)));
357 QByteArray buf;
358
359 networkRequest.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
360
361 const auto && flag = HTTP().post(networkRequest, body, buf, timeout);
362
363 return { flag, buf };
364 }
365
post(const QNetworkRequest & request,const QByteArray & body,const int & timeout)366 QPair<bool, QByteArray> JQNet::HTTP::post(const QNetworkRequest& request, const QByteArray& body, const int& timeout)
367 {
368 QByteArray buf;
369 HTTP http;
370
371 const auto && flag = http.post(request, body, buf, timeout);
372
373 return { flag, buf };
374 }
375
post(const QNetworkRequest & request,const QSharedPointer<QHttpMultiPart> & multiPart,const int & timeout)376 QPair<bool, QByteArray> JQNet::HTTP::post(
377 const QNetworkRequest& request, const QSharedPointer<QHttpMultiPart>& multiPart, const int& timeout)
378 {
379 QByteArray buf;
380 HTTP http;
381
382 const auto && flag = http.post(request, multiPart, buf, timeout);
383
384 return { flag, buf };
385 }
386
put(const QString & url,const QByteArray & body,const int & timeout)387 QPair<bool, QByteArray> JQNet::HTTP::put(const QString& url, const QByteArray& body, const int& timeout)
388 {
389 QNetworkRequest networkRequest((QUrl(url)));
390 QByteArray buf;
391
392 networkRequest.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
393
394 const auto && flag = HTTP().put(networkRequest, body, buf, timeout);
395
396 return { flag, buf };
397 }
398
put(const QNetworkRequest & request,const QByteArray & body,const int & timeout)399 QPair<bool, QByteArray> JQNet::HTTP::put(const QNetworkRequest& request, const QByteArray& body, const int& timeout)
400 {
401 QByteArray buf;
402 HTTP http;
403
404 const auto && flag = http.put(request, body, buf, timeout);
405
406 return { flag, buf };
407 }
408
put(const QNetworkRequest & request,const QSharedPointer<QHttpMultiPart> & multiPart,const int & timeout)409 QPair<bool, QByteArray> JQNet::HTTP::put(
410 const QNetworkRequest& request, const QSharedPointer<QHttpMultiPart>& multiPart, const int& timeout)
411 {
412 QByteArray buf;
413 HTTP http;
414
415 const auto && flag = http.put(request, multiPart, buf, timeout);
416
417 return { flag, buf };
418 }
419
420 #if !(defined Q_OS_LINUX) && (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
patch(const QString & url,const QByteArray & body,const int & timeout)421 QPair<bool, QByteArray> JQNet::HTTP::patch(const QString& url, const QByteArray& body, const int& timeout)
422 {
423 QNetworkRequest networkRequest((QUrl(url)));
424 QByteArray buf;
425
426 networkRequest.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
427
428 const auto && flag = HTTP().patch(networkRequest, body, buf, timeout);
429
430 return { flag, buf };
431 }
432
patch(const QNetworkRequest & request,const QByteArray & body,const int & timeout)433 QPair<bool, QByteArray> JQNet::HTTP::patch(const QNetworkRequest& request, const QByteArray& body, const int& timeout)
434 {
435 QByteArray buf;
436 HTTP http;
437
438 const auto && flag = http.patch(request, body, buf, timeout);
439
440 return { flag, buf };
441 }
442 #endif
443
handle(QNetworkReply * reply,const int & timeout,const std::function<void (const QByteArray &)> & onFinished,const std::function<void (const QNetworkReply::NetworkError &,const QByteArray & data)> & onError,const std::function<void ()> & onTimeout)444 void JQNet::HTTP::handle(QNetworkReply* reply, const int& timeout,
445 const std::function<void(const QByteArray&)>& onFinished,
446 const std::function<void(const QNetworkReply::NetworkError&, const QByteArray& data)>& onError,
447 const std::function<void()>& onTimeout)
448 {
449 QSharedPointer<bool> isCalled(new bool(false));
450
451 QTimer* timer = nullptr;
452 if (timeout) {
453 timer = new QTimer;
454 timer->setSingleShot(true);
455
456 QObject::connect(timer, &QTimer::timeout, [timer, onTimeout, isCalled]() {
457 if (*isCalled) {
458 return;
459 }
460 *isCalled = true;
461
462 onTimeout();
463 timer->deleteLater();
464 });
465 timer->start(timeout);
466 }
467
468 QObject::connect(reply, &QNetworkReply::finished, [reply, timer, onFinished, isCalled]() {
469 if (*isCalled) {
470 return;
471 }
472 *isCalled = true;
473
474 if (timer) {
475 timer->deleteLater();
476 }
477 const auto && acceptedData = reply->readAll();
478 onFinished(acceptedData);
479 });
480
481 #ifndef QT_NO_SSL
482 if (reply->url().toString().toLower().startsWith("https")) {
483 QObject::connect(reply,
484 static_cast<void (QNetworkReply::*)(const QList<QSslError>&)>(&QNetworkReply::sslErrors),
485 [reply](const QList<QSslError>& errors) {
486 qDebug() << "HTTP::handle: ignoreSslErrors:" << errors;
487 reply->ignoreSslErrors();
488 });
489 }
490 #endif
491
492 QObject::connect(reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
493 [reply, timer, onError, isCalled](const QNetworkReply::NetworkError& code) {
494 if (*isCalled) {
495 return;
496 }
497 *isCalled = true;
498
499 if (timer) {
500 timer->deleteLater();
501 }
502 const auto && acceptedData = reply->readAll();
503
504 onError(code, acceptedData);
505 });
506 }
507