Downloader.cpp
123 lines
| 4.0 KiB
| text/x-c
|
CppLexer
r0 | #include <Network/Downloader.h> | |||
#include <memory> | ||||
#include <QNetworkRequest> | ||||
#include <QNetworkReply> | ||||
#include <QNetworkAccessManager> | ||||
#include <QAuthenticator> | ||||
#include <QVariant> | ||||
#include <QHash> | ||||
#include <QPair> | ||||
#include <QCoreApplication> | ||||
#include <QReadWriteLock> | ||||
class Downloader::p_Downloader | ||||
{ | ||||
using login_pair=QPair<QString,QString>; | ||||
QNetworkAccessManager manager; | ||||
QHash<QString,login_pair> auth; | ||||
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; | ||||
} | ||||
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); | ||||
} | ||||
}; | ||||
QObject::connect(&manager, &QNetworkAccessManager::authenticationRequired, login_bambda); | ||||
} | ||||
Response get(const QString& url, const QString &user="", const QString &passwd="") | ||||
{ | ||||
QNetworkRequest request = buildRequest(url, user, passwd); | ||||
QNetworkReply *reply = manager.get(request); | ||||
while (!reply->isFinished()) | ||||
QCoreApplication::processEvents(); | ||||
QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); | ||||
Response resp = Response(reply->readAll(), status_code.toInt()); | ||||
delete reply; | ||||
if(user!="" and passwd!="") | ||||
auth.remove(url); | ||||
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); | ||||
auto callback_wrapper = [url, uuid, callback, this](){ | ||||
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()); | ||||
auth.remove(url); | ||||
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; | ||||
} | ||||
}; | ||||
Response Downloader::get(const QString &url, const QString &user, const QString &passwd) | ||||
{ | ||||
return Downloader::instance().impl->get(url, user, passwd); | ||||
} | ||||
QUuid Downloader::getAsync(const QString &url, std::function<void (QUuid ,Response)> callback, const QString &user, const QString &passwd) | ||||
{ | ||||
return Downloader::instance().impl->getAsync(url, callback, user, passwd); | ||||
} | ||||
bool Downloader::downloadFinished(QUuid uuid) | ||||
{ | ||||
return Downloader::instance().impl->downloadFinished(uuid); | ||||
} | ||||
Downloader::Downloader() | ||||
:impl(spimpl::make_unique_impl<p_Downloader>()) | ||||
{ | ||||
} | ||||