r189 - in /debtorrent/trunk/DebTorrent: BT1/Downloader.py BT1/Encrypter.py BT1/PiecePicker.py BT1/Rerequester.py download_bt1.py

camrdale-guest at users.alioth.debian.org camrdale-guest at users.alioth.debian.org
Sat Jul 28 21:54:58 UTC 2007


Author: camrdale-guest
Date: Sat Jul 28 21:54:58 2007
New Revision: 189

URL: http://svn.debian.org/wsvn/debtorrent/?sc=1&rev=189
Log:
You guessed it ... more documentation.

Modified:
    debtorrent/trunk/DebTorrent/BT1/Downloader.py
    debtorrent/trunk/DebTorrent/BT1/Encrypter.py
    debtorrent/trunk/DebTorrent/BT1/PiecePicker.py
    debtorrent/trunk/DebTorrent/BT1/Rerequester.py
    debtorrent/trunk/DebTorrent/download_bt1.py

Modified: debtorrent/trunk/DebTorrent/BT1/Downloader.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Downloader.py?rev=189&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Downloader.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Downloader.py Sat Jul 28 21:54:58 2007
@@ -90,7 +90,7 @@
         @type index: C{int}
         @param index: the piece that failed
         @type bump: C{boolean}
-        @param bump: whether to increase the interest level in the 
+        @param bump: whether to decrease the interest level in the 
             L{PiecePicker.PiecePicker} (optional, defaults to False)
         
         """

Modified: debtorrent/trunk/DebTorrent/BT1/Encrypter.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Encrypter.py?rev=189&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Encrypter.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Encrypter.py Sat Jul 28 21:54:58 2007
@@ -138,11 +138,12 @@
 incompletecounter = IncompleteCounter()
 
 
-# header, options, download id, my id, [length, message]
-
 class Connection:
     """A single, possibly encrypted, connection to a peer.
     
+    The BitTorrent handshake is in the order: header, options, download id 
+    (info hash), peer id, [length, message], ....
+
     @type Encoder: L{Encoder}
     @ivar Encoder: the collection of all connections
     @type connection: L{DebTorrent.SocketHandler.SingleSocket}

