Browse Source

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
Tatsuhiro Tsujikawa 16 years ago
parent
commit
339795311b

+ 12 - 0
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>
 
 	Use createRequestGroupForUri to create the download for torrent

+ 9 - 2
src/BtDependency.cc

@@ -71,8 +71,15 @@ bool BtDependency::resolve()
 	dependee->getPieceStorage()->getDiskAdaptor();
       diskAdaptor->openExistingFile();
       std::string content = util::toString(diskAdaptor);
-      bittorrent::loadFromMemory
-	(content, context, File(dependee->getFirstFilePath()).getBasename());
+      if(dependee->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
+	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() !=
 	 _dependant->getDownloadContext()->getFileEntries().size()) {
 	throw DL_ABORT_EX("The number of file in torrent doesn't match to"

+ 4 - 25
src/UTMetadataPostDownloadHandler.cc

@@ -45,6 +45,7 @@
 #include "a2functional.h"
 #include "DiskAdaptor.h"
 #include "PieceStorage.h"
+#include "bencode.h"
 
 namespace aria2 {
 
@@ -72,35 +73,13 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups
 {
   SharedHandle<DownloadContext> dctx = requestGroup->getDownloadContext();
   const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT);
-  std::string torrent =
-    strconcat("d4:info",
-	      util::toString(requestGroup->getPieceStorage()->getDiskAdaptor()),
-	      "e");
+  std::string metadata =
+    util::toString(requestGroup->getPieceStorage()->getDiskAdaptor());
+  std::string torrent = bittorrent::metadata2Torrent(metadata, attrs);
   try {
     std::deque<SharedHandle<RequestGroup> > newRgs;
     createRequestGroupForBitTorrent(newRgs, requestGroup->getOption(),
 				    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());
   } catch(RecoverableException& e) {
     _logger->error("Failed to parse BitTorrent metadata.", e);

+ 15 - 0
src/bittorrent_helper.cc

@@ -904,6 +904,21 @@ void loadMagnet
   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 aria2

+ 5 - 0
src/bittorrent_helper.h

@@ -230,6 +230,11 @@ void assertID
 
 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 aria2

+ 21 - 0
test/BittorrentHelperTest.cc

@@ -61,6 +61,7 @@ class BittorrentHelperTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testMetadata);
   CPPUNIT_TEST(testParseMagnet);
   CPPUNIT_TEST(testParseMagnet_base32);
+  CPPUNIT_TEST(testMetadata2Torrent);
   CPPUNIT_TEST_SUITE_END();
 public:
   void setUp() {
@@ -102,6 +103,7 @@ public:
   void testMetadata();
   void testParseMagnet();
   void testParseMagnet_base32();
+  void testMetadata2Torrent();
 };
 
 
@@ -734,6 +736,25 @@ void BittorrentHelperTest::testParseMagnet_base32()
      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 aria2

+ 33 - 0
test/BtDependencyTest.cc

@@ -13,6 +13,9 @@
 #include "FileEntry.h"
 #include "PieceSelector.h"
 #include "bittorrent_helper.h"
+#include "DirectDiskAdaptor.h"
+#include "ByteArrayDiskWriter.h"
+#include "MockPieceStorage.h"
 
 namespace aria2 {
 
@@ -20,6 +23,7 @@ class BtDependencyTest:public CppUnit::TestFixture {
 
   CPPUNIT_TEST_SUITE(BtDependencyTest);
   CPPUNIT_TEST(testResolve);
+  CPPUNIT_TEST(testResolve_metadata);
   CPPUNIT_TEST(testResolve_loadError);
   CPPUNIT_TEST(testResolve_dependeeFailure);
   CPPUNIT_TEST(testResolve_dependeeInProgress);
@@ -64,6 +68,7 @@ public:
   }
 
   void testResolve();
+  void testResolve_metadata();
   void testResolve_loadError();
   void testResolve_dependeeFailure();
   void testResolve_dependeeInProgress();
@@ -93,6 +98,34 @@ void BtDependencyTest::testResolve()
   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()
 {
   SharedHandle<RequestGroup> dependant = createDependant(_option);