Downloader.cpp
123 lines
| 4.0 KiB
| text/x-c
|
CppLexer
r1342 | #include <Network/Downloader.h> | |||
#include <memory> | ||||
#include <QNetworkRequest> | ||||
#include <QNetworkReply> | ||||
#include <QNetworkAccessManager> | ||||
#include <QAuthenticator> | ||||
#include <QVariant> | ||||
#include <QHash> | ||||
#include <QPair> | ||||
#include <QCoreApplication> | ||||
r1343 | #include <QReadWriteLock> | |||
r1342 | ||||
class Downloader::p_Downloader | ||||
{ | ||||
using login_pair=QPair<QString,QString>; | ||||
QNetworkAccessManager manager; | ||||
QHash<QString,login_pair> auth; | ||||
r1343 | QReadWriteLock pending_requests_lock; | |||
QHash<QUuid,QNetworkReply*> pending_requests; | ||||
QNetworkRequest buildRequest(const QString& url, const QString &user="", const QString &passwd="") | ||||
{ | ||||
QNetworkRequest request; | ||||
request.setUrl(QUrl(url)); | ||||
request.setRawHeader("User-Agent", "SciQLop 1.0"); | ||||
if(user!="" and passwd!="") | ||||
{ | ||||
//might grow quickly since we can have tons of URLs for the same host | ||||
auth[url]=login_pair(user,passwd); | ||||
QString login = "Basic "+user+":"+passwd; | ||||
request.setRawHeader("Authorization",login.toLocal8Bit()); | ||||
} | ||||
return request; | ||||
} | ||||
r1342 | ||||
public: | ||||
explicit p_Downloader() | ||||
{ | ||||
auto login_bambda = [this](QNetworkReply * reply, QAuthenticator * authenticator) | ||||
{ | ||||
if(auth.contains(reply->url().toString())) | ||||
{ | ||||
auto login = auth[reply->url().toString()]; | ||||
authenticator->setUser(login.first); | ||||
authenticator->setPassword(login.second); | ||||
} | ||||
}; | ||||
r1343 | ||||
r1342 | QObject::connect(&manager, &QNetworkAccessManager::authenticationRequired, login_bambda); | |||
} | ||||
Response get(const QString& url, const QString &user="", const QString &passwd="") | ||||
{ | ||||
r1343 | QNetworkRequest request = buildRequest(url, user, passwd); | |||
r1342 | QNetworkReply *reply = manager.get(request); | |||
while (!reply->isFinished()) | ||||
QCoreApplication::processEvents(); | ||||
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); | ||||
r1343 | Response resp = Response(reply->readAll(), status_code.toInt()); | |||
delete reply; | ||||
r1344 | if(user!="" and passwd!="") | |||
auth.remove(url); | ||||
r1343 | return resp; | |||
} | ||||
QUuid getAsync(const QString &url, std::function<void (QUuid ,Response)> callback, const QString &user, const QString &passwd) | ||||
{ | ||||
auto uuid = QUuid::createUuid(); | ||||
QNetworkRequest request = buildRequest(url, user, passwd); | ||||
QNetworkReply *reply = manager.get(request); | ||||
r1344 | auto callback_wrapper = [url, uuid, callback, this](){ | |||
r1343 | QNetworkReply* reply; | |||
{ | ||||
QWriteLocker locker(&pending_requests_lock); | ||||
reply = pending_requests.take(uuid); | ||||
} | ||||
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); | ||||
Response resp = Response(reply->readAll(), status_code.toInt()); | ||||
r1344 | auth.remove(url); | |||
r1343 | delete reply; | |||
callback(uuid, resp); | ||||
}; | ||||
QObject::connect(reply, &QNetworkReply::finished, callback_wrapper); | ||||
{ | ||||
QWriteLocker locker(&pending_requests_lock); | ||||
pending_requests[uuid] = reply; | ||||
} | ||||
return uuid; | ||||
} | ||||
bool downloadFinished(QUuid uuid) | ||||
{ | ||||
QReadLocker locker(&pending_requests_lock); | ||||
if(pending_requests.contains(uuid)) | ||||
{ | ||||
auto req = pending_requests[uuid]; | ||||
return req->isFinished(); | ||||
} | ||||
return true; | ||||
r1342 | } | |||
}; | ||||
r1343 | Response Downloader::get(const QString &url, const QString &user, const QString &passwd) | |||
r1342 | { | |||
r1343 | return Downloader::instance().impl->get(url, user, passwd); | |||
r1342 | } | |||
r1343 | QUuid Downloader::getAsync(const QString &url, std::function<void (QUuid ,Response)> callback, const QString &user, const QString &passwd) | |||
r1342 | { | |||
r1343 | return Downloader::instance().impl->getAsync(url, callback, user, passwd); | |||
} | ||||
bool Downloader::downloadFinished(QUuid uuid) | ||||
{ | ||||
return Downloader::instance().impl->downloadFinished(uuid); | ||||
r1342 | } | |||
Downloader::Downloader() | ||||
:impl(spimpl::make_unique_impl<p_Downloader>()) | ||||
{ | ||||
} | ||||