Modified: debtorrent/trunk/DebTorrent/BT1/PiecePicker.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/PiecePicker.py?rev=189&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/PiecePicker.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/PiecePicker.py Sat Jul 28 21:54:58 2007
@@ -1,8 +1,10 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Choose pieces to download."""
 
 from random import randrange, shuffle
 from DebTorrent.clock import clock
@@ -13,9 +15,96 @@
     False = 0
 
 class PiecePicker:
+    """Choose pieces to download.
+    
+    @type rarest_first_cutoff: C{int}
+    @ivar rarest_first_cutoff: number of completed piece downloads at
+        which to switch from random piece selection to rarest first
+    @type rarest_first_priority_cutoff: C{int}
+    @ivar rarest_first_priority_cutoff: the number of peers which need to
+        have a piece before other partials take priority over rarest first
+    @type priority_step: C{int}
+    @ivar priority_step: the difference bewteen priority levels 0, 1, and 2
+    @type cutoff: C{int}
+    @ivar cutoff: the number of peers which need to
+        have a piece before other partials take priority over rarest first
+    @type numpieces: C{int}
+    @ivar numpieces: total number of pieces in the download
+    @type started: C{list} of C{int}
+    @ivar started: the pieces that have been requested for download
+    @type totalcount: C{int}
+    @ivar totalcount: the total number of copies of all pieces in non-seeding peers
+    @type numhaves: C{list} of C{int}
+    @ivar numhaves: the number of copies of each piece in non-seeding peers
+    @type priority: C{list} of C{int}
+    @ivar priority: the priority of each piece::
+        -1 -- do not download
+         0 -- highest priority
+         1 -- medium priority
+         2 -- lowest priority
+    @type removed_partials: C{dictionary}
+    @ivar removed_partials: keys are the pieces that were started but then disabled
+    @type crosscount: C{list} of C{int}
+    @ivar crosscount: at each index, the value is the number of pieces that
+        have that many copies in the non-seeding peers
+    @type crosscount2: C{list} of C{int}
+    @ivar crosscount2: at each index, the value is the number of pieces that
+        have that many copies in the non-seeding peers (including this peer)
+    @type has: C{list} of C{int}
+    @ivar has: values are 1 for the pieces that this peer has
+    @type numgot: C{int}
+    @ivar numgot: the number of pieces this peer has
+    @type done: C{boolean}
+    @ivar done: whether the download is complete
+    @type seed_connections: C{dictionary}
+    @ivar seed_connections: connections that have been made in super-seed mode,
+        keys are L{Connecter.Connection}, values are the piece have that was
+        last sent to the peer
+    @type past_ips: C{dictionary}
+    @ivar past_ips: the IPs that have previously connected in super-seed mode,
+        keys are IP addresses, values are the piece have that was last sent to
+        the peer
+    @type seed_time: C{float}
+    @ivar seed_time: the time when the first peer was seen in super-seed mode
+    @type superseed: C{boolean}
+    @ivar superseed: whether we are in super-seed mode
+    @type seeds_connected: C{int}
+    @ivar seeds_connected: the number of connected seeds
+    @type interests: C{list} of C{list} of C{int}
+    @ivar interests: the interest levels, each level is a list of piece indexes
+        that are at that level
+    @type level_in_interests: C{list} of C{int}
+    @ivar level_in_interests: one per piece, the level that each piece is at
+        in the interests
+    @type pos_in_interests: C{list} of C{int}
+    @ivar pos_in_interests: the position within the interest level that each
+        piece is at
+    @type seed_got_haves: C{list} of C{int}
+    @ivar seed_got_haves: the number of copies of pieces in super-seed mode
+    
+    """
+    
     def __init__(self, numpieces,
                  rarest_first_cutoff = 1, rarest_first_priority_cutoff = 3,
                  priority_step = 20):
+        """Initialize the instance and the piece interests.
+        
+        @type numpieces: C{int}
+        @param numpieces: total number of pieces in the download
+        @type rarest_first_cutoff: C{int}
+        @param rarest_first_cutoff: number of completed piece downloads at
+            which to switch from random piece selection to rarest first
+            (optional, defaults to 1)
+        @type rarest_first_priority_cutoff: C{int}
+        @param rarest_first_priority_cutoff: the number of peers which need to
+            have a piece before other partials take priority over rarest first
+            (optional, defaults to 3)
+        @type priority_step: C{int}
+        @param priority_step: the difference bewteen priority levels 0, 1, and 2
+            (optional, defaults to 20)
+        
+        """
+        
         self.rarest_first_cutoff = rarest_first_cutoff
         self.rarest_first_priority_cutoff = rarest_first_priority_cutoff + priority_step
         self.priority_step = priority_step
@@ -39,6 +128,7 @@
         self._init_interests()
 
     def _init_interests(self):
+        """Initialize the interests in pieces to all not interested."""
         self.interests = [[] for x in xrange(self.priority_step)]
         self.level_in_interests = [self.priority_step] * self.numpieces
         interests = range(self.numpieces)
@@ -51,6 +141,13 @@
 
 
     def got_have(self, piece):
+        """Process a piece that has a new copy found.
+        
+        @type piece: C{int}
+        @param piece: the piece that was copied
+        
+        """
+        
         self.totalcount+=1
         numint = self.numhaves[piece]
         self.numhaves[piece] += 1
@@ -77,6 +174,13 @@
         self._shift_over(piece, self.interests[numint], self.interests[numint + 1])
 
     def lost_have(self, piece):
+        """Process a piece that lost a copy.
+        
+        @type piece: C{int}
+        @param piece: the piece that lost a copy
+        
+        """
+        
         self.totalcount-=1
         numint = self.numhaves[piece]
         self.numhaves[piece] -= 1
@@ -96,6 +200,17 @@
         self._shift_over(piece, self.interests[numint], self.interests[numint - 1])
 
     def _shift_over(self, piece, l1, l2):
+        """Remove a piece from an old interest level to a new one.
+        
+        @type piece: C{int}
+        @param piece: the piece that is to be moved
+        @type l1: C{list} of C{int}
+        @param l1: the old interest level list
+        @type l2: C{list} of C{int}
+        @param l2: the new interest level list
+        
+        """
+        
         assert self.superseed or (not self.has[piece] and self.priority[piece] >= 0)
         parray = self.pos_in_interests
         p = parray[piece]
@@ -117,10 +232,12 @@
 
 
     def got_seed(self):
+        """Process a newly found seed."""
         self.seeds_connected += 1
         self.cutoff = max(self.rarest_first_priority_cutoff-self.seeds_connected,0)
 
     def became_seed(self):
+        """Process this client becoming a seed."""
         self.got_seed()
         self.totalcount -= self.numpieces
         self.numhaves = [i-1 for i in self.numhaves]
@@ -133,15 +250,35 @@
             del self.crosscount2[0]
 
     def lost_seed(self):
+        """Process a lost seed."""
         self.seeds_connected -= 1
         self.cutoff = max(self.rarest_first_priority_cutoff-self.seeds_connected,0)
 
 
     def requested(self, piece):
+        """Add a piece that a request has been sent for to the list of started pieces.
+        
+        @type piece: C{int}
+        @param piece: the piece that is started
+        
+        """
+        
         if piece not in self.started:
             self.started.append(piece)
 
     def _remove_from_interests(self, piece, keep_partial = False):
+        """Remove a piece from the interests.
+        
+        @type piece: C{int}
+        @param piece: the piece that is to be removed
+        @type keep_partial: C{boolean}
+        @param keep_partial: if the piece has been started, whether to keep a
+            note of that so that if it becomes interesting again it can be
+            immediately added to the list of started pieces
+            (optional, defaults to False)
+        
+        """
+        
         l = self.interests[self.level_in_interests[piece]]
         p = self.pos_in_interests[piece]
         assert l[p] == piece
@@ -157,6 +294,13 @@
             pass
 
     def complete(self, piece):
+        """Process a successfully received piece.
+        
+        @type piece: C{int}
+        @param piece: the piece that was received
+        
+        """
+        
         assert not self.has[piece]
         self.has[piece] = 1
         self.numgot += 1
@@ -173,6 +317,18 @@
 
 
     def next(self, haves, wantfunc, complete_first = False):
+        """Choose a piece to request to download next from a peer.
+        
+        @type haves: C{list} of C{int}
+        @param haves: the list of pieces that the peer has
+        @type wantfunc: C{method}
+        @param wantfunc: a method that returns True if the piece is desired
+        @type complete_first: C{boolean}
+        @param complete_first: whether to complete a partially dowloaded piece
+            before requsting a new one (optional, defaults to False)
+        
+        """
+        
         cutoff = self.numgot < self.rarest_first_cutoff
         complete_first = (complete_first or cutoff) and not haves.complete()
         best = None
@@ -203,9 +359,26 @@
 
 
     def am_I_complete(self):
+        """Determine if the download is complete.
+        
+        @rtype: C{boolean}
+        @return: whether the download is complete
+        
+        """
+        
         return self.done
     
     def bump(self, piece):
+        """Move a piece to the end of its interest level.
+        
+        Reduces the priority for downloading this piece, unless it is the only
+        one in its level.
+        
+        @type piece: C{int}
+        @param piece: the piece that is to be downgraded
+        
+        """
+        
         l = self.interests[self.level_in_interests[piece]]
         pos = self.pos_in_interests[piece]
         del l[pos]
@@ -218,6 +391,17 @@
             pass
 
     def set_priority(self, piece, p):
+        """Adjust the priority for a piece.
+        
+        @type piece: C{int}
+        @param piece: the piece that is to be prioritised
+        @type p: C{int}
+        @param p: the new priority for the piece
+        @rtype: C{boolean}
+        @return: whether the downloader should try requesting more
+        
+        """
+        
         if self.superseed:
             return False    # don't muck with this if you're a superseed
         oldp = self.priority[piece]
@@ -265,16 +449,38 @@
         return False
 
     def is_blocked(self, piece):
+        """Determine whether a piece is disabled.
+        
+        @type piece: C{int}
+        @param piece: the piece that is to be checked
+        @rtype: C{boolean}
+        @return: whether the priority is to not download the piece
+        
+        """
+        
         return self.priority[piece] < 0
 
 
     def set_superseed(self):
+        """Switch to super-seeding mode."""
         assert self.done
         self.superseed = True
         self.seed_got_haves = [0] * self.numpieces
         self._init_interests()  # assume everyone is disconnected
 
     def next_have(self, connection, looser_upload):
+        """Determine the next piece to tell a peer we have in super-seed mode.
+        
+        @type connection: L{Connecter.Connection}
+        @param connection: the peer connection the have will be sent on
+        @type looser_upload: C{boolean}
+        @param looser_upload: whether to be looser in determining the piece
+        @rtype: C{int}
+        @return: the piece index to send in the have message, or -1 if
+            something has gone wrong and the connection is to be closed
+        
+        """
+        
         if self.seed_time is None:
             self.seed_time = clock()
             return None
@@ -317,6 +523,13 @@
         return -1       # something screwy; terminate connection
 
     def lost_peer(self, connection):
+        """Process a lost peer in super-seed mode.
+        
+        @type connection: L{Connecter.Connection}
+        @param connection: the peer connection that was lost
+        
+        """
+        
         olddl = self.seed_connections.get(connection)
         if olddl is None:
             return

Modified: debtorrent/trunk/DebTorrent/BT1/Rerequester.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Rerequester.py?rev=189&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Rerequester.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Rerequester.py Sat Jul 28 21:54:58 2007
@@ -2,8 +2,19 @@
 # modified for multitracker operation by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Communicate with a tracker.
+
+ at type mapbase64: C{string}
+ at var mapbase64: the 64 characters to use for a base64 representation
+ at type keys: C{dictionary}
+ at var keys: the key parameters to send to tracker, keys are the announce addresses
+ at type basekeydata: C{string}
+ at var basekeydata: semi-random data to use to create the key
+
+"""
 
 from DebTorrent.zurllib import urlopen, quote
 from urlparse import urlparse, urlunparse
