mirror of https://github.com/kiwix/libkiwix.git
Add a Download class to encapsulate a aria2 download.
This commit is contained in:
parent
f718c4c472
commit
43ff8565d1
|
@ -21,6 +21,8 @@
|
||||||
#define KIWIX_DOWNLOADER_H
|
#define KIWIX_DOWNLOADER_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -40,6 +42,41 @@ class AriaError : public std::runtime_error {
|
||||||
AriaError(const std::string& message) : std::runtime_error(message) {}
|
AriaError(const std::string& message) : std::runtime_error(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Download {
|
||||||
|
public:
|
||||||
|
typedef enum { ACTIVE, WAITING, PAUSED, ERROR, COMPLETE, REMOVED, UNKNOWN } StatusResult;
|
||||||
|
|
||||||
|
Download() :
|
||||||
|
m_status(UNKNOWN) {}
|
||||||
|
Download(std::shared_ptr<Aria2> p_aria, std::string did)
|
||||||
|
: mp_aria(p_aria),
|
||||||
|
m_status(UNKNOWN),
|
||||||
|
m_did(did) {};
|
||||||
|
void updateStatus(bool follow=false);
|
||||||
|
StatusResult getStatus() { return m_status; }
|
||||||
|
std::string getDid() { return m_did; }
|
||||||
|
std::string getFollowedBy() { return m_followedBy; }
|
||||||
|
uint64_t getTotalLength() { return m_totalLength; }
|
||||||
|
uint64_t getCompletedLength() { return m_completedLength; }
|
||||||
|
uint64_t getDownloadSpeed() { return m_downloadSpeed; }
|
||||||
|
uint64_t getVerifiedLength() { return m_verifiedLength; }
|
||||||
|
std::string getPath() { return m_path; }
|
||||||
|
std::vector<std::string>& getUris() { return m_uris; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<Aria2> mp_aria;
|
||||||
|
StatusResult m_status;
|
||||||
|
std::string m_did = "";
|
||||||
|
std::string m_followedBy = "";
|
||||||
|
uint64_t m_totalLength;
|
||||||
|
uint64_t m_completedLength;
|
||||||
|
uint64_t m_downloadSpeed;
|
||||||
|
uint64_t m_verifiedLength;
|
||||||
|
std::vector<std::string> m_uris;
|
||||||
|
std::string m_path;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tool to download things.
|
* A tool to download things.
|
||||||
*
|
*
|
||||||
|
@ -60,9 +97,15 @@ class Downloader
|
||||||
*/
|
*/
|
||||||
DownloadedFile download(const std::string& url);
|
DownloadedFile download(const std::string& url);
|
||||||
|
|
||||||
private:
|
Download* startDownload(const std::string& uri);
|
||||||
|
Download* getDownload(const std::string& did);
|
||||||
|
|
||||||
std::unique_ptr<Aria2> mp_aria;
|
size_t getNbDownload() { return m_knownDownloads.size(); }
|
||||||
|
std::vector<std::string> getDownloadIds();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::unique_ptr<Download>> m_knownDownloads;
|
||||||
|
std::shared_ptr<Aria2> mp_aria;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "downloader.h"
|
#include "downloader.h"
|
||||||
#include "common/pathTools.h"
|
#include "common/pathTools.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
@ -33,10 +34,73 @@
|
||||||
namespace kiwix
|
namespace kiwix
|
||||||
{
|
{
|
||||||
|
|
||||||
|
void Download::updateStatus(bool follow)
|
||||||
|
{
|
||||||
|
static std::vector<std::string> statusKey = {"status", "files", "totalLength",
|
||||||
|
"completedLength", "followedBy",
|
||||||
|
"downloadSpeed", "verifiedLength"};
|
||||||
|
std::string strStatus;
|
||||||
|
if(follow && !m_followedBy.empty()) {
|
||||||
|
strStatus = mp_aria->tellStatus(m_followedBy, statusKey);
|
||||||
|
} else {
|
||||||
|
strStatus = mp_aria->tellStatus(m_did, statusKey);
|
||||||
|
}
|
||||||
|
// std::cout << strStatus << std::endl;
|
||||||
|
MethodResponse response(strStatus);
|
||||||
|
if (response.isFault()) {
|
||||||
|
m_status = Download::UNKNOWN;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto structNode = response.getParams().getParam(0).getValue().getStruct();
|
||||||
|
auto _status = structNode.getMember("status").getValue().getAsS();
|
||||||
|
auto status = _status == "active" ? Download::ACTIVE
|
||||||
|
: _status == "waiting" ? Download::WAITING
|
||||||
|
: _status == "paused" ? Download::PAUSED
|
||||||
|
: _status == "error" ? Download::ERROR
|
||||||
|
: _status == "complete" ? Download::COMPLETE
|
||||||
|
: _status == "removed" ? Download::REMOVED
|
||||||
|
: Download::UNKNOWN;
|
||||||
|
if (status == COMPLETE) {
|
||||||
|
try {
|
||||||
|
auto followedByMember = structNode.getMember("followedBy");
|
||||||
|
m_followedBy = followedByMember.getValue().getArray().getValue(0).getAsS();
|
||||||
|
if (follow) {
|
||||||
|
status = ACTIVE;
|
||||||
|
updateStatus(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (InvalidRPCNode& e) { }
|
||||||
|
}
|
||||||
|
m_status = status;
|
||||||
|
m_totalLength = std::stoull(structNode.getMember("totalLength").getValue().getAsS());
|
||||||
|
m_completedLength = std::stoull(structNode.getMember("completedLength").getValue().getAsS());
|
||||||
|
m_downloadSpeed = std::stoull(structNode.getMember("downloadSpeed").getValue().getAsS());
|
||||||
|
try {
|
||||||
|
auto verifiedLengthValue = structNode.getMember("verifiedLength").getValue();
|
||||||
|
m_verifiedLength = std::stoull(verifiedLengthValue.getAsS());
|
||||||
|
} catch (InvalidRPCNode& e) { m_verifiedLength = 0; }
|
||||||
|
auto filesMember = structNode.getMember("files");
|
||||||
|
auto fileStruct = filesMember.getValue().getArray().getValue(0).getStruct();
|
||||||
|
m_path = fileStruct.getMember("path").getValue().getAsS();
|
||||||
|
auto urisArray = fileStruct.getMember("uris").getValue().getArray();
|
||||||
|
int index = 0;
|
||||||
|
m_uris.clear();
|
||||||
|
while(true) {
|
||||||
|
try {
|
||||||
|
auto uriNode = urisArray.getValue(index++).getStruct().getMember("uri");
|
||||||
|
m_uris.push_back(uriNode.getValue().getAsS());
|
||||||
|
} catch(InvalidRPCNode& e) { break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Constructor */
|
/* Constructor */
|
||||||
Downloader::Downloader() :
|
Downloader::Downloader() :
|
||||||
mp_aria(new Aria2())
|
mp_aria(new Aria2())
|
||||||
{
|
{
|
||||||
|
for (auto gid : mp_aria->tellActive()) {
|
||||||
|
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
|
||||||
|
m_knownDownloads[gid]->updateStatus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,39 +114,29 @@ void Downloader::close()
|
||||||
mp_aria->close();
|
mp_aria->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pugi::xml_node find_member_in_struct(pugi::xml_node struct_node, std::string member_name) {
|
std::vector<std::string> Downloader::getDownloadIds() {
|
||||||
for(auto member=struct_node.first_child(); member; member=member.next_sibling()) {
|
std::vector<std::string> ret;
|
||||||
std::string _member_name = member.child("name").text().get();
|
for(auto& p:m_knownDownloads) {
|
||||||
if (_member_name == member_name) {
|
ret.push_back(p.first);
|
||||||
return member.child("value");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pugi::xml_node();
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadedFile Downloader::download(const std::string& url) {
|
DownloadedFile Downloader::download(const std::string& url) {
|
||||||
DownloadedFile fileHandle;
|
DownloadedFile fileHandle;
|
||||||
try {
|
try {
|
||||||
std::vector<std::string> uris = {url};
|
|
||||||
std::vector<std::string> status_key = {"status", "files"};
|
std::vector<std::string> status_key = {"status", "files"};
|
||||||
std::string gid;
|
auto download = startDownload(url);
|
||||||
|
std::cerr << "gid is : " << download->getDid() << std::endl;
|
||||||
gid = mp_aria->addUri(uris);
|
|
||||||
std::cerr << "gid is : " << gid << std::endl;
|
|
||||||
pugi::xml_document ret;
|
pugi::xml_document ret;
|
||||||
while(true) {
|
while(true) {
|
||||||
auto strStatus = mp_aria->tellStatus(gid, status_key);
|
download->updateStatus();
|
||||||
MethodResponse response(strStatus);
|
std::cerr << "Status is " << download->getStatus() << std::endl;
|
||||||
auto structNode = response.getParams().getParam(0).getValue().getStruct();
|
if (download->getStatus() == Download::COMPLETE) {
|
||||||
auto status = structNode.getMember("status").getValue().getAsS();
|
|
||||||
std::cerr << "Status is " << status << std::endl;
|
|
||||||
if (status == "complete") {
|
|
||||||
fileHandle.success = true;
|
fileHandle.success = true;
|
||||||
auto filesMember = structNode.getMember("files");
|
fileHandle.path = download->getPath();
|
||||||
auto fileStruct = filesMember.getValue().getArray().getValue(0).getStruct();
|
|
||||||
fileHandle.path = fileStruct.getMember("path").getValue().getAsS();
|
|
||||||
std::cerr << "FilePath is " << fileHandle.path << std::endl;
|
std::cerr << "FilePath is " << fileHandle.path << std::endl;
|
||||||
} else if (status == "error") {
|
} else if (download->getStatus() == Download::ERROR) {
|
||||||
fileHandle.success = false;
|
fileHandle.success = false;
|
||||||
} else {
|
} else {
|
||||||
// [TODO] Be wise here.
|
// [TODO] Be wise here.
|
||||||
|
@ -95,4 +149,33 @@ DownloadedFile Downloader::download(const std::string& url) {
|
||||||
return fileHandle;
|
return fileHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Download* Downloader::startDownload(const std::string& uri)
|
||||||
|
{
|
||||||
|
for (auto& p: m_knownDownloads) {
|
||||||
|
auto& d = p.second;
|
||||||
|
auto& uris = d->getUris();
|
||||||
|
if (std::find(uris.begin(), uris.end(), uri) != uris.end())
|
||||||
|
return d.get();
|
||||||
|
}
|
||||||
|
std::vector<std::string> uris = {uri};
|
||||||
|
auto gid = mp_aria->addUri(uris);
|
||||||
|
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
|
||||||
|
return m_knownDownloads[gid].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Download* Downloader::getDownload(const std::string& did)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return m_knownDownloads.at(did).get();
|
||||||
|
} catch(exception& e) {
|
||||||
|
for (auto gid : mp_aria->tellActive()) {
|
||||||
|
if (gid == did) {
|
||||||
|
m_knownDownloads[gid] = std::unique_ptr<Download>(new Download(mp_aria, gid));
|
||||||
|
return m_knownDownloads[gid].get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue