mirror of https://github.com/aria2/aria2
2009-11-28 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Accept BitTorrent Magnet URI in Metalink resource type bittorrent. Rewritten UTMetadataPostDownloadHandler. To create torrent data from metadata, use new metadata2Torrent() function. * src/BtDependency.cc * src/UTMetadataPostDownloadHandler.cc * src/bittorrent_helper.cc * src/bittorrent_helper.h * test/BittorrentHelperTest.cc * test/BtDependencyTest.ccpull/1/head
parent
96205abc67
commit
339795311b
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
||||||
|
2009-11-28 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
|
Accept BitTorrent Magnet URI in Metalink resource type bittorrent.
|
||||||
|
Rewritten UTMetadataPostDownloadHandler. To create torrent data
|
||||||
|
from metadata, use new metadata2Torrent() function.
|
||||||
|
* src/BtDependency.cc
|
||||||
|
* src/UTMetadataPostDownloadHandler.cc
|
||||||
|
* src/bittorrent_helper.cc
|
||||||
|
* src/bittorrent_helper.h
|
||||||
|
* test/BittorrentHelperTest.cc
|
||||||
|
* test/BtDependencyTest.cc
|
||||||
|
|
||||||
2009-11-28 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
2009-11-28 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
Use createRequestGroupForUri to create the download for torrent
|
Use createRequestGroupForUri to create the download for torrent
|
||||||
|
|
|
@ -71,8 +71,15 @@ bool BtDependency::resolve()
|
||||||
dependee->getPieceStorage()->getDiskAdaptor();
|
dependee->getPieceStorage()->getDiskAdaptor();
|
||||||
diskAdaptor->openExistingFile();
|
diskAdaptor->openExistingFile();
|
||||||
std::string content = util::toString(diskAdaptor);
|
std::string content = util::toString(diskAdaptor);
|
||||||
bittorrent::loadFromMemory
|
if(dependee->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
|
||||||
(content, context, File(dependee->getFirstFilePath()).getBasename());
|
const BDE& attrs =
|
||||||
|
dependee->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
|
||||||
|
bittorrent::loadFromMemory
|
||||||
|
(bittorrent::metadata2Torrent(content, attrs), context, "default");
|
||||||
|
} else {
|
||||||
|
bittorrent::loadFromMemory
|
||||||
|
(content, context, File(dependee->getFirstFilePath()).getBasename());
|
||||||
|
}
|
||||||
if(context->getFileEntries().size() !=
|
if(context->getFileEntries().size() !=
|
||||||
_dependant->getDownloadContext()->getFileEntries().size()) {
|
_dependant->getDownloadContext()->getFileEntries().size()) {
|
||||||
throw DL_ABORT_EX("The number of file in torrent doesn't match to"
|
throw DL_ABORT_EX("The number of file in torrent doesn't match to"
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "a2functional.h"
|
#include "a2functional.h"
|
||||||
#include "DiskAdaptor.h"
|
#include "DiskAdaptor.h"
|
||||||
#include "PieceStorage.h"
|
#include "PieceStorage.h"
|
||||||
|
#include "bencode.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -72,35 +73,13 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups
|
||||||
{
|
{
|
||||||
SharedHandle<DownloadContext> dctx = requestGroup->getDownloadContext();
|
SharedHandle<DownloadContext> dctx = requestGroup->getDownloadContext();
|
||||||
const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
||||||
std::string torrent =
|
std::string metadata =
|
||||||
strconcat("d4:info",
|
util::toString(requestGroup->getPieceStorage()->getDiskAdaptor());
|
||||||
util::toString(requestGroup->getPieceStorage()->getDiskAdaptor()),
|
std::string torrent = bittorrent::metadata2Torrent(metadata, attrs);
|
||||||
"e");
|
|
||||||
try {
|
try {
|
||||||
std::deque<SharedHandle<RequestGroup> > newRgs;
|
std::deque<SharedHandle<RequestGroup> > newRgs;
|
||||||
createRequestGroupForBitTorrent(newRgs, requestGroup->getOption(),
|
createRequestGroupForBitTorrent(newRgs, requestGroup->getOption(),
|
||||||
std::deque<std::string>(), torrent);
|
std::deque<std::string>(), torrent);
|
||||||
if(attrs.containsKey(bittorrent::ANNOUNCE_LIST)) {
|
|
||||||
for(std::deque<SharedHandle<RequestGroup> >::const_iterator i =
|
|
||||||
newRgs.begin(); i != newRgs.end(); ++i) {
|
|
||||||
SharedHandle<DownloadContext> newDctx = (*i)->getDownloadContext();
|
|
||||||
if(!newDctx->hasAttribute(bittorrent::BITTORRENT)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
BDE& newAttrs = newDctx->getAttribute(bittorrent::BITTORRENT);
|
|
||||||
if(attrs[bittorrent::INFO_HASH].s() !=
|
|
||||||
newAttrs[bittorrent::INFO_HASH].s()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
assert(newAttrs[bittorrent::ANNOUNCE_LIST].isList());
|
|
||||||
if(newAttrs[bittorrent::ANNOUNCE_LIST].size() == 0) {
|
|
||||||
newAttrs[bittorrent::ANNOUNCE_LIST] =
|
|
||||||
attrs[bittorrent::ANNOUNCE_LIST];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
groups.insert(groups.end(), newRgs.begin(), newRgs.end());
|
groups.insert(groups.end(), newRgs.begin(), newRgs.end());
|
||||||
} catch(RecoverableException& e) {
|
} catch(RecoverableException& e) {
|
||||||
_logger->error("Failed to parse BitTorrent metadata.", e);
|
_logger->error("Failed to parse BitTorrent metadata.", e);
|
||||||
|
|
|
@ -904,6 +904,21 @@ void loadMagnet
|
||||||
dctx->setAttribute(BITTORRENT, attrs);
|
dctx->setAttribute(BITTORRENT, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string metadata2Torrent(const std::string& metadata, const BDE& attrs)
|
||||||
|
{
|
||||||
|
std::string torrent = "d";
|
||||||
|
if(attrs.containsKey(bittorrent::ANNOUNCE_LIST)) {
|
||||||
|
const BDE& announceList = attrs[bittorrent::ANNOUNCE_LIST];
|
||||||
|
if(announceList.size() > 0) {
|
||||||
|
torrent += "13:announce-list";
|
||||||
|
torrent += bencode::encode(announceList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
torrent +=
|
||||||
|
strconcat("4:info", metadata, "e");
|
||||||
|
return torrent;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bittorrent
|
} // namespace bittorrent
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -230,6 +230,11 @@ void assertID
|
||||||
|
|
||||||
void generateRandomKey(unsigned char* key);
|
void generateRandomKey(unsigned char* key);
|
||||||
|
|
||||||
|
// Converts attrs into torrent data. attrs must be a BDE::dict. This
|
||||||
|
// function does not guarantee the returned string is valid torrent
|
||||||
|
// data.
|
||||||
|
std::string metadata2Torrent(const std::string& metadata, const BDE& attrs);
|
||||||
|
|
||||||
} // namespace bittorrent
|
} // namespace bittorrent
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -61,6 +61,7 @@ class BittorrentHelperTest:public CppUnit::TestFixture {
|
||||||
CPPUNIT_TEST(testMetadata);
|
CPPUNIT_TEST(testMetadata);
|
||||||
CPPUNIT_TEST(testParseMagnet);
|
CPPUNIT_TEST(testParseMagnet);
|
||||||
CPPUNIT_TEST(testParseMagnet_base32);
|
CPPUNIT_TEST(testParseMagnet_base32);
|
||||||
|
CPPUNIT_TEST(testMetadata2Torrent);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
public:
|
public:
|
||||||
void setUp() {
|
void setUp() {
|
||||||
|
@ -102,6 +103,7 @@ public:
|
||||||
void testMetadata();
|
void testMetadata();
|
||||||
void testParseMagnet();
|
void testParseMagnet();
|
||||||
void testParseMagnet_base32();
|
void testParseMagnet_base32();
|
||||||
|
void testMetadata2Torrent();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -734,6 +736,25 @@ void BittorrentHelperTest::testParseMagnet_base32()
|
||||||
util::toHex(attrs[bittorrent::INFO_HASH].s()));
|
util::toHex(attrs[bittorrent::INFO_HASH].s()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BittorrentHelperTest::testMetadata2Torrent()
|
||||||
|
{
|
||||||
|
std::string metadata = "METADATA";
|
||||||
|
BDE attrs = BDE::dict();
|
||||||
|
BDE announceList = BDE::list();
|
||||||
|
attrs[ANNOUNCE_LIST] = announceList;
|
||||||
|
CPPUNIT_ASSERT_EQUAL
|
||||||
|
(std::string("d4:infoMETADATAe"), metadata2Torrent(metadata, attrs));
|
||||||
|
announceList << BDE::list();
|
||||||
|
announceList[0] << std::string("http://localhost/announce");
|
||||||
|
CPPUNIT_ASSERT_EQUAL
|
||||||
|
(std::string("d"
|
||||||
|
"13:announce-list"
|
||||||
|
"ll25:http://localhost/announceee"
|
||||||
|
"4:infoMETADATA"
|
||||||
|
"e"),
|
||||||
|
metadata2Torrent(metadata, attrs));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bittorrent
|
} // namespace bittorrent
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
#include "FileEntry.h"
|
#include "FileEntry.h"
|
||||||
#include "PieceSelector.h"
|
#include "PieceSelector.h"
|
||||||
#include "bittorrent_helper.h"
|
#include "bittorrent_helper.h"
|
||||||
|
#include "DirectDiskAdaptor.h"
|
||||||
|
#include "ByteArrayDiskWriter.h"
|
||||||
|
#include "MockPieceStorage.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -20,6 +23,7 @@ class BtDependencyTest:public CppUnit::TestFixture {
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE(BtDependencyTest);
|
CPPUNIT_TEST_SUITE(BtDependencyTest);
|
||||||
CPPUNIT_TEST(testResolve);
|
CPPUNIT_TEST(testResolve);
|
||||||
|
CPPUNIT_TEST(testResolve_metadata);
|
||||||
CPPUNIT_TEST(testResolve_loadError);
|
CPPUNIT_TEST(testResolve_loadError);
|
||||||
CPPUNIT_TEST(testResolve_dependeeFailure);
|
CPPUNIT_TEST(testResolve_dependeeFailure);
|
||||||
CPPUNIT_TEST(testResolve_dependeeInProgress);
|
CPPUNIT_TEST(testResolve_dependeeInProgress);
|
||||||
|
@ -64,6 +68,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void testResolve();
|
void testResolve();
|
||||||
|
void testResolve_metadata();
|
||||||
void testResolve_loadError();
|
void testResolve_loadError();
|
||||||
void testResolve_dependeeFailure();
|
void testResolve_dependeeFailure();
|
||||||
void testResolve_dependeeInProgress();
|
void testResolve_dependeeInProgress();
|
||||||
|
@ -93,6 +98,34 @@ void BtDependencyTest::testResolve()
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, firstFileEntry->getRemainingUris().size());
|
CPPUNIT_ASSERT_EQUAL((size_t)1, firstFileEntry->getRemainingUris().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BtDependencyTest::testResolve_metadata()
|
||||||
|
{
|
||||||
|
SharedHandle<RequestGroup> dependant = createDependant(_option);
|
||||||
|
SharedHandle<RequestGroup> dependee =
|
||||||
|
createDependee(_option, "metadata", 0);
|
||||||
|
|
||||||
|
SharedHandle<DirectDiskAdaptor> diskAdaptor(new DirectDiskAdaptor());
|
||||||
|
SharedHandle<ByteArrayDiskWriter> diskWriter(new ByteArrayDiskWriter());
|
||||||
|
diskAdaptor->setDiskWriter(diskWriter);
|
||||||
|
diskWriter->setString
|
||||||
|
("d4:name19:aria2-0.8.2.tar.bz26:lengthi384e12:piece lengthi128e"
|
||||||
|
"6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCC"
|
||||||
|
"e");
|
||||||
|
SharedHandle<MockPieceStorage> pieceStorage(new MockPieceStorage());
|
||||||
|
pieceStorage->setDiskAdaptor(diskAdaptor);
|
||||||
|
pieceStorage->setDownloadFinished(true);
|
||||||
|
dependee->setPieceStorage(pieceStorage);
|
||||||
|
BDE attrs = BDE::dict();
|
||||||
|
dependee->getDownloadContext()->setAttribute(bittorrent::BITTORRENT, attrs);
|
||||||
|
|
||||||
|
BtDependency dep(dependant, dependee);
|
||||||
|
CPPUNIT_ASSERT(dep.resolve());
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL
|
||||||
|
(std::string("cd41c7fdddfd034a15a04d7ff881216e01c4ceaf"),
|
||||||
|
bittorrent::getInfoHashString(dependant->getDownloadContext()));
|
||||||
|
}
|
||||||
|
|
||||||
void BtDependencyTest::testResolve_loadError()
|
void BtDependencyTest::testResolve_loadError()
|
||||||
{
|
{
|
||||||
SharedHandle<RequestGroup> dependant = createDependant(_option);
|
SharedHandle<RequestGroup> dependant = createDependant(_option);
|
||||||
|
|
Loading…
Reference in New Issue