@@ -35,12 +46,28 @@
 basekeydata = str(getpid()) + repr(time()) + 'tracker'
 
 def add_key(tracker):
+    """Create a random base64 key to send to the tracker.
+    
+    @type tracker: C{string}
+    @param tracker: the announce address for the tracker
+    
+    """
+    
     key = ''
     for i in sha(basekeydata+tracker).digest()[-6:]:
         key += mapbase64[ord(i) & 0x3F]
     keys[tracker] = key
 
 def get_key(tracker):
+    """Get the query parameter for the key to send to the tracker.
+    
+    @type tracker: C{string}
+    @param tracker: the announce address for the tracker
+    @rtype: C{string}
+    @return: the query parameter to send to the tracker
+    
+    """
+    
     try:
         return "&key="+keys[tracker]
     except:
@@ -48,19 +75,160 @@
         return "&key="+keys[tracker]
 
 class fakeflag:
+    """A fake flag to use if one is not supplied.
+    
+    @type state: C{boolean}
+    @ivar state: the current state of the flag
+    
+    """
+    
     def __init__(self, state=False):
+        """Set the new flag.
+        
+        @type state: C{boolean}
+        @param state: the initial state of the flag
+        
+        """
+        
         self.state = state
+        
     def wait(self):
+        """Do nothing."""
         pass
