2010-02-27 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Supported name attribute of metalink::metaurl element and
	multi-file torrent with Metalink4.  Files with same metaurl are
	grouped and downloaded in one RequestGroup.
	* src/BtDependency.cc
	* src/FileEntry.h
	* src/Metalink2RequestGroup.cc
	* src/Metalink2RequestGroup.h
	* src/MetalinkEntry.cc
	* src/MetalinkEntry.h
	* src/MetalinkHelper.cc
	* src/MetalinkHelper.h
	* src/MetalinkMetaurl.cc
	* src/MetalinkMetaurl.h
	* src/MetalinkParserController.cc
	* src/RequestGroup.cc
	* src/RequestGroup.h
	* src/bittorrent_helper.cc
	* test/BittorrentHelperTest.cc
	* test/BtDependencyTest.cc
	* test/MetalinkHelperTest.cc
pull/1/head
Tatsuhiro Tsujikawa 2010-02-26 15:37:08 +00:00
parent 5032394c6a
commit 2a6775e80b
18 changed files with 500 additions and 157 deletions

View File

@ -1,3 +1,26 @@
2010-02-27 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Supported name attribute of metalink::metaurl element and
multi-file torrent with Metalink4. Files with same metaurl are
grouped and downloaded in one RequestGroup.
* src/BtDependency.cc
* src/FileEntry.h
* src/Metalink2RequestGroup.cc
* src/Metalink2RequestGroup.h
* src/MetalinkEntry.cc
* src/MetalinkEntry.h
* src/MetalinkHelper.cc
* src/MetalinkHelper.h
* src/MetalinkMetaurl.cc
* src/MetalinkMetaurl.h
* src/MetalinkParserController.cc
* src/RequestGroup.cc
* src/RequestGroup.h
* src/bittorrent_helper.cc
* test/BittorrentHelperTest.cc
* test/BtDependencyTest.cc
* test/MetalinkHelperTest.cc
2010-02-26 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Store name attribute of metalink:metaurl element in MetalinkMetaurl.

View File

