[Debtorrent-commits] r75 - /debtorrent/branches/http-listen/DebTorrent/BT1/HTTPDownloader.py
camrdale-guest at users.alioth.debian.org
camrdale-guest at users.alioth.debian.org
Fri Jun 1 02:07:41 UTC 2007
Author: camrdale-guest
Date: Fri Jun 1 02:07:36 2007
New Revision: 75
URL: http://svn.debian.org/wsvn/debtorrent/?sc=1&rev=75
Log:
Documented the HTTPDownloader before modifying it.
Modified:
debtorrent/branches/http-listen/DebTorrent/BT1/HTTPDownloader.py
Modified: debtorrent/branches/http-listen/DebTorrent/BT1/HTTPDownloader.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/branches/http-listen/DebTorrent/BT1/HTTPDownloader.py?rev=75&op=diff
==============================================================================
--- debtorrent/branches/http-listen/DebTorrent/BT1/HTTPDownloader.py (original)
+++ debtorrent/branches/http-listen/DebTorrent/BT1/HTTPDownloader.py Fri Jun 1 02:07:36 2007
@@ -1,8 +1,20 @@
# Written by John Hoffman
# Modified by Cameron Dale
# see LICENSE.txt for license information
-
+#
# $Id$
+
+"""Manage downloading pieces over HTTP.
+
+ at type EXPIRE_TIME: C{int}
+ at var EXPIRE_TIME: number of seconds after which disconnected seeds are expired
+ (not used)
+ at type VERSION: C{string}
+ at var VERSION: the UserAgent identifier sent to all sites
+ at type haveall: L{haveComplete}
+ at var haveall: instance of the seed's bitfield
+
+"""
from DebTorrent.CurrentRateMeasure import Measure
from random import randint
@@ -22,14 +34,80 @@
VERSION = product_name+'/'+version_short
class haveComplete:
+ """Dummy class similar to L{Debtorrent.bitfield.Bitfield}.
+
+ This class represents the HTTP seed's bitfield, which is always complete
+ and has every piece because it is a seed.
+
+ """
def complete(self):
+ """Dummy function to always return true."""
return True
def __getitem__(self, x):
+ """Dummy function to always return true."""
return True
haveall = haveComplete()
class SingleDownload:
+ """Control HTTP downloads from a single site.
+
+ @type downloader: L{HTTPDownloader}
+ @ivar downloader: the collection of all HTTP downloads
+ @type baseurl: C{string}
+ @ivar baseurl: the complete URL to append download info to
+ @type netloc: C{string}
+ @ivar netloc: the webserver address and port to connect to
+ (from the L{baseurl}
+ @type connection: C{HTTPConnection}
+ @ivar connection: the connection to the HTTP server
+ @type seedurl: C{string}
+ @ivar seedurl: the path component from the L{baseurl}
+ @type measure: L{DebTorrent.CurrentRateMeasure.Measure}
+ @ivar measure: tracks the download rate from the site
+ @type index: C{int}
+ @ivar index: the piece index currently being downloaded
+ @type url: C{string}
+ @ivar url: the URL to request from the site
+ @type requests: C{list} of requests
+ @ivar requests: a list of the requests for a piece's ranges
+ @type request_size: C{int}
+ @ivar request_size: the total size of all requests
+ @type endflag: C{boolean}
+ @ivar endflag: unknown
+ @type error: C{string}
+ @ivar error: the error received from the server
+ @type retry_period: C{int}
+ @ivar retry_period: the time to wait before making another request
+ @type _retry_period: C{int}
+ @ivar _retry_period: the server-specified time to wait before making
+ another request
+ @type errorcount: C{int}
+ @ivar errorcount: the number of download errors that have occurred since
+ the last successful download from the site
+ @type goodseed: C{boolean}
+ @ivar goodseed: whether there has been a successful download from the seed
+ @type active: C{boolean}
+ @ivar active: whether there is a download underway
+ @type cancelled: C{boolean}
+ @ivar cancelled: whether the download has been cancelled
+ @type received_data: C{string}
+ @ivar received_data: the data returned from the most recent request
+ @type connection_status: C{int}
+ @ivar connection_status: the status code returned by the server for the
+ most recent request
+
+ """
+
def __init__(self, downloader, url):
+ """Initialize the instance.
+
+ @type downloader: L{HTTPDownloader}
+ @param downloader: the collection of all HTTP downloads
+ @type url: C{string}
+ @param url: the base URL to append download info to
+
+ """
+
self.downloader = downloader
self.baseurl = url
try:
@@ -69,6 +147,13 @@
self.resched(randint(2,10))
def resched(self, len = None):
+ """(Re)Schedule a download from the HTTP seed.
+
+ @type len: C{int}
+ @param len: the amount of time to wait before doing the download (seconds)
+
+ """
+
if len is None:
len = self.retry_period
if self.errorcount > 3:
@@ -76,12 +161,27 @@
self.downloader.rawserver.add_task(self.download, len)
def _want(self, index):
+ """Determine whether the piece is needed.
+
+ @type index: C{int}
+ @param index: the piece index
+ @rtype: C{boolean}
+ @return: whether the piece is needed
+
+ """
+
if self.endflag:
return self.downloader.storage.do_I_have_requests(index)
else:
return self.downloader.storage.is_unstarted(index)
def download(self):
+ """Start a request for a piece.
+
+ Finds a new piece to download from the picker, creates the URL for the
+ request, and then starts the request.
+
+ """
self.cancelled = False
if self.downloader.picker.am_I_complete():
self.downloader.downloads.remove(self)
@@ -105,6 +205,12 @@
self.active = True
def _request(self):
+ """Do the request.
+
+ Send the request to the server and wait for the response. Then
+ process the response and save the result.
+
+ """
import encodings.ascii
import encodings.punycode
import encodings.idna
@@ -130,6 +236,7 @@
self.downloader.rawserver.add_task(self.request_finished)
def request_finished(self):
+ """Process the completed request and schedule another."""
self.active = False
if self.error is not None:
if self.goodseed:
@@ -149,6 +256,16 @@
self.resched()
def _got_data(self):
+ """Process the returned data from the request.
+
+ Update the rate measures, pass the data to the storage, mark the piece
+ as complete.
+
+ @rtype: C[boolean}
+ @return: whether the data was good
+
+ """
+
if self.connection_status == 503: # seed is busy
try:
self.retry_period = max(int(self.received_data),5)
@@ -179,6 +296,7 @@
return True
def _get_requests(self):
+ """Get the requests for a piece."""
self.requests = []
self.request_size = 0L
while self.downloader.storage.do_I_have_requests(self.index):
@@ -188,6 +306,13 @@
self.requests.sort()
def _fulfill_requests(self):
+ """Pass the downloaded data to the storage.
+
+ @rtype: C{boolean}
+ @return: whether the piece was successfully received (hash checked)
+
+ """
+
start = 0L
success = True
while self.requests:
@@ -200,11 +325,19 @@
return success
def _release_requests(self):
+ """Release any pending requests for piece ranges."""
for begin, length in self.requests:
self.downloader.storage.request_lost(self.index, begin, length)
self.requests = []
def _request_ranges(self):
+ """Build a list of ranges to request from the site.
+
+ @rtype: C{string}
+ @return: the comma separated ranges to request
+
+ """
+
s = ''
begin, length = self.requests[0]
for begin1, length1 in self.requests[1:]:
@@ -223,9 +356,67 @@
class HTTPDownloader:
+ """Collection of all the HTTP downloads.
+
+ @type storage: L{StorageWrapper.StorageWrapper}
+ @ivar storage: the piece storage instance
+ @type picker: L{PiecePicker.PiecePicker}
+ @ivar picker: the piece choosing instance
+ @type rawserver: L{Debtorrent.RawServer.RawServer}
+ @ivar rawserver: the server
+ @type finflag: C{Threading.Event}
+ @ivar finflag: the flag indicating when the download is complete
+ @type errorfunc: C{method}
+ @ivar errorfunc: the method to call when an error occurs
+ @type peerdownloader: L{Downloader.Downloader}
+ @ivar peerdownloader: the instance of the collection of normal downloaders
+ @type infohash: C{string}
+ @ivar infohash: the info hash
+ @type max_rate_period: C{float}
+ @ivar max_rate_period: maximum amount of time to guess the current
+ rate estimate represents
+ @type gotpiecefunc: C{method}
+ @ivar gotpiecefunc: the method to call when a piece comes in
+ @type measurefunc: C{method}
+ @ivar measurefunc: the method to call to add downloaded data to the total
+ download rate measurement
+ @type downloads: C{list} of L{SingleDownload}
+ @ivar downloads: the list of all current download connections to sites
+ @type seedsfound: C{int}
+ @ivar seedsfound: the number of seeds successfully downloaded from
+
+ """
+
def __init__(self, storage, picker, rawserver,
finflag, errorfunc, peerdownloader,
max_rate_period, infohash, measurefunc, gotpiecefunc):
+ """Initialize the instance.
+
+ @type storage: L{StorageWrapper.StorageWrapper}
+ @param storage: the piece storage instance
+ @type picker: L{PiecePicker.PiecePicker}
+ @param picker: the piece choosing instance
+ @type rawserver: L{Debtorrent.RawServer.RawServer}
+ @param rawserver: the server
+ @type finflag: C{Threading.Event}
+ @param finflag: the flag indicating when the download is complete
+ @type errorfunc: C{method}
+ @param errorfunc: the method to call when an error occurs
+ @type peerdownloader: L{Downloader.Downloader}
+ @param peerdownloader: the instance of the collection of normal downloaders
+ @type max_rate_period: C{float}
+ @param max_rate_period: maximum amount of time to guess the current
+ rate estimate represents
+ @type infohash: C{string}
+ @param infohash: the info hash
+ @type measurefunc: C{method}
+ @param measurefunc: the method to call to add downloaded data to the total
+ download rate measurement
+ @type gotpiecefunc: C{method}
+ @param gotpiecefunc: the method to call when a piece comes in
+
+ """
+
self.storage = storage
self.picker = picker
self.rawserver = rawserver
@@ -240,15 +431,38 @@
self.seedsfound = 0
def make_download(self, url):
+ """Create a new download from a site.
+
+ @type url: C{string}
+ @param url: the base URL to use for downloading from that site
+ @rtype: L{SingleDownload}
+ @return: the SingleDownload instance created
+
+ """
+
self.downloads.append(SingleDownload(self, url))
return self.downloads[-1]
def get_downloads(self):
+ """Get the list of all current downloads.
+
+ @rtype: C{list} of L{SingleDownload}
+ @return: all current downloads from sites
+
+ """
+
if self.finflag.isSet():
return []
return self.downloads
def cancel_piece_download(self, pieces):
+ """Cancel any active downloads for the pieces.
+
+ @type pieces: C{list} of C{int}
+ @param pieces: the list of pieces to cancel downloads of
+
+ """
+
for d in self.downloads:
if d.active and d.index in pieces:
d.cancelled = True
More information about the Debtorrent-commits
mailing list