+
     def isSet(self):
+        """Check if the current state is set.
+        
+        @rtype: C{boolean}
+        @return: whether the flag is set
+        
+        """
+        
         return self.state
 
 class Rerequester:
+    """Communicate with a tracker.
+    
+    @type sched: C{method}
+    @ivar sched: method to call to schedule future invocation of requester functions
+    @type externalsched: C{method}
+    @ivar externalsched: method to call to schedule future invocation of other functions
+    @type errorfunc: C{method}
+    @ivar errorfunc: method to call when an error occurs
+    @type excfunc: C{method}
+    @ivar excfunc: method to call when an exception occurs
+    @type connect: C{method}
+    @ivar connect: method to call to start connections to new peers
+    @type howmany: C{method}
+    @ivar howmany: method to call to determine how many connections are open
+    @type amount_left: C{method}
+    @ivar amount_left: method to call to determine how much is left to download
+    @type up: C{method}
+    @ivar up: method to call to determine how much has been uploaded
+    @type down: C{method}
+    @ivar down: method to call to determine how much has been downloaded
+    @type upratefunc: C{method}
+    @ivar upratefunc: method to call to determine the current upload rate
+    @type downratefunc: C{method}
+    @ivar downratefunc: method to call to determine the current download rate
+    @type doneflag: C{threading.Event}
+    @ivar doneflag: the flag that indicates when the program is to be shutdown
+    @type unpauseflag: C{threading.Event}
+    @ivar unpauseflag: the flag to unset to pause the download
+    @type seededfunc: C{method}
+    @ivar seededfunc: method to call if the tracker reports the torrent is seeded
+    @type force_rapid_update: C{boolean}
+    @ivar force_rapid_update: whether to do quick tracker updates when requested
+    @type ip: C{string}
+    @ivar ip: IP address to report to the tracker
+    @type minpeers: C{int}
+    @ivar minpeers: minimum number of peers to not do rerequesting
+    @type maxpeers: C{int}
+    @ivar maxpeers: number of peers at which to stop initiating new connections
+    @type interval: C{int}
+    @ivar interval: minimum time to wait between requesting more peers
+    @type timeout: C{int}
+    @ivar timeout: time to wait before assuming that a connection has timed out
+    @type trackerlist: C{list} of C{list} of C{string}
+    @ivar trackerlist: the trackers to connect to
+    @type lastsuccessful: C{string}
+    @ivar lastsuccessful: the last tracker address that was successfully contacted
+    @type rejectedmessage: C{string}
+    @ivar rejectedmessage: the start of the error messages to use when a failure occurs
+    @type url: C{string}
+    @ivar url: the query parameters to send to all trackers
+    @type last: unknown
+    @ivar last: a tracker parameter
+    @type trackerid: unknown
+    @ivar trackerid: a tracker parameter
+    @type announce_interval: C{int}
+    @ivar announce_interval: the tracker-specified announce interval to use
+    @type last_failed: C{boolean}
+    @ivar last_failed: whether the last request was successful
+    @type never_succeeded: C{boolean}
+    @ivar never_succeeded: whether there has ever been a successful request
+    @type errorcodes: C{dictionary}
+    @ivar errorcodes: error codes and messages that have occurred
+    @type lock: L{SuccessLock}
+    @ivar lock: the locks to use to synchronize threaded tracker requests
+    @type special: C{string}
+    @ivar special: a special tracker announce address to send a single request to
+    @type stopped: C{boolean}
+    @ivar stopped: whether the download is stopped
+    
+    """
+    
     def __init__( self, port, myid, infohash, trackerlist, config,
                   sched, externalsched, errorfunc, excfunc, connect,
                   howmany, amount_left, up, down, upratefunc, downratefunc,
                   doneflag, unpauseflag = fakeflag(True),
                   seededfunc = None, force_rapid_update = False ):
