[or-cvs] [thandy/master] Add ability to create .torrent metadata when making a package

Nick Mathewson nickm at seul.org
Tue Aug 25 21:01:45 UTC 2009


Author: Sebastian Hahn <sebastian at torproject.org>
Date: Tue, 11 Aug 2009 13:43:06 +0200
Subject: Add ability to create .torrent metadata when making a package
Commit: aa0d32f4b675e155e6e004604bf8b6ee4e607873

Also update the spec with the information where the .torrent
metadata file will be stored.
---
 doc/HOWTO                 |    3 +-
 lib/thandy/SignerCLI.py   |   14 ++++++++
 lib/thandy/bt_compat.py   |   76 +++++++++++++++++++++++++++++++++++++++++++++
 lib/thandy/master_keys.py |    3 ++
 specs/thandy-spec.txt     |    6 +++
 5 files changed, 101 insertions(+), 1 deletions(-)
 create mode 100644 lib/thandy/bt_compat.py

diff --git a/doc/HOWTO b/doc/HOWTO
index a5937f3..4ec6068 100644
--- a/doc/HOWTO
+++ b/doc/HOWTO
@@ -217,7 +217,8 @@ and notes:
 
     * For the actual data files (i.e. the packages themselves), for now you
       just copy them into the repository manually. Later there will be some
-      version of thandy-server insert that handles them too.
+      version of thandy-server insert that handles them too. The same goes
+      for the BitTorrent metadata files.
 
 .GENERATING TIMESTAMPS.
 
diff --git a/lib/thandy/SignerCLI.py b/lib/thandy/SignerCLI.py
index d0feef6..06536aa 100644
--- a/lib/thandy/SignerCLI.py
+++ b/lib/thandy/SignerCLI.py
@@ -7,6 +7,7 @@ import sys
 import thandy.keys
 import thandy.formats
 import thandy.util
+import thandy.bt_compat
 
 json = thandy.util.importJSON()
 
@@ -78,6 +79,19 @@ def makepackage(args):
     f = open(location, 'w')
     json.dump(signable, f, indent=1, sort_keys=True)
     f.close()
+    btcomp = thandy.bt_compat.BtCompat()
+    # If we have bittorrent support, we always create the appropriate metadata.
+    thandy.bt_compat.BtCompat.setUseBt(True)
+    if not thandy.bt_compat.BtCompat.shouldUseBt():
+        print "Not generating BitTorrent metadata files"
+        return
+    print "Generating BitTorrent metadata file"
+    metaFile = btcomp.makeMetaFile(dataFile)
+    mfLocation = os.path.split(btcomp.getBtMetadataLocation(location, dataFile))[-1]
+    print "Writing BitTorrent Metadata file to %s"%mfLocation
+    f = open(mfLocation, 'w')
+    f.write(metaFile)
+    f.close()
 
 def makebundle(args):
     options, args = getopt.getopt(args, "", "keyid=")
diff --git a/lib/thandy/bt_compat.py b/lib/thandy/bt_compat.py
new file mode 100644
index 0000000..43cecad
--- /dev/null
+++ b/lib/thandy/bt_compat.py
@@ -0,0 +1,76 @@
+# Copyright 2008 The Tor Project, Inc.  See LICENSE for licensing information.
+
+import os.path
+import time
+
+import thandy.master_keys
+
+no_bt = None
+try:
+    import BitTorrent.bencode
+    import BitTorrent.btformats
+    import BitTorrent.download
+except ImportError:
+    no_bt = True
+from sha import sha # XXX Use PyCrypto here?
+
+
+class BtCompat:
+    """Interface for different bittorrent implementations"""
+
+    usingBt = False
+
+    def __init__(self):
+        self.tUrl = thandy.master_keys.DEFAULT_TRACKER
+        if not no_bt:
+            assert(self.tUrl is not None and self.tUrl != "")
+        self.pieceLength = 2 ** 18 # Piece length of 262144 bytes
+
+    # XXX Do we need to be thread-safe here and below?
+    @staticmethod
+    def shouldUseBt():
+        return BtCompat.usingBt
+
+    @staticmethod
+    def setUseBt(useBt):
+        if no_bt:
+            return
+        BtCompat.usingBt = useBt
+
+    @staticmethod
+    def getBtMetadataLocation(packagepath, filepath, pathprefix=""):
+        """Given a path for the package, the path for a file of that
+           package, and an optional prefix, return the path for the
+           .torrent metadata file. Always return Unix-like paths, to
+           ensure compatibility with fetching the path from a
+           webserver.
+        """
+        return (os.path.join(pathprefix, os.path.dirname(packagepath),
+                             os.path.basename(filepath)) + ".torrent"
+               ).replace("\\", "/")
+
+    def makeMetaFile(self, file):
+        """Given a path to a file, create the contents of a .torrent
+           metadata file and return them.
+        """
+        size = os.path.getsize(file)
+        filename = os.path.basename(file)
+        pieces = []
+        p = 0
+        h = open(file, 'rb')
+        while p < size:
+            x = h.read(min(self.pieceLength, size - p))
+            pieces.append(sha(x).digest())
+            p += self.pieceLength
+            if p > size:
+                p = size
+        h.close()
+        info = {'pieces': ''.join(pieces),
+            'piece length': self.pieceLength, 'length': size,
+            'name': filename}
+        # Check we didn't screw up with the info
+        BitTorrent.btformats.check_info(info)
+        data = {'info': info, 'announce': self.tUrl,
+                'creation date': long(time.time())}
+        return BitTorrent.bencode.bencode(data)
+
diff --git a/lib/thandy/master_keys.py b/lib/thandy/master_keys.py
index 05c50a8..be13f52 100644
--- a/lib/thandy/master_keys.py
+++ b/lib/thandy/master_keys.py
@@ -17,3 +17,6 @@ DEFAULT_MIRRORLIST = {
                 }
              ],
 }
+
+DEFAULT_TRACKER = NONE
+
diff --git a/specs/thandy-spec.txt b/specs/thandy-spec.txt
index daadd05..eae908b 100644
--- a/specs/thandy-spec.txt
+++ b/specs/thandy-spec.txt
@@ -248,6 +248,12 @@
          file that makes up a package, its hash, and what procedure
          is used to install it.
 
+    /pkginfo/packagename/os-arch/version/(some filename).torrent
+
+         The .torrent metadata file used to download that file. The
+         file name is exactly the same as specified in the package
+         file.
+
     /packages/packagename/os-arch/version/(some filename)
 
          The actual package file.  Its naming convention will depend
-- 
1.5.6.5




More information about the tor-commits mailing list