@@ -10,14 +10,16 | |||||
10 |
|
10 | |||
11 | #include <QString> |
|
11 | #include <QString> | |
12 | #include <QByteArray> |
|
12 | #include <QByteArray> | |
|
13 | #include <QUuid> | |||
13 |
|
14 | |||
14 | /** |
|
15 | /** | |
15 | * @brief The Downloader handles all data donwloads in SciQLOP. |
|
16 | * @brief The Downloader handles all data donwloads in SciQLOP. | |
16 | */ |
|
17 | */ | |
17 | class SCIQLOP_CORE_EXPORT Downloader{ |
|
18 | class SCIQLOP_CORE_EXPORT Downloader{ | |
18 | public: |
|
19 | public: | |
19 | static Response get(const QString& url); |
|
20 | static Response get(const QString& url, const QString& user="", const QString& passwd=""); | |
20 |
static |
|
21 | static QUuid getAsync(const QString& url, std::function<void (QUuid, Response)> callback, const QString& user="", const QString& passwd=""); | |
|
22 | static bool downloadFinished(QUuid uuid); | |||
21 |
|
23 | |||
22 | static Downloader& instance() |
|
24 | static Downloader& instance() | |
23 | { |
|
25 | { |
@@ -9,12 +9,30 | |||||
9 | #include <QHash> |
|
9 | #include <QHash> | |
10 | #include <QPair> |
|
10 | #include <QPair> | |
11 | #include <QCoreApplication> |
|
11 | #include <QCoreApplication> | |
|
12 | #include <QReadWriteLock> | |||
12 |
|
13 | |||
13 | class Downloader::p_Downloader |
|
14 | class Downloader::p_Downloader | |
14 | { |
|
15 | { | |
15 | using login_pair=QPair<QString,QString>; |
|
16 | using login_pair=QPair<QString,QString>; | |
16 | QNetworkAccessManager manager; |
|
17 | QNetworkAccessManager manager; | |
17 | QHash<QString,login_pair> auth; |
|
18 | QHash<QString,login_pair> auth; | |
|
19 | QReadWriteLock pending_requests_lock; | |||
|
20 | QHash<QUuid,QNetworkReply*> pending_requests; | |||
|
21 | ||||
|
22 | QNetworkRequest buildRequest(const QString& url, const QString &user="", const QString &passwd="") | |||
|
23 | { | |||
|
24 | QNetworkRequest request; | |||
|
25 | request.setUrl(QUrl(url)); | |||
|
26 | request.setRawHeader("User-Agent", "SciQLop 1.0"); | |||
|
27 | if(user!="" and passwd!="") | |||
|
28 | { | |||
|
29 | //might grow quickly since we can have tons of URLs for the same host | |||
|
30 | auth[url]=login_pair(user,passwd); | |||
|
31 | QString login = "Basic "+user+":"+passwd; | |||
|
32 | request.setRawHeader("Authorization",login.toLocal8Bit()); | |||
|
33 | } | |||
|
34 | return request; | |||
|
35 | } | |||
18 |
|
36 | |||
19 | public: |
|
37 | public: | |
20 | explicit p_Downloader() |
|
38 | explicit p_Downloader() | |
@@ -29,37 +47,70 public: | |||||
29 | authenticator->setPassword(login.second); |
|
47 | authenticator->setPassword(login.second); | |
30 | } |
|
48 | } | |
31 | }; |
|
49 | }; | |
|
50 | ||||
32 | QObject::connect(&manager, &QNetworkAccessManager::authenticationRequired, login_bambda); |
|
51 | QObject::connect(&manager, &QNetworkAccessManager::authenticationRequired, login_bambda); | |
33 | } |
|
52 | } | |
34 |
|
53 | |||
35 | Response get(const QString& url, const QString &user="", const QString &passwd="") |
|
54 | Response get(const QString& url, const QString &user="", const QString &passwd="") | |
36 | { |
|
55 | { | |
37 | QNetworkRequest request; |
|
56 | QNetworkRequest request = buildRequest(url, user, passwd); | |
38 | request.setUrl(QUrl(url)); |
|
|||
39 | request.setRawHeader("User-Agent", "SciQLop 1.0"); |
|
|||
40 | if(user!="" and passwd!="") |
|
|||
41 | { |
|
|||
42 | //might grow quickly since we can have tons of URLs for the same host |
|
|||
43 | auth[url]=login_pair(user,passwd); |
|
|||
44 | QString login = "Basic "+user+":"+passwd; |
|
|||
45 | request.setRawHeader("Authorization",login.toLocal8Bit()); |
|
|||
46 | } |
|
|||
47 | QNetworkReply *reply = manager.get(request); |
|
57 | QNetworkReply *reply = manager.get(request); | |
48 | while (!reply->isFinished()) |
|
58 | while (!reply->isFinished()) | |
49 | QCoreApplication::processEvents(); |
|
59 | QCoreApplication::processEvents(); | |
50 | QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); |
|
60 | QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); | |
51 |
|
|
61 | Response resp = Response(reply->readAll(), status_code.toInt()); | |
|
62 | delete reply; | |||
|
63 | return resp; | |||
|
64 | } | |||
|
65 | ||||
|
66 | QUuid getAsync(const QString &url, std::function<void (QUuid ,Response)> callback, const QString &user, const QString &passwd) | |||
|
67 | { | |||
|
68 | auto uuid = QUuid::createUuid(); | |||
|
69 | QNetworkRequest request = buildRequest(url, user, passwd); | |||
|
70 | QNetworkReply *reply = manager.get(request); | |||
|
71 | auto callback_wrapper = [uuid, callback, this](){ | |||
|
72 | QNetworkReply* reply; | |||
|
73 | { | |||
|
74 | QWriteLocker locker(&pending_requests_lock); | |||
|
75 | reply = pending_requests.take(uuid); | |||
|
76 | } | |||
|
77 | QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); | |||
|
78 | Response resp = Response(reply->readAll(), status_code.toInt()); | |||
|
79 | delete reply; | |||
|
80 | callback(uuid, resp); | |||
|
81 | }; | |||
|
82 | QObject::connect(reply, &QNetworkReply::finished, callback_wrapper); | |||
|
83 | { | |||
|
84 | QWriteLocker locker(&pending_requests_lock); | |||
|
85 | pending_requests[uuid] = reply; | |||
|
86 | } | |||
|
87 | return uuid; | |||
|
88 | } | |||
|
89 | bool downloadFinished(QUuid uuid) | |||
|
90 | { | |||
|
91 | QReadLocker locker(&pending_requests_lock); | |||
|
92 | if(pending_requests.contains(uuid)) | |||
|
93 | { | |||
|
94 | auto req = pending_requests[uuid]; | |||
|
95 | return req->isFinished(); | |||
|
96 | } | |||
|
97 | return true; | |||
52 | } |
|
98 | } | |
53 | }; |
|
99 | }; | |
54 |
|
100 | |||
55 | Response Downloader::get(const QString &url) |
|
101 | Response Downloader::get(const QString &url, const QString &user, const QString &passwd) | |
56 | { |
|
102 | { | |
57 | return Downloader::instance().impl->get(url); |
|
103 | return Downloader::instance().impl->get(url, user, passwd); | |
58 | } |
|
104 | } | |
59 |
|
105 | |||
60 |
|
|
106 | QUuid Downloader::getAsync(const QString &url, std::function<void (QUuid ,Response)> callback, const QString &user, const QString &passwd) | |
61 | { |
|
107 | { | |
62 | return Downloader::instance().impl->get(url, user, passwd); |
|
108 | return Downloader::instance().impl->getAsync(url, callback, user, passwd); | |
|
109 | } | |||
|
110 | ||||
|
111 | bool Downloader::downloadFinished(QUuid uuid) | |||
|
112 | { | |||
|
113 | return Downloader::instance().impl->downloadFinished(uuid); | |||
63 | } |
|
114 | } | |
64 |
|
115 | |||
65 | Downloader::Downloader() |
|
116 | Downloader::Downloader() |
@@ -22,6 +22,29 private slots: | |||||
22 | QCOMPARE(resp.data(), QString("{\n \"user-agent\": \"SciQLop 1.0\"\n}\n")); |
|
22 | QCOMPARE(resp.data(), QString("{\n \"user-agent\": \"SciQLop 1.0\"\n}\n")); | |
23 | } |
|
23 | } | |
24 |
|
24 | |||
|
25 | void simpleAsyncGet() | |||
|
26 | { | |||
|
27 | bool done = false; | |||
|
28 | int status = -1; | |||
|
29 | QByteArray data; | |||
|
30 | auto callback = [&done, &status, &data](QUuid uuid,Response resp) | |||
|
31 | { | |||
|
32 | status = resp.status_code(); | |||
|
33 | done = true; | |||
|
34 | data = resp.data(); | |||
|
35 | }; | |||
|
36 | auto uuid = Downloader::getAsync("http://ovh.net/files/1Mio.dat", callback); | |||
|
37 | QCOMPARE(Downloader::downloadFinished(uuid), false); | |||
|
38 | while (!done) | |||
|
39 | { | |||
|
40 | QCoreApplication::processEvents(); | |||
|
41 | } | |||
|
42 | QCOMPARE(Downloader::downloadFinished(uuid), true); | |||
|
43 | QCOMPARE(status, 200); | |||
|
44 | QCOMPARE(data[0],'\xBA'); | |||
|
45 | QCOMPARE(data[data.length()-1],'\x20'); | |||
|
46 | } | |||
|
47 | ||||
25 | void wrongUrl() |
|
48 | void wrongUrl() | |
26 | { |
|
49 | { | |
27 | auto resp = Downloader::get("https://lpp.polytechniqe2.fr"); |
|
50 | auto resp = Downloader::get("https://lpp.polytechniqe2.fr"); |
General Comments 0
You need to be logged in to leave comments.
Login now