+        """Initialize the instance.
+        
+        @type port: C{int}
+        @param port: port to connect to this peer on
+        @type myid: C{string}
+        @param myid: the peer ID to use
+        @type infohash: C{string}
+        @param infohash: the info hash of the torrent being downloaded
+        @type trackerlist: C{list} of C{list} of C{string}
+        @param trackerlist: the trackers to connect to
+        @type config: C{dictionary}
+        @param config: the configuration parameters
+        @type sched: C{method}
+        @param sched: method to call to schedule future invocation of requester functions
+        @type externalsched: C{method}
+        @param externalsched: method to call to schedule future invocation of other functions
+        @type errorfunc: C{method}
+        @param errorfunc: method to call when an error occurs
+        @type excfunc: C{method}
+        @param excfunc: method to call when an exception occurs
+        @type connect: C{method}
+        @param connect: method to call to start connections to new peers
+        @type howmany: C{method}
+        @param howmany: method to call to determine how many connections are open
+        @type amount_left: C{method}
+        @param amount_left: method to call to determine how much is left to download
+        @type up: C{method}
+        @param up: method to call to determine how much has been uploaded
+        @type down: C{method}
+        @param down: method to call to determine how much has been downloaded
+        @type upratefunc: C{method}
+        @param upratefunc: method to call to determine the current upload rate
+        @type downratefunc: C{method}
+        @param downratefunc: method to call to determine the current download rate
+        @type doneflag: C{threading.Event}
+        @param doneflag: the flag that indicates when the program is to be shutdown
+        @type unpauseflag: C{threading.Event}
+        @param unpauseflag: the flag to unset to pause the download
+        @type seededfunc: C{method}
+        @param seededfunc: method to call if the tracker reports the torrent
+            is seeded (optional, defaults to not checking)
+        @type force_rapid_update: C{boolean}
+        @param force_rapid_update: whether to do quick tracker updates when 
+            requested (optional, defaults to False)
+        
+        """
 
         self.sched = sched
         self.externalsched = externalsched