@ -47,6 +47,7 @@
#include "File.h"
#include "bittorrent_helper.h"
#include "DlAbortEx.h"
#include "StringFormat.h"
namespace aria2 {
@ -58,6 +59,18 @@ BtDependency::BtDependency(const RequestGroupWeakHandle& dependant,
BtDependency::~BtDependency() {}
static void copyValues(const SharedHandle<FileEntry>& d,
const SharedHandle<FileEntry>& s)
{
d->setRequested(true);
d->setPath(s->getPath());
d->addUris(s->getRemainingUris().begin(),
s->getRemainingUris().end());
if(!s->isSingleHostMultiConnectionEnabled()) {
d->disableSingleHostMultiConnection();
}
}
bool BtDependency::resolve()
{
if(_dependee->getNumCommand() == 0 && _dependee->downloadFinished()) {
@ -80,23 +93,38 @@ bool BtDependency::resolve()
bittorrent::loadFromMemory
(content, context, File(dependee->getFirstFilePath()).getBasename());
}
if(context->getFileEntries().size() !=
_dependant->getDownloadContext()->getFileEntries().size()) {
throw DL_ABORT_EX("The number of file in torrent doesn't match to"
" the dependent.");
}
const std::vector<SharedHandle<FileEntry> >& fileEntries =
context->getFileEntries();
const std::vector<SharedHandle<FileEntry> >& dependantFileEntries =
_dependant->getDownloadContext()->getFileEntries();
// If dependant's FileEntry::getOriginalName() is empty, we
// assume that torrent is single file. In Metalink3, this is
// always assumed.
if(fileEntries.size() == 1 && dependantFileEntries.size() == 1 &&
dependantFileEntries[0]->getOriginalName().empty()) {
copyValues(fileEntries[0], dependantFileEntries[0]);
} else {
std::for_each(fileEntries.begin(), fileEntries.end(),
std::bind2nd(mem_fun_sh(&FileEntry::setRequested),false));
// Copy file path in _dependant's FileEntries to newly created
// context's FileEntries to endorse the path structure of
// _dependant. URIs and singleHostMultiConnection are also copied.
for(std::vector<SharedHandle<FileEntry> >::const_iterator s =
_dependant->getDownloadContext()->getFileEntries().begin(),
d = context->getFileEntries().begin();
d != context->getFileEntries().end(); ++s, ++d) {
(*d)->setPath((*s)->getPath());
(*d)->addUris((*s)->getRemainingUris().begin(),
(*s)->getRemainingUris().end());
if(!(*s)->isSingleHostMultiConnectionEnabled()) {
(*d)->disableSingleHostMultiConnection();
dependantFileEntries.begin(); s != dependantFileEntries.end();
++s){
std::vector<SharedHandle<FileEntry> >::const_iterator d =
context->getFileEntries().begin();
for(; d != context->getFileEntries().end(); ++d) {
if((*d)->getOriginalName() == (*s)->getOriginalName()) {
break;
}
}
if(d == context->getFileEntries().end()) {
throw DL_ABORT_EX
(StringFormat("No entry %s in torrent file",
(*s)->getOriginalName().c_str()).str());
}
copyValues(*d, *s);
}
}
} catch(RecoverableException& e) {

View File

@ -70,6 +70,7 @@ private:
// available.
std::deque<URIResult> _uriResults;
bool _singleHostMultiConnection;
std::string _originalName;
Logger* _logger;
void storePool(const SharedHandle<Request>& request);
@ -227,6 +228,16 @@ public:
void reuseUri(size_t num);
void releaseRuntimeResource();
void setOriginalName(const std::string& originalName)
{
_originalName = originalName;
}
const std::string& getOriginalName() const
{
return _originalName;
}
};
typedef SharedHandle<FileEntry> FileEntryHandle;

View File

@ -136,57 +136,66 @@ void removeMetalinkContentTypes(const SharedHandle<RequestGroup>& group)
void
Metalink2RequestGroup::createRequestGroup
(std::deque<SharedHandle<RequestGroup> >& groups,
std::deque<SharedHandle<MetalinkEntry> > entries,
const std::deque<SharedHandle<MetalinkEntry> >& entries,
const SharedHandle<Option>& option)
{
if(entries.size() == 0) {
if(entries.empty()) {
_logger->notice(EX_NO_RESULT_WITH_YOUR_PREFS);
return;
}
std::deque<int32_t> selectIndexes =
util::parseIntRange(option->get(PREF_SELECT_FILE)).flush();
bool useIndex;
if(selectIndexes.size()) {
useIndex = true;
} else {
useIndex = false;
}
int32_t count = 0;
for(std::deque<SharedHandle<MetalinkEntry> >::iterator itr = entries.begin(); itr != entries.end();
++itr, ++count) {
SharedHandle<MetalinkEntry>& entry = *itr;
if(option->defined(PREF_METALINK_LOCATION)) {
std::sort(selectIndexes.begin(), selectIndexes.end());
std::vector<SharedHandle<MetalinkEntry> > selectedEntries;
selectedEntries.reserve(entries.size());
std::deque<std::string> locations;
if(option->defined(PREF_METALINK_LOCATION)) {
util::split(option->get(PREF_METALINK_LOCATION),
std::back_inserter(locations), ",", true);
std::transform
(locations.begin(), locations.end(), locations.begin(), util::toLower);
entry->setLocationPriority
(locations, -MetalinkResource::getLowestPriority());
}
std::string preferredProtocol;
if(option->get(PREF_METALINK_PREFERRED_PROTOCOL) != V_NONE) {
entry->setProtocolPriority
(option->get(PREF_METALINK_PREFERRED_PROTOCOL),
-MetalinkResource::getLowestPriority());
preferredProtocol = option->get(PREF_METALINK_PREFERRED_PROTOCOL);
}
if(useIndex) {
if(std::find(selectIndexes.begin(), selectIndexes.end(), count+1) ==
selectIndexes.end()) {
{
int32_t count = 1;
for(std::deque<SharedHandle<MetalinkEntry> >::const_iterator i =
entries.begin(); i != entries.end(); ++i, ++count) {
(*i)->dropUnsupportedResource();
if((*i)->resources.empty() && (*i)->metaurls.empty()) {
continue;
}
(*i)->setLocationPriority
(locations, -MetalinkResource::getLowestPriority());
if(!preferredProtocol.empty()) {
(*i)->setProtocolPriority
(preferredProtocol, -MetalinkResource::getLowestPriority());
}
entry->dropUnsupportedResource();
if(entry->resources.empty() && entry->metaurls.empty()) {
continue;
if(selectIndexes.empty() ||
std::binary_search(selectIndexes.begin(), selectIndexes.end(), count)){
selectedEntries.push_back(*i);
}
_logger->info(MSG_METALINK_QUEUEING, entry->getPath().c_str());
}
}
std::for_each(entries.begin(), entries.end(),
mem_fun_sh(&MetalinkEntry::reorderMetaurlsByPriority));
std::vector<std::pair<std::string,
std::vector<SharedHandle<MetalinkEntry> > > > entryGroups;
MetalinkHelper::groupEntryByMetaurlName(entryGroups, selectedEntries);
for(std::vector<std::pair<std::string,
std::vector<SharedHandle<MetalinkEntry> > > >::const_iterator itr =
entryGroups.begin(); itr != entryGroups.end(); ++itr) {
const std::string& metaurl = (*itr).first;
const std::vector<SharedHandle<MetalinkEntry> >& mes = (*itr).second;
_logger->info("Processing metaurl group metaurl=%s", metaurl.c_str());
#ifdef ENABLE_BITTORRENT
SharedHandle<RequestGroup> torrentRg;
if(!entry->metaurls.empty()) {
entry->reorderMetaurlsByPriority();
// there is torrent entry
if(!metaurl.empty()) {
std::deque<std::string> uris;
uris.push_back(entry->metaurls[0]->url);
uris.push_back(metaurl);
{
std::deque<SharedHandle<RequestGroup> > result;
createRequestGroupForUri(result, option, uris,
@ -213,11 +222,15 @@ Metalink2RequestGroup::createRequestGroup
}
}
#endif // ENABLE_BITTORRENT
SharedHandle<RequestGroup> rg(new RequestGroup(option));
SharedHandle<DownloadContext> dctx;
if(mes.size() == 1) {
SharedHandle<MetalinkEntry> entry = mes[0];
_logger->info(MSG_METALINK_QUEUEING, entry->getPath().c_str());
entry->reorderResourcesByPriority();
std::deque<std::string> uris;
std::for_each(entry->resources.begin(), entry->resources.end(),
AccumulateNonP2PUrl(uris));
SharedHandle<RequestGroup> rg(new RequestGroup(option));
// If piece hash is specified in the metalink,
// make segment size equal to piece hash size.
size_t pieceLength;
@ -230,12 +243,11 @@ Metalink2RequestGroup::createRequestGroup
#else
pieceLength = option->getAsInt(PREF_SEGMENT_SIZE);
#endif // ENABLE_MESSAGE_DIGEST
SharedHandle<DownloadContext> dctx
(new DownloadContext
dctx.reset(new DownloadContext
(pieceLength,
entry->getLength(),
util::applyDir(option->get(PREF_DIR), entry->file->getPath())));
dctx->setDir(option->get(PREF_DIR));
util::applyDir(option->get(PREF_DIR),
entry->file->getPath())));
dctx->getFirstFileEntry()->setUris(uris);
if(option->getAsBool(PREF_METALINK_ENABLE_UNIQUE_PROTOCOL)) {
dctx->getFirstFileEntry()->disableSingleHostMultiConnection();
@ -253,22 +265,51 @@ Metalink2RequestGroup::createRequestGroup
}
#endif // ENABLE_MESSAGE_DIGEST
dctx->setSignature(entry->getSignature());
rg->setDownloadContext(dctx);
rg->setNumConcurrentCommand
(entry->maxConnections < 0 ?
option->getAsInt(PREF_METALINK_SERVERS) :
std::min(option->getAsInt(PREF_METALINK_SERVERS),
static_cast<int32_t>(entry->maxConnections)));
// remove "metalink" from Accept Type list to avoid loop in tranparent
// metalink
} else {
dctx.reset(new DownloadContext());
// piece length is overridden by the one in torrent file.
dctx->setPieceLength(option->getAsInt(PREF_SEGMENT_SIZE));
std::vector<SharedHandle<FileEntry> > fileEntries;
off_t offset = 0;
for(std::deque<SharedHandle<MetalinkEntry> >::const_iterator i =
entries.begin(); i != entries.end(); ++i) {
_logger->info("Metalink: Queueing %s for download as a member.",
(*i)->getPath().c_str());
_logger->debug("originalName = %s", (*i)->metaurls[0]->name.c_str());
(*i)->reorderResourcesByPriority();
std::deque<std::string> uris;
std::for_each((*i)->resources.begin(), (*i)->resources.end(),
AccumulateNonP2PUrl(uris));
SharedHandle<FileEntry> fe
(new FileEntry
(util::applyDir(option->get(PREF_DIR), (*i)->file->getPath()),
(*i)->file->getLength(), offset, uris));
if(option->getAsBool(PREF_METALINK_ENABLE_UNIQUE_PROTOCOL)) {
fe->disableSingleHostMultiConnection();
}
fe->setOriginalName((*i)->metaurls[0]->name);
fileEntries.push_back(fe);
offset += (*i)->file->getLength();
}
dctx->setFileEntries(fileEntries.begin(), fileEntries.end());
rg->setNumConcurrentCommand(option->getAsInt(PREF_METALINK_SERVERS));
}
dctx->setDir(option->get(PREF_DIR));
rg->setDownloadContext(dctx);
// remove "metalink" from Accept Type list to avoid loop in
// tranparent metalink
removeMetalinkContentTypes(rg);
#ifdef ENABLE_BITTORRENT
// Inject depenency between rg and torrentRg here if torrentRg.isNull() == false
// Inject depenency between rg and torrentRg here if
// torrentRg.isNull() == false
if(!torrentRg.isNull()) {
SharedHandle<Dependency> dep(new BtDependency(rg, torrentRg));
rg->dependsOn(dep);
torrentRg->belongsTo(rg->getGID());
}
#endif // ENABLE_BITTORRENT

View File

@ -54,7 +54,7 @@ private:
void
createRequestGroup(std::deque<SharedHandle<RequestGroup> >& groups,
std::deque<SharedHandle<MetalinkEntry> > entries,
const std::deque<SharedHandle<MetalinkEntry> >& entries,
const SharedHandle<Option>& option);
public:
Metalink2RequestGroup();

View File

@ -51,7 +51,7 @@
namespace aria2 {
MetalinkEntry::MetalinkEntry():
file(0),
sizeKnown(false),
maxConnections(-1)
{}
@ -94,7 +94,7 @@ MetalinkEntry& MetalinkEntry::operator=(const MetalinkEntry& metalinkEntry)
return *this;
}
std::string MetalinkEntry::getPath() const
const std::string& MetalinkEntry::getPath() const
{
return file->getPath();
}

View File

@ -61,6 +61,8 @@ public:
std::string version;
std::vector<std::string> languages;
std::vector<std::string> oses;
// True if size is specified in Metalink document.
bool sizeKnown;
std::deque<SharedHandle<MetalinkResource> > resources;
std::vector<SharedHandle<MetalinkMetaurl> > metaurls;
int maxConnections; // Metalink3Spec
@ -77,7 +79,7 @@ public:
MetalinkEntry& operator=(const MetalinkEntry& metalinkEntry);
std::string getPath() const;
const std::string& getPath() const;
uint64_t getLength() const;

View File

@ -41,6 +41,7 @@
#include "prefs.h"
#include "DlAbortEx.h"
#include "BinaryStream.h"
#include "MetalinkMetaurl.h"
namespace aria2 {
@ -79,4 +80,41 @@ void MetalinkHelper::query
option->get(PREF_METALINK_OS));
}
void MetalinkHelper::groupEntryByMetaurlName
(std::vector<
std::pair<std::string, std::vector<SharedHandle<MetalinkEntry> > > >& result,
const std::vector<SharedHandle<MetalinkEntry> >& entries)
{
for(std::vector<SharedHandle<MetalinkEntry> >::const_iterator eiter =
entries.begin(); eiter != entries.end(); ++eiter) {
if((*eiter)->metaurls.empty()) {
std::pair<std::string, std::vector<SharedHandle<MetalinkEntry> > > p;
p.second.push_back(*eiter);
result.push_back(p);
} else {
std::vector<
std::pair<std::string,
std::vector<SharedHandle<MetalinkEntry> > > >::iterator i =
result.begin();
if((*eiter)->metaurls[0]->name.empty() ||
!(*eiter)->sizeKnown) {
i = result.end();
}
for(; i != result.end(); ++i) {
if((*i).first == (*eiter)->metaurls[0]->url &&
!(*i).second[0]->metaurls[0]->name.empty()) {
(*i).second.push_back(*eiter);
break;
}
}
if(i == result.end()) {
std::pair<std::string, std::vector<SharedHandle<MetalinkEntry> > > p;
p.first = (*eiter)->metaurls[0]->url;
p.second.push_back(*eiter);
result.push_back(p);
}
}
}
}
} // namespace aria2

View File

@ -36,9 +36,12 @@
#define _D_METALINK_HELPER_H_
#include "common.h"
#include "SharedHandle.h"
#include <string>
#include <deque>
#include <vector>
#include "SharedHandle.h"
namespace aria2 {
@ -65,6 +68,11 @@ public:
static void parseAndQuery
(std::deque<SharedHandle<MetalinkEntry> >& result,
const SharedHandle<BinaryStream>& binaryStream, const Option* option);
static void groupEntryByMetaurlName
(std::vector<
std::pair<std::string, std::vector<SharedHandle<MetalinkEntry> > > >& result,
const std::vector<SharedHandle<MetalinkEntry> >& entries);
};
} // namespace aria2

View File

@ -42,4 +42,9 @@ const std::string MetalinkMetaurl::MEDIATYPE_TORRENT("torrent");
MetalinkMetaurl::MetalinkMetaurl():
priority(MetalinkResource::getLowestPriority()) {}
MetalinkMetaurl::MetalinkMetaurl
(const std::string& url, const std::string& mediatype,
const std::string& name, int priority):
url(url), mediatype(mediatype), name(name), priority(priority) {}
} // namespace aria2

View File

@ -45,11 +45,14 @@ class MetalinkMetaurl {
public:
std::string url;
std::string mediatype;
int priority;
std::string name;
int priority;
MetalinkMetaurl();
MetalinkMetaurl(const std::string& url, const std::string& mediatype,
const std::string& name, int priority);
static const std::string MEDIATYPE_TORRENT;
};

View File

@ -100,6 +100,7 @@ void MetalinkParserController::setFileLengthOfEntry(uint64_t length)
} else {
_tEntry->file->setLength(length);
}
_tEntry->sizeKnown = true;
}
void MetalinkParserController::setVersionOfEntry(const std::string& version)

View File

@ -205,6 +205,8 @@ void RequestGroup::createInitialCommand
SharedHandle<BtRegistry> btRegistry = e->getBtRegistry();
if(!btRegistry->getDownloadContext
(torrentAttrs[bittorrent::INFO_HASH].s()).isNull()) {
// TODO If metadataGetMode == false and each FileEntry has
// URI, then go without BT.
throw DOWNLOAD_FAILURE_EXCEPTION
(StringFormat
("InfoHash %s is already registered.",
@ -284,14 +286,7 @@ void RequestGroup::createInitialCommand
return;
}
// Remove the control file if download file doesn't exist
if(progressInfoFile->exists() && !_pieceStorage->getDiskAdaptor()->fileExists()) {
progressInfoFile->removeFile();
_logger->notice(MSG_REMOVED_DEFUNCT_CONTROL_FILE,
progressInfoFile->getFilename().c_str(),
_downloadContext->getBasePath().c_str());
}
removeDefunctControlFile(progressInfoFile);
{
uint64_t actualFileSize = _pieceStorage->getDiskAdaptor()->size();
if(actualFileSize == _downloadContext->getTotalLength()) {
@ -372,12 +367,7 @@ void RequestGroup::createInitialCommand
}
}
#endif // ENABLE_BITTORRENT
// TODO Currently, BitTorrent+WEB-Seeding is only way to download
// multiple files in one RequestGroup. In this context, we don't
// have BitTorrent, so add assertion here. This situation will be
// changed if Metalink spec is formalized to support multi-file
// torrent.
assert(_downloadContext->getFileEntries().size() == 1);
if(_downloadContext->getFileEntries().size() == 1) {
// TODO I assume here when totallength is set to DownloadContext and it is
// not 0, then filepath is also set DownloadContext correctly....
if(_option->getAsBool(PREF_DRY_RUN) ||
@ -409,6 +399,49 @@ void RequestGroup::createInitialCommand
processCheckIntegrityEntry(commands, checkIntegrityEntry, e);
}
}
} else {
// In this context, multiple FileEntry objects are in
// DownloadContext.
if(e->_requestGroupMan->isSameFileBeingDownloaded(this)) {
throw DOWNLOAD_FAILURE_EXCEPTION
(StringFormat(EX_DUPLICATE_FILE_DOWNLOAD,
_downloadContext->getBasePath().c_str()).str());
}
initPieceStorage();
if(_downloadContext->getFileEntries().size() > 1) {
_pieceStorage->setupFileFilter();
}
SharedHandle<DefaultBtProgressInfoFile> progressInfoFile
(new DefaultBtProgressInfoFile(_downloadContext,
_pieceStorage,
_option.get()));
removeDefunctControlFile(progressInfoFile);
// Call Load, Save and file allocation command here
if(progressInfoFile->exists()) {
// load .aria2 file if it exists.
progressInfoFile->load();
_pieceStorage->getDiskAdaptor()->openFile();
} else {
if(_pieceStorage->getDiskAdaptor()->fileExists()) {
if(!_option->getAsBool(PREF_CHECK_INTEGRITY) &&
!_option->getAsBool(PREF_ALLOW_OVERWRITE)) {
// TODO we need this->haltRequested = true?
throw DOWNLOAD_FAILURE_EXCEPTION
(StringFormat
(MSG_FILE_ALREADY_EXISTS,
_downloadContext->getBasePath().c_str()).str());
} else {
_pieceStorage->getDiskAdaptor()->openFile();
}
} else {
_pieceStorage->getDiskAdaptor()->openFile();
}
}
_progressInfoFile = progressInfoFile;
SharedHandle<CheckIntegrityEntry> checkIntegrityEntry
(new StreamCheckIntegrityEntry(this));
processCheckIntegrityEntry(commands, checkIntegrityEntry, e);
}
}
void RequestGroup::processCheckIntegrityEntry(std::deque<Command*>& commands,
@ -543,6 +576,19 @@ void RequestGroup::adjustFilename
}
}
void RequestGroup::removeDefunctControlFile
(const SharedHandle<BtProgressInfoFile>& progressInfoFile)
{
// Remove the control file if download file doesn't exist
if(progressInfoFile->exists() &&
!_pieceStorage->getDiskAdaptor()->fileExists()) {
progressInfoFile->removeFile();
_logger->notice(MSG_REMOVED_DEFUNCT_CONTROL_FILE,
progressInfoFile->getFilename().c_str(),
_downloadContext->getBasePath().c_str());
}
}
void RequestGroup::loadAndOpenFile(const BtProgressInfoFileHandle& progressInfoFile)
{
try {
@ -550,14 +596,7 @@ void RequestGroup::loadAndOpenFile(const BtProgressInfoFileHandle& progressInfoF
_pieceStorage->getDiskAdaptor()->initAndOpenFile();
return;
}
// Remove the control file if download file doesn't exist
if(progressInfoFile->exists() && !_pieceStorage->getDiskAdaptor()->fileExists()) {
progressInfoFile->removeFile();
_logger->notice(MSG_REMOVED_DEFUNCT_CONTROL_FILE,
progressInfoFile->getFilename().c_str(),
_downloadContext->getBasePath().c_str());
}
removeDefunctControlFile(progressInfoFile);
if(progressInfoFile->exists()) {
progressInfoFile->load();
_pieceStorage->getDiskAdaptor()->openExistingFile();

View File

@ -180,6 +180,9 @@ private:
// _uriResults, then last result code is returned. Otherwise
// returns downloadresultcode::UNKNOWN_ERROR.
downloadresultcode::RESULT downloadResult() const;
void removeDefunctControlFile
(const SharedHandle<BtProgressInfoFile>& progressInfoFile);
public:
// The copy of option is stored in RequestGroup object.
RequestGroup(const SharedHandle<Option>& option);

View File

@ -263,6 +263,7 @@ static void extractFileEntries
(new FileEntry(util::applyDir(ctx->getDir(), path),
fileLengthData.i(),
offset, uris));
fileEntry->setOriginalName(path);
fileEntries.push_back(fileEntry);
offset += fileEntry->getLength();
}
@ -291,6 +292,7 @@ static void extractFileEntries
SharedHandle<FileEntry> fileEntry
(new FileEntry(util::applyDir(ctx->getDir(), name),totalLength, 0,
uris));
fileEntry->setOriginalName(name);
fileEntries.push_back(fileEntry);
}
ctx->setFileEntries(fileEntries.begin(), fileEntries.end());

View File

@ -168,6 +168,8 @@ void BittorrentHelperTest::testGetFileEntries() {
SharedHandle<FileEntry> fileEntry1 = *itr;
CPPUNIT_ASSERT_EQUAL(std::string("./aria2-test/aria2/src/aria2c"),
fileEntry1->getPath());
CPPUNIT_ASSERT_EQUAL(std::string("aria2-test/aria2/src/aria2c"),
fileEntry1->getOriginalName());
itr++;
SharedHandle<FileEntry> fileEntry2 = *itr;
CPPUNIT_ASSERT_EQUAL(std::string("./aria2-test/aria2-0.2.2.tar.bz2"),
@ -186,6 +188,8 @@ void BittorrentHelperTest::testGetFileEntriesSingle() {
SharedHandle<FileEntry> fileEntry1 = *itr;
CPPUNIT_ASSERT_EQUAL(std::string("./aria2-0.8.2.tar.bz2"),
fileEntry1->getPath());
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.8.2.tar.bz2"),
fileEntry1->getOriginalName());
}
void BittorrentHelperTest::testGetTotalLength() {

View File

@ -23,6 +23,9 @@ class BtDependencyTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(BtDependencyTest);
CPPUNIT_TEST(testResolve);
CPPUNIT_TEST(testResolve_originalNameNoMatch);
CPPUNIT_TEST(testResolve_singleFileWithoutOriginalName);
CPPUNIT_TEST(testResolve_multiFile);
CPPUNIT_TEST(testResolve_metadata);
CPPUNIT_TEST(testResolve_loadError);
CPPUNIT_TEST(testResolve_dependeeFailure);
@ -37,7 +40,9 @@ class BtDependencyTest:public CppUnit::TestFixture {
dctx->setDir("/tmp");
std::deque<std::string> uris;
uris.push_back("http://localhost/outfile.path");
dctx->getFirstFileEntry()->setUris(uris);
SharedHandle<FileEntry> fileEntry = dctx->getFirstFileEntry();
fileEntry->setUris(uris);
fileEntry->setOriginalName("aria2-0.8.2.tar.bz2");
dependant->setDownloadContext(dctx);
return dependant;
}
@ -65,6 +70,9 @@ public:
}
void testResolve();
void testResolve_originalNameNoMatch();
void testResolve_singleFileWithoutOriginalName();
void testResolve_multiFile();
void testResolve_metadata();
void testResolve_loadError();
void testResolve_dependeeFailure();
@ -93,6 +101,64 @@ void BtDependencyTest::testResolve()
CPPUNIT_ASSERT_EQUAL(std::string("/tmp/outfile.path"),
firstFileEntry->getPath());
CPPUNIT_ASSERT_EQUAL((size_t)1, firstFileEntry->getRemainingUris().size());
CPPUNIT_ASSERT(firstFileEntry->isRequested());
}
void BtDependencyTest::testResolve_originalNameNoMatch()
{
std::string filename = "single.torrent";
SharedHandle<RequestGroup> dependant = createDependant(_option);
dependant->getDownloadContext()->getFirstFileEntry()->setOriginalName
("aria2-1.1.0.tar.bz2");
SharedHandle<RequestGroup> dependee =
createDependee(_option, filename, File(filename).size());
dependee->getPieceStorage()->markAllPiecesDone();
BtDependency dep(dependant, dependee);
CPPUNIT_ASSERT(dep.resolve());
CPPUNIT_ASSERT(!dependant->getDownloadContext()->hasAttribute
(bittorrent::BITTORRENT));
}
void BtDependencyTest::testResolve_singleFileWithoutOriginalName()
{
std::string filename = "single.torrent";
SharedHandle<RequestGroup> dependant = createDependant(_option);
dependant->getDownloadContext()->getFirstFileEntry()->setOriginalName("");
SharedHandle<RequestGroup> dependee =
createDependee(_option, filename, File(filename).size());
dependee->getPieceStorage()->markAllPiecesDone();
BtDependency dep(dependant, dependee);
CPPUNIT_ASSERT(dep.resolve());
CPPUNIT_ASSERT(dependant->getDownloadContext()->hasAttribute
(bittorrent::BITTORRENT));
}
void BtDependencyTest::testResolve_multiFile()
{
std::string filename = "test.torrent";
SharedHandle<RequestGroup> dependant = createDependant(_option);
dependant->getDownloadContext()->getFirstFileEntry()->setOriginalName
("aria2-test/aria2/src/aria2c");
SharedHandle<RequestGroup> dependee =
createDependee(_option, filename, File(filename).size());
dependee->getPieceStorage()->markAllPiecesDone();
BtDependency dep(dependant, dependee);
CPPUNIT_ASSERT(dep.resolve());
CPPUNIT_ASSERT(dependant->getDownloadContext()->hasAttribute
(bittorrent::BITTORRENT));
const std::vector<SharedHandle<FileEntry> >& fileEntries =
dependant->getDownloadContext()->getFileEntries();
CPPUNIT_ASSERT_EQUAL(std::string("/tmp/outfile.path"),
fileEntries[0]->getPath());
CPPUNIT_ASSERT(fileEntries[0]->isRequested());
CPPUNIT_ASSERT_EQUAL(std::string("/tmp/aria2-test/aria2-0.2.2.tar.bz2"),
fileEntries[1]->getPath());
CPPUNIT_ASSERT(!fileEntries[1]->isRequested());
}
void BtDependencyTest::testResolve_metadata()
@ -121,6 +187,8 @@ void BtDependencyTest::testResolve_metadata()
CPPUNIT_ASSERT_EQUAL
(std::string("cd41c7fdddfd034a15a04d7ff881216e01c4ceaf"),
bittorrent::getInfoHashString(dependant->getDownloadContext()));
CPPUNIT_ASSERT
(dependant->getDownloadContext()->getFirstFileEntry()->isRequested());
}
void BtDependencyTest::testResolve_loadError()

View File

@ -1,8 +1,11 @@
#include "MetalinkHelper.h"
#include <cppunit/extensions/HelperMacros.h>
#include "MetalinkEntry.h"
#include "Option.h"
#include "prefs.h"
#include <cppunit/extensions/HelperMacros.h>
#include "MetalinkMetaurl.h"
namespace aria2 {
@ -11,16 +14,14 @@ class MetalinkHelperTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(MetalinkHelperTest);
CPPUNIT_TEST(testParseAndQuery);
CPPUNIT_TEST(testParseAndQuery_version);
CPPUNIT_TEST(testGroupEntryByMetaurlName);
CPPUNIT_TEST_SUITE_END();
private:
public:
void setUp() {}
void tearDown() {}
void testParseAndQuery();
void testParseAndQuery_version();
void testGroupEntryByMetaurlName();
};
@ -45,4 +46,70 @@ void MetalinkHelperTest::testParseAndQuery_version()
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.5.1.tar.bz2"), entry->getPath());
}
void MetalinkHelperTest::testGroupEntryByMetaurlName()
{
std::vector<SharedHandle<MetalinkEntry> > entries;
SharedHandle<MetalinkEntry> e1(new MetalinkEntry());
e1->version = "1";
e1->sizeKnown = true;
// no name
e1->metaurls.push_back
(SharedHandle<MetalinkMetaurl>
(new MetalinkMetaurl("http://meta1", "torrent", "", 1)));
SharedHandle<MetalinkEntry> e2(new MetalinkEntry());
e2->version = "2";
e2->sizeKnown = true;
SharedHandle<MetalinkEntry> e3(new MetalinkEntry());
e3->version = "3";
e3->sizeKnown = true;
e3->metaurls.push_back
(SharedHandle<MetalinkMetaurl>
(new MetalinkMetaurl("http://meta2", "torrent", "f3", 1)));
SharedHandle<MetalinkEntry> e4(new MetalinkEntry());
e4->version = "4";
e4->sizeKnown = true;
e4->metaurls.push_back
(SharedHandle<MetalinkMetaurl>
(new MetalinkMetaurl("http://meta1", "torrent", "f4", 1)));
SharedHandle<MetalinkEntry> e5(new MetalinkEntry());
e5->version = "5";
// no size
e5->metaurls.push_back
(SharedHandle<MetalinkMetaurl>
(new MetalinkMetaurl("http://meta1", "torrent", "f5", 1)));
SharedHandle<MetalinkEntry> e6(new MetalinkEntry());
e6->version = "6";
e6->sizeKnown = true;
e6->metaurls.push_back
(SharedHandle<MetalinkMetaurl>
(new MetalinkMetaurl("http://meta1", "torrent", "f6", 1)));
entries.push_back(e1);
entries.push_back(e2);
entries.push_back(e3);
entries.push_back(e4);
entries.push_back(e5);
entries.push_back(e6);
std::vector<std::pair<std::string,
std::vector<SharedHandle<MetalinkEntry> > > > result;
MetalinkHelper::groupEntryByMetaurlName(result, entries);
CPPUNIT_ASSERT_EQUAL(std::string("http://meta1"), result[0].first);
CPPUNIT_ASSERT_EQUAL(std::string("1"), result[0].second[0]->version);
CPPUNIT_ASSERT_EQUAL(std::string(""), result[1].first);
CPPUNIT_ASSERT_EQUAL(std::string("2"), result[1].second[0]->version);
CPPUNIT_ASSERT_EQUAL(std::string("http://meta2"), result[2].first);
CPPUNIT_ASSERT_EQUAL(std::string("3"), result[2].second[0]->version);
CPPUNIT_ASSERT_EQUAL(std::string("http://meta1"), result[3].first);
CPPUNIT_ASSERT_EQUAL(std::string("4"), result[3].second[0]->version);
CPPUNIT_ASSERT_EQUAL(std::string("6"), result[3].second[1]->version);
}
} // namespace aria2