@@ -127,10 +295,12 @@
         self.stopped = False
 
     def start(self):
+        """Start the tracker requester."""
         self.sched(self.c, self.interval/2)
         self.d(0)
 
     def c(self):
+        """Start a periodic general announce request for more peers."""
         if self.stopped:
             return
         if not self.unpauseflag.isSet() and (
@@ -140,9 +310,21 @@
             self._c()
 
     def _c(self):
+        """Schedule another general announce request for more peers."""
         self.sched(self.c, self.interval)
 
     def d(self, event = 3):
+        """Start a periodic announce request.
+        
+        @type event: C{int}
+        @param event: the type of announce request to do (optional, defaults to 3)::
+            0 -- started
+            1 -- completed
+            2 -- stopped
+            3 -- general announce
+        
+        """
+        
         if self.stopped:
             return
         if not self.unpauseflag.isSet():
@@ -151,6 +333,7 @@
         self.announce(event, self._d)
 
     def _d(self):
+        """Schedule another announce request"""
         if self.never_succeeded:
             self.sched(self.d, 60)  # retry in 60 seconds
         elif self.force_rapid_update:
@@ -160,11 +343,39 @@
 
 
     def hit(self, event = 3):
+        """Start a specific type of announce request for more peers.
+        
+        @type event: C{int}
+        @param event: the type of announce request to do (optional, defaults to 3)::
+            0 -- started
+            1 -- completed
+            2 -- stopped
+            3 -- general announce
+        
+        """
+        
         if not self.unpauseflag.isSet() and (
             self.howmany() < self.minpeers or self.force_rapid_update ):
             self.announce(event)
 
     def announce(self, event = 3, callback = lambda: None, specialurl = None):
+        """Create an announce request.
+        
+        @type event: C{int}
+        @param event: the type of announce request to do (optional, defaults to 3)::
+            0 -- started
+            1 -- completed
+            2 -- stopped
+            3 -- general announce
+        @type callback: C{method}
+        @param callback: the method to call when the announce is complete
+            (optional, defaults to doing nothing)
+        @type specialurl: C{string}
+        @param specialurl: a special tracker announce address to send this
+            request to (optional, defaults to the regular tracker list)
+        
+        """
+        
         if specialurl is not None:
             s = self.url+'&uploaded=0&downloaded=0&left=1'   # don't add to statistics
             if self.howmany() >= self.maxpeers:
@@ -195,13 +406,36 @@
         self.rerequest(s, callback)
 
 
-    def snoop(self, peers, callback = lambda: None):  # tracker call support
+    def snoop(self, peers, callback = lambda: None):
+        """Send an immediate request to the tracker.
+        
+        Tracker call support for the tracker-to-tracker communication.
+        
+        @type peers: C{int}
+        @param peers: the number of peers to request
+        @type callback: C{method}
+        @param callback: the method to call when the announce is complete
+            (optional, defaults to doing nothing)
+        
+        """
+        
         self.rerequest(self.url
             +'&event=stopped&port=0&uploaded=0&downloaded=0&left=1&tracker=1&numwant='
             +str(peers), callback)
 
 
     def rerequest(self, s, callback):
+        """Start a threaded request to a tracker.
+        
+        Uses the L{SuccessLock} to make sure concurrent requests are not allowed.
+        
+        @type s: C{string}
+        @param s: the query to add to the URL for the request
+        @type callback: C{method}
+        @param callback: the method to call when the announce is complete
+        
+        """
+        
         if not self.lock.isfinished():  # still waiting for prior cycle to complete??
             def retry(self = self, s = s, callback = callback):
                 self.rerequest(s, callback)
@@ -213,6 +447,15 @@
         rq.start()
 
     def _rerequest(self, s, callback):
+        """Try all the trackers in the list for an announce request.
+        
+        @type s: C{string}
+        @param s: the query to add to the URL for the request
+        @type callback: C{method}
+        @param callback: the method to call when the announce is complete
+        
+        """
+        
         try:
             def fail (self = self, callback = callback):
                 self._fail(callback)
@@ -244,6 +487,13 @@
 
 
     def _fail(self, callback):
+        """Process the failed request.
+        
+        @type callback: C{method}
+        @param callback: the method to call when the announce is complete
+        
+        """
+        
         if ( (self.upratefunc() < 100 and self.downratefunc() < 100)
              or not self.amount_left() ):
             for f in ['rejected', 'bad_data', 'troublecode']:
@@ -260,6 +510,17 @@
 
 
     def rerequest_single(self, t, s, callback):
+        """Start a threaded request to a single tracker and wait for it to complete.
+        
+        @type t: C{string}
+        @param t: the announce address of the tracker to contact
+        @type s: C{string}
+        @param s: the query to add to the URL for the request
+        @type callback: C{method}
+        @param callback: the method to call when the announce is complete
+        
+        """
+        
         l = self.lock.set()
         rq = Thread(target = self._rerequest_single, args = [t, s+get_key(t), l, callback])
         rq.setDaemon(False)
@@ -281,6 +542,19 @@
 
 
     def _rerequest_single(self, t, s, l, callback):
+        """Perform a request to a single tracker.
+        
+        @type t: C{string}
+        @param t: the announce address of the tracker to contact
+        @type s: C{string}
+        @param s: the query to add to the URL for the request
+        @type l: C{long}
+        @param l: the current hold on the lock
+        @type callback: C{method}
+        @param callback: the method to call when the announce is complete
+        
+        """
+        
         try:        
             closer = [None]
             def timedout(self = self, l = l, closer = closer):
@@ -354,6 +628,15 @@
 
 
     def postrequest(self, r, callback):
+        """Process the returned request from a single tracker.
+        
+        @type r: C{dictionary}
+        @param r: the bdecoded data returned by the tracker
+        @type callback: C{method}
+        @param callback: the method to call when the request is complete
+        
+        """
+        
         if r.has_key('warning message'):
                 self.errorfunc('warning from tracker - ' + r['warning message'])
         self.announce_interval = r.get('interval', self.announce_interval)
@@ -401,6 +684,13 @@
         callback()
 
     def exception(self, callback):
+        """Process an exception that occurred during the request..
+        
+        @type callback: C{method}
+        @param callback: the method to call when the request is complete
+        
+        """
+        
         data = StringIO()
         print_exc(file = data)
         def r(s = data.getvalue(), callback = callback):
@@ -413,7 +703,25 @@
 
 
 class SuccessLock:
+    """Locks to synchronize threaded requests to trackers.
+    
+    @type lock: C{threading.Lock)
+    @ivar lock: lock to ensure no concurrent access to this object
+    @type pause: C{threading.Lock)
+    @ivar pause: lock to synchronize sending requests to trackers
+    @type code: C{long}
+    @ivar code: a unique code sent to each setter of the lock
+    @type success: C{boolean}
+    @ivar success: whether the request was successful
+    @type finished: C{boolean}
+    @ivar finished: whether the request is complete
+    @type first: C{boolean}
+    @ivar first: whether the first trip has occurred yet
+    
+    """
+    
     def __init__(self):
+        """Initialize the instance."""
         self.lock = Lock()
         self.pause = Lock()
         self.code = 0L
@@ -421,10 +729,18 @@
         self.finished = True
 
     def reset(self):
+        """Reset the instance to it's initial state."""
         self.success = False
         self.finished = False
 
     def set(self):
+        """Set the lock for a request.
+        
+        @rtype: C{long}
+        @return: the unique identifier code for this request
+        
+        """
+        
         self.lock.acquire()
         if not self.pause.locked():
             self.pause.acquire()
@@ -434,6 +750,15 @@
         return self.code
 
     def trip(self, code, s = False):
+        """Interrupt a not yet finished request.
+        
+        @type code: C{long}
+        @param code: the unique identifier code for the request
+        @type s: C{boolean}
+        @param s: whether to set the request as successful
+        
+        """
+        
         self.lock.acquire()
         try:
             if code == self.code and not self.finished:
@@ -447,19 +772,35 @@
             self.lock.release()
 
     def give_up(self):
+        """Terminate a request unsuccessfully."""
         self.lock.acquire()
         self.success = False
         self.finished = True
         self.lock.release()
 
     def wait(self):
+        """Wait for the current request to complete."""
         self.pause.acquire()
 
     def unwait(self, code):
+        """Stop waiting for a request to complete.
+        
+        @type code: C{long}
+        @param code: the unique identifier code for the request
+        
+        """
+        
         if code == self.code and self.pause.locked():
             self.pause.release()
 
     def isfinished(self):
+        """Check if the current request is complete.
+        
+        @rtype: C{boolean}
+        @return: whether the request is complete
+        
+        """
+        
         self.lock.acquire()
         x = self.finished
         self.lock.release()

Modified: debtorrent/trunk/DebTorrent/download_bt1.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/download_bt1.py?rev=189&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/download_bt1.py (original)
+++ debtorrent/trunk/DebTorrent/download_bt1.py Sat Jul 28 21:54:58 2007
@@ -1109,7 +1109,8 @@
         """Start the tracker requester.
         
         @type seededfunc: C{method}
-        @param seededfunc: unknown
+        @param seededfunc: method to call if the tracker reports the torrent
+            is seeded (optional, defaults to not checking)
         @type force_rapid_update: C{boolean}
         @param force_rapid_update: whether to do quick tracker updates when 
             requested (optional, defaults to False)




More information about the Debtorrent-commits mailing list