r114 - in /debtorrent/trunk/DebTorrent: BT1/AptListener.py BT1/Connecter.py HTTPCache.py HTTPHandler.py PSYCO.py RateLimiter.py iprangeparse.py natpunch.py parseargs.py parsedir.py piecebuffer.py
camrdale-guest at users.alioth.debian.org
camrdale-guest at users.alioth.debian.org
Sun Jun 17 04:35:51 UTC 2007
Author: camrdale-guest
Date: Sun Jun 17 04:35:50 2007
New Revision: 114
URL: http://svn.debian.org/wsvn/debtorrent/?sc=1&rev=114
Log:
More documentation.
Modified:
debtorrent/trunk/DebTorrent/BT1/AptListener.py
debtorrent/trunk/DebTorrent/BT1/Connecter.py
debtorrent/trunk/DebTorrent/HTTPCache.py
debtorrent/trunk/DebTorrent/HTTPHandler.py
debtorrent/trunk/DebTorrent/PSYCO.py
debtorrent/trunk/DebTorrent/RateLimiter.py
debtorrent/trunk/DebTorrent/iprangeparse.py
debtorrent/trunk/DebTorrent/natpunch.py
debtorrent/trunk/DebTorrent/parseargs.py
debtorrent/trunk/DebTorrent/parsedir.py
debtorrent/trunk/DebTorrent/piecebuffer.py
Modified: debtorrent/trunk/DebTorrent/BT1/AptListener.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/AptListener.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/AptListener.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/AptListener.py Sun Jun 17 04:35:50 2007
@@ -527,8 +527,6 @@
@type path: C{list} of C{string}
@param path: the path of the file to download, starting with the mirror name
- @type data: C{string}
- @param data: the downloaded newly cached file
@type r: (C{int}, C{string}, C{dictionary}, C{string})
@param r: the HTTP status code, status message, headers, and cached data
Modified: debtorrent/trunk/DebTorrent/BT1/Connecter.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Connecter.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Connecter.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Connecter.py Sun Jun 17 04:35:50 2007
@@ -104,7 +104,7 @@
@ivar download: the Downloader instance to use for the connection
@type send_choke_queued: C{boolean}
@ivar send_choke_queued: whether to suppress the next L{CHOKE} message
- @type just_unchoked: C{long}
+ @type just_unchoked: C{int}
@ivar just_unchoked: the time of a recent L{UNCHOKE}, if it was the first
"""
Modified: debtorrent/trunk/DebTorrent/HTTPCache.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/HTTPCache.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/HTTPCache.py (original)
+++ debtorrent/trunk/DebTorrent/HTTPCache.py Sun Jun 17 04:35:50 2007
@@ -57,7 +57,7 @@
@type connection_status: C{int}
@ivar connection_status: the status code returned by the server
@type connection_response: C{string}
- @ivar connection_status: the status message returned by the server
+ @ivar connection_response: the status message returned by the server
"""
Modified: debtorrent/trunk/DebTorrent/HTTPHandler.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/HTTPHandler.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/HTTPHandler.py (original)
+++ debtorrent/trunk/DebTorrent/HTTPHandler.py Sun Jun 17 04:35:50 2007
@@ -1,8 +1,19 @@
# Written by Bram Cohen
# Modified by Cameron Dale
# see LICENSE.txt for license information
-
+#
# $Id$
+
+"""Handles incoming HTTP connections from other clients to this server.
+
+ at type DEBUG: C{boolean}
+ at var DEBUG: whether to print debugging messages
+ at type weekdays: C{list} of C{string}
+ at var weekdays: the days of the week
+ at type months: C{list} of C{string}
+ at var months: the months of the year
+
+"""
from cStringIO import StringIO
from sys import stdout
@@ -23,7 +34,47 @@
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
class HTTPConnection:
+ """A single connection from an HTTP client.
+
+ Handles a single HTTP GET or HEAD request from a client using HTTP/1.0.
+
+ @type handler: L{HTTPHandler}
+ @ivar handler: the handler for all incoming HTTP connections
+ @type connection: unknown
+ @ivar connection: the new connection that was created
+ @type buf: C{string}
+ @ivar buf: unknown
+ @type closed: C{boolean}
+ @ivar closed: unknown
+ @type done: C{boolean}
+ @ivar done: unknown
+ @type donereading: C{boolean}
+ @ivar donereading: unknown
+ @type next_func: C{method}
+ @ivar next_func: the next method to call to process data on this connection
+ @type header: unknown
+ @ivar header: unknown
+ @type command: unknown
+ @ivar command: unknown
+ @type pre1: unknown
+ @ivar pre1: unknown
+ @type headers: unknown
+ @ivar headers: unknown
+ @type encoding: unknown
+ @ivar encoding: unknown
+
+ """
+
def __init__(self, handler, connection):
+ """Initialize the instance.
+
+ @type handler: L{HTTPHandler}
+ @param handler: the handler for all incoming HTTP connections
+ @type connection: unknown
+ @param connection: the new connection that was created
+
+ """
+
self.handler = handler
self.connection = connection
self.buf = ''
@@ -33,9 +84,28 @@
self.next_func = self.read_type
def get_ip(self):
+ """Get the IP address of the connection.
+
+ @rtype: C{string}
+ @return: the IP address
+
+ """
+
return self.connection.get_ip()
def data_came_in(self, data):
+ """Process data that came in on the connection.
+
+ Processes the request lines one at a time by calling the L{next_func}
+ method with the lines.
+
+ @type data: C{string}
+ @param data: the data that came in
+ @rtype: C{boolean}
+ @return: whether to keep the connection open
+
+ """
+
if self.donereading or self.next_func is None:
return True
self.buf += data
@@ -53,6 +123,15 @@
return False
def read_type(self, data):
+ """Process the first header line that came in.
+
+ @type data: C{string}
+ @param data: the line that came in
+ @rtype: C{method}
+ @return: the next method to call to process data on this connection
+
+ """
+
self.header = data.strip()
words = data.split()
if len(words) == 3:
@@ -71,6 +150,15 @@
return self.read_header
def read_header(self, data):
+ """Process the next header line that came in.
+
+ @type data: C{string}
+ @param data: the line that came in
+ @rtype: C{method}
+ @return: the next method to call to process data on this connection
+
+ """
+
data = data.strip()
if data == '':
self.donereading = True
@@ -92,6 +180,19 @@
return self.read_header
def answer(self, (responsecode, responsestring, headers, data)):
+ """Send a response to the client on the connection and close it.
+
+ @type responsecode: C{int}
+ @param responsecode: the response code to send
+ @type responsestring: C{string}
+ @param responsestring: the response string to send
+ @type headers: C{dictionary}
+ @param headers: the headers to send with the response
+ @type data: C{string}
+ @param data: the data to send with the response
+
+ """
+
if self.closed:
return
if self.encoding == 'gzip':
@@ -133,20 +234,64 @@
self.connection.shutdown(1)
class HTTPHandler:
+ """The handler for all new and existing HTTP connections.
+
+ @type connections: C{dictionary}
+ @ivar connections: all the existing connections, keys are the connection
+ objects, values are the L{HTTPConnection} objects
+ @type getfunc: C{method}
+ @ivar getfunc: the method to call with the processed GET requests
+ @type minflush: C{float}
+ @ivar minflush: the minimum amount of time between flushing the log
+ @type lastflush: C{float}
+ @ivar lastflush: the time of the last log flush
+
+ """
+
def __init__(self, getfunc, minflush):
+ """Initialize the instance.
+
+ @type getfunc: C{method}
+ @param getfunc: the method to call with the processed GET requests
+ @type minflush: C{float}
+ @param minflush: the minimum amount of time between flushing the log
+
+ """
+
self.connections = {}
self.getfunc = getfunc
self.minflush = minflush
self.lastflush = clock()
def external_connection_made(self, connection):
+ """Create a new HTTPConnection object.
+
+ @type connection: unknown
+ @param connection: the connection
+
+ """
+
self.connections[connection] = HTTPConnection(self, connection)
def connection_flushed(self, connection):
+ """Flush a connection.
+
+ @type connection: unknown
+ @param connection: the connection
+
+ """
+
if self.connections[connection].done:
connection.shutdown(1)
def connection_lost(self, connection):
+ """Remove the lost connection from the existing ones.
+
+ @type connection: unknown
+ @param connection: the connection
+
+ """
+
ec = self.connections[connection]
ec.closed = True
del ec.connection
@@ -154,12 +299,42 @@
del self.connections[connection]
def data_came_in(self, connection, data):
+ """Process incoming data on an existing connection.
+
+ @type connection: unknown
+ @param connection: the connection
+ @type data: C{string}
+ @param data: the data that came in
+
+ """
+
c = self.connections[connection]
if not c.data_came_in(data) and not c.closed:
c.connection.shutdown(1)
def log(self, ip, ident, username, header,
responsecode, length, referrer, useragent):
+ """Print a log message.
+
+ @type ip: C{string}
+ @param ip: the IP address of the connection
+ @type ident: C{string}
+ @param ident: the type of connection
+ @type username: C{string}
+ @param username: unknown
+ @type header: C{string}
+ @param header: the first header line of the request
+ @type responsecode: C{int}
+ @param responsecode: the HTTP status code of the response
+ @type length: C{int}
+ @param length: the number of bytes in the data returned
+ @type referrer: C{string}
+ @param referrer: the referer for the incoming request
+ @type useragent: C{string}
+ @param useragent: the client's useragent used to make the request
+
+ """
+
year, month, day, hour, minute, second, a, b, c = time.localtime(time.time())
print '%s %s %s [%02d/%3s/%04d:%02d:%02d:%02d] "%s" %i %i "%s" "%s"' % (
ip, ident, username, day, months[month], year, hour,
Modified: debtorrent/trunk/DebTorrent/PSYCO.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/PSYCO.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/PSYCO.py (original)
+++ debtorrent/trunk/DebTorrent/PSYCO.py Sun Jun 17 04:35:50 2007
@@ -1,10 +1,19 @@
# Modified by Cameron Dale
# see LICENSE.txt for license information
-
+#
# $Id$
-# edit this file to enable/disable Psyco
-# psyco = 1 -- enabled
-# psyco = 0 -- disabled
+"""Whether to use the Psyco extension module.
+
+Edit this file to enable/disable the use of the Psyco extension module to
+speed up the execution of the code.
+
+1 => enabled
+0 => disabled
+
+ at type psyco: C{int}
+ at var psyco: whether to use the Psyco extension module
+
+"""
psyco = 0
Modified: debtorrent/trunk/DebTorrent/RateLimiter.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/RateLimiter.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/RateLimiter.py (original)
+++ debtorrent/trunk/DebTorrent/RateLimiter.py Sun Jun 17 04:35:50 2007
@@ -1,8 +1,43 @@
# Written by Bram Cohen
# Modified by Cameron Dale
# see LICENSE.txt for license information
-
+#
# $Id$
+
+"""Limit the upload rate.
+
+ at type DEBUG: C{boolean}
+ at var DEBUG: whether to print debugging messages
+ at type MAX_RATE_PERIOD: C{float}
+ at var MAX_RATE_PERIOD: unknown
+ at type MAX_RATE: C{float}
+ at var MAX_RATE: the (very large) limit to use to not limit the upload rate
+ at type PING_BOUNDARY: C{int}
+ at var PING_BOUNDARY: unknown
+ at type PING_SAMPLES: C{int}
+ at var PING_SAMPLES: unknown
+ at type PING_DISCARDS: C{int}
+ at var PING_DISCARDS: unknown
+ at type PING_THRESHHOLD: C{int}
+ at var PING_THRESHHOLD: unknown
+ at type PING_DELAY: C{int}
+ at var PING_DELAY: unknown
+ at type PING_DELAY_NEXT: C{int}
+ at var PING_DELAY_NEXT: unknown
+ at type ADJUST_UP: C{float}
+ at var ADJUST_UP: unknown
+ at type ADJUST_DOWN: C{float}
+ at var ADJUST_DOWN: unknown
+ at type UP_DELAY_FIRST: C{int}
+ at var UP_DELAY_FIRST: unknown
+ at type UP_DELAY_NEXT: C{int}
+ at var UP_DELAY_NEXT: unknown
+ at type SLOTS_STARTING: C{int}
+ at var SLOTS_STARTING: unknown
+ at type SLOTS_FACTOR: C{float}
+ at var SLOTS_FACTOR: unknown
+
+"""
from traceback import print_exc
from binascii import b2a_hex
@@ -39,7 +74,48 @@
SLOTS_FACTOR = 1.66/1000
class RateLimiter:
+ """Limit the upload rate.
+
+ @type sched: C{method}
+ @ivar sched: the method to call to schedule a task with the server
+ @type last: L{BT1.Connecter.Connection}
+ @ivar last: the last connection on the circular queue of connections to send on
+ @type unitsize: unknown
+ @ivar unitsize: unknown
+ @type slotsfunc: C{method}
+ @ivar slotsfunc: the method to call to set the number of connections limits
+ @type measure: L{CurrentRateMeasure.Measure}
+ @ivar measure: the measurer to use to help calculate the upload rate
+ @type autoadjust: C{boolean}
+ @ivar autoadjust: whether the upload limit is being automatically adjusted
+ @type upload_rate: C{float}
+ @ivar upload_rate: the maximum upload rate to limit to
+ @type slots: C{int}
+ @ivar slots: the number of upload slots to use (for automatic adjustment)
+ @type autoadjustup: C{int}
+ @ivar autoadjustup: unknown
+ @type pings: unknown
+ @ivar pings: unknown
+ @type lasttime: unknown
+ @ivar lasttime: unknown
+ @type bytes_sent: C{int}
+ @ivar bytes_sent: the number of bytes sent on the most recent attempt
+
+ """
+
def __init__(self, sched, unitsize, slotsfunc = lambda x: None):
+ """Initialize the instance.
+
+ @type sched: C{method}
+ @param sched: the method to call to schedule a task with the server
+ @type unitsize: unknown
+ @param unitsize: unknown
+ @type slotsfunc: C{method}
+ @param slotsfunc: the method to call to set the number of connections limits
+ (optional, defaults to not setting anything)
+
+ """
+
self.sched = sched
self.last = None
self.unitsize = unitsize
@@ -50,7 +126,13 @@
self.slots = SLOTS_STARTING # garbage if not automatic
def set_upload_rate(self, rate):
- # rate = -1 # test automatic
+ """Set the upload rate to limit to.
+
+ @type rate: C{float}
+ @param rate: maximum KB/s to upload at (0 = no limit, -1 = automatic)
+
+ """
+
if rate < 0:
if self.autoadjust:
return
@@ -69,6 +151,18 @@
self.bytes_sent = 0
def queue(self, conn):
+ """Queue the connection for later uploading.
+
+ The queue is actually stored in the L{BT1.Connecter.Connection} objects
+ using their next_upload instance variable, and is circular.
+
+ If the queue is empty, this will start the queue processer.
+
+ @type conn: L{BT1.Connecter.Connection}
+ @param conn: the connection to add to the queue for uploading to
+
+ """
+
assert conn.next_upload is None
if self.last is None:
self.last = conn
@@ -80,18 +174,33 @@
self.last = conn
def try_send(self, check_time = False):
+ """Loop through the circular queue of upload connections, trying to send on each.
+
+ @type check_time: C{boolean}
+ @param check_time: unknown
+
+ """
+
t = clock()
self.bytes_sent -= (t - self.lasttime) * self.upload_rate
self.lasttime = t
if check_time:
self.bytes_sent = max(self.bytes_sent, 0)
+
+ # Get the first connection (the next one after the last one)
cur = self.last.next_upload
+
+ # Loop until some data has been sent (or the queue is empty)
while self.bytes_sent <= 0:
+ # Try sending bytes on it
bytes = cur.send_partial(self.unitsize)
self.bytes_sent += bytes
self.measure.update_rate(bytes)
+
+ # If nothing could be sent, remove the connection from the queue
if bytes == 0 or cur.backlogged():
if self.last is cur:
+ # If this is the only connection in the queue, stop the processer
self.last = None
cur.next_upload = None
break
@@ -100,17 +209,33 @@
cur.next_upload = None
cur = self.last.next_upload
else:
+ # Go to the next connection
self.last = cur
cur = cur.next_upload
else:
+ # The queue is not empty, so schedule a future attempt to send
self.sched(self.try_send, self.bytes_sent / self.upload_rate)
def adjust_sent(self, bytes):
+ """Add data from other places to this measure.
+
+ @type bytes: C{int}
+ @param bytes: the amount of data that was sent/received
+
+ """
+
self.bytes_sent = min(self.bytes_sent+bytes, self.upload_rate*3)
self.measure.update_rate(bytes)
def ping(self, delay):
+ """Use the new ping time to calculate an automatically adjusted upload limit.
+
+ @type delay: C{float}
+ @param delay: the elapsed time between unchoking and receiving a request
+
+ """
+
if DEBUG:
print 'ping delay:', delay
if not self.autoadjust:
@@ -150,7 +275,3 @@
self.lasttime = clock()
self.bytes_sent = 0
self.autoadjustup = UP_DELAY_NEXT
-
-
-
-
Modified: debtorrent/trunk/DebTorrent/iprangeparse.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/iprangeparse.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/iprangeparse.py (original)
+++ debtorrent/trunk/DebTorrent/iprangeparse.py Sun Jun 17 04:35:50 2007
@@ -1,8 +1,16 @@
# Written by John Hoffman
# Modified by Cameron Dale
# see LICENSE.txt for license information
-
+#
# $Id$
+
+"""Deal with all types of IP addresses and IP address ranges.
+
+ at type ipv4addrmask: C{long}
+ at var ipv4addrmask: the address mask used to determine if the IP address
+ in C{long} format is v4 encapsulated in a v6 address
+
+"""
from bisect import bisect, insort
@@ -15,6 +23,16 @@
def to_long_ipv4(ip):
+ """Convert an IP address from a string to a long.
+
+ @type ip: C{string}
+ @param ip: the IP address
+ @rtype: C{long}
+ @return: the same IP address
+ @raises ValueError: if the input IP address is poorly formatted
+
+ """
+
ip = ip.split('.')
if len(ip) != 4:
raise ValueError, "bad address"
@@ -26,6 +44,16 @@
def to_long_ipv6(ip):
+ """Convert an IPv6 address from a string to a long.
+
+ @type ip: C{string}
+ @param ip: the IPv6 address
+ @rtype: C{long}
+ @return: the same IPv6 address
+ @raises ValueError: if the input IPv6 address is poorly formatted
+
+ """
+
if ip == '':
raise ValueError, "bad address"
if ip == '::': # boundary handling
@@ -71,7 +99,30 @@
ipv4addrmask = 65535L*256*256*256*256
class IP_List:
+ """Stores mutltiple IP address ranges.
+
+ @type ipv4list: C{list} of C{long}
+ @ivar ipv4list: the starting IP addresses of the ranges
+ @type ipv4dict: C{dictionary} of {C{long}: C{long}}
+ @ivar ipv4dict: the IP address ranges, keys are the starting
+ IP addresses, values are the ends of the IP address ranges
+ @type ipv6list: C{list} of C{long}
+ @ivar ipv6list: the starting IPv6 addresses of the ranges
+ @type ipv6dict: C{dictionary} of {C{long}: C{long}}
+ @ivar ipv6dict: the IPv6 address ranges, keys are the starting
+ IPv6 addresses, values are the ends of the IPv6 address ranges
+
+ """
+
def __init__(self, entrylist=None):
+ """Initialize the instance.
+
+ @type entrylist: C{list} of (C{string}, C{string})
+ @param entrylist: the IP address ranges to start with
+ (optional, defaults to None)
+
+ """
+
self.ipv4list = [] # starts of ranges
self.ipv4dict = {} # start: end of ranges
self.ipv6list = [] # "
@@ -100,10 +151,27 @@
self._import_ipv6(l6)
def __nonzero__(self):
+ """Check whether there are any IP address ranges stored.
+
+ @rtype: C{boolean}
+ @return: whether there are IP address ranges stored
+
+ """
+
return bool(self.ipv4list or self.ipv6list)
def append(self, ip_beg, ip_end = None):
+ """Add a new IP address range.
+
+ @type ip_beg: C{string}
+ @param ip_beg: the beginning IP address for the range
+ @type ip_end: C{string}
+ @param ip_end: the neding Ip address for the range
+ (optional, defaults to the beginning IP address)
+
+ """
+
if ip_end is None:
ip_end = ip_beg
else:
@@ -151,7 +219,14 @@
d[ip_beg] = ip_end
- def _import_ipv4(self, entrylist): #entrylist = sorted list of pairs of ipv4s converted to longs
+ def _import_ipv4(self, entrylist):
+ """Initialize an empty IPv4 storage with IPv4 address ranges.
+
+ @type entrylist: C{list} of (C{long}, C{long})
+ @param entrylist: the IPv4 address ranges to start with
+
+ """
+
assert not self.ipv4list
if not entrylist:
return
@@ -170,7 +245,14 @@
for b,e in l:
self.ipv4dict[b] = e
- def _import_ipv6(self, entrylist): #entrylist = sorted list of pairs of ipv6s converted to longs
+ def _import_ipv6(self, entrylist):
+ """Initialize an empty IPv6 storage with IPv6 address ranges.
+
+ @type entrylist: C{list} of (C{long}, C{long})
+ @param entrylist: the IPv6 address ranges to start with
+
+ """
+
assert not self.ipv6list
if not entrylist:
return
@@ -191,6 +273,15 @@
def includes(self, ip):
+ """Determine whether the IP address is included in any of the ranges.
+
+ @type ip: C{string}
+ @param ip: the IP address to check
+ @rtype: C{boolean}
+ @return: whether the IP address is in one of the ranges
+
+ """
+
if not (self.ipv4list or self.ipv6list):
return False
if ip.find(':') < 0: # IPv4
@@ -215,10 +306,20 @@
return True
return False
-
- # reads a list from a file in the format 'whatever:whatever:ip-ip'
- # (not IPv6 compatible at all)
def read_rangelist(self, file):
+ """Parse a file for lists of IPv4 address ranges to initialize the empty storage with.
+
+ The file to parse must have lines in the format 'whatever:whatever:ip-ip'.
+ The 'whatever' will be ignored, and the IP addresses must be in IPv4
+ format. If the rang is only a single IP address, omit the '-' and the
+ second 'ip'. Empty lines will be ignored, as will lines beginning with
+ '#' which can be used for comments.
+
+ @type file: C{string}
+ @param file: the name of the file to parse
+
+ """
+
l = []
f = open(file, 'r')
while True:
@@ -246,9 +347,27 @@
def is_ipv4(ip):
+ """Determine whether the IP address is in the IPv4 format.
+
+ @type ip: C{string}
+ @param ip: the IP address to check
+ @rtype: C{boolean}
+ @return: whether the IP address is for IPv4
+
+ """
+
return ip.find(':') < 0
def is_valid_ip(ip):
+ """Determine whether the IP address is a valid IPv4 or IPv6 address.
+
+ @type ip: C{string}
+ @param ip: the IP address to check
+ @rtype: C{boolean}
+ @return: whether the IP address is valid
+
+ """
+
try:
if is_ipv4(ip):
a = ip.split('.')
Modified: debtorrent/trunk/DebTorrent/natpunch.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/natpunch.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/natpunch.py (original)
+++ debtorrent/trunk/DebTorrent/natpunch.py Sun Jun 17 04:35:50 2007
@@ -3,8 +3,29 @@
# and from example code by Myers Carpenter
# Modified by Cameron Dale
# see LICENSE.txt for license information
-
+#
# $Id$
+
+"""UPnP methods for opening ports in firewalls (Windows only).
+
+ at type DEBUG: C{boolean}
+ at var DEBUG: whether to print debugging messages
+ at type EXPIRE_CACHE: C{int}
+ at var EXPIRE_CACHE: unknown
+ at type ID: unknown
+ at var ID: unknown
+ at type _upnp_: unknown
+ at var _upnp_: unknown
+ at type UPnP_test: unknown
+ at var UPnP_test: unknown
+ at type UPnP_open_port: unknown
+ at var UPnP_open_port: unknown
+ at type UPnP_close_port: unknown
+ at var UPnP_close_port: unknown
+ at type UPnP_reset: unknown
+ at var UPnP_reset: unknown
+
+"""
import socket
from traceback import print_exc
@@ -30,9 +51,18 @@
-class _UPnP1: # derived from Myers Carpenter's code
- # seems to use the machine's local UPnP
- # system for its operation. Runs fairly fast
+class _UPnP1:
+ """A UPnP method.
+
+ Derived from Myers Carpenter's code. Seems to use the machine's local
+ UPnP system for its operation. Runs fairly fast.
+
+ @type map: unknown
+ @ivar map: unknown
+ @type last_got_map: unknown
+ @ivar last_got_map: unknown
+
+ """
def __init__(self):
self.map = None
@@ -58,6 +88,15 @@
def open(self, ip, p):
+ """
+
+ @type ip: unknown
+ @param ip: unknown
+ @type p: unknown
+ @param p: unknown
+
+ """
+
map = self._get_map()
try:
map.Add(p,'TCP',p,ip,True,ID)
@@ -73,6 +112,13 @@
def close(self, p):
+ """
+
+ @type p: unknown
+ @param p: unknown
+
+ """
+
map = self._get_map()
try:
map.Remove(p,'TCP')
@@ -88,6 +134,13 @@
def clean(self, retry = False):
+ """
+
+ @type retry: unknown
+ @param retry: unknown
+
+ """
+
if not _supported:
return
try:
@@ -115,10 +168,20 @@
pass
-class _UPnP2: # derived from Yejun Yang's code
- # apparently does a direct search for UPnP hardware
- # may work in some cases where _UPnP1 won't, but is slow
- # still need to implement "clean" method
+class _UPnP2:
+ """Another UPnP method.
+
+ Derived from Yejun Yang's code
+ # apparently does a direct search for UPnP hardware
+ # may work in some cases where _UPnP1 won't, but is slow
+ # still need to implement "clean" method
+
+ @type services: unknown
+ @ivar services: unknown
+ @type last_got_services: unknown
+ @ivar last_got_services: unknown
+
+ """
def __init__(self):
self.services = None
@@ -160,6 +223,15 @@
def open(self, ip, p):
+ """
+
+ @type ip: unknown
+ @param ip: unknown
+ @type p: unknown
+ @param p: unknown
+
+ """
+
svcs = self._get_services()
success = False
for s in svcs:
@@ -175,6 +247,13 @@
def close(self, p):
+ """
+
+ @type p: unknown
+ @param p: unknown
+
+ """
+
svcs = self._get_services()
success = False
for s in svcs:
@@ -189,7 +268,24 @@
return success
-class _UPnP: # master holding class
+class _UPnP:
+ """Master holding class.
+
+ @type upnp1: unknown
+ @ivar upnp1: unknown
+ @type upnp2: unknown
+ @ivar upnp2: unknown
+ @type upnplist: unknown
+ @ivar upnplist: unknown
+ @type upnp: unknown
+ @ivar upnp: unknown
+ @type local_ip: unknown
+ @ivar local_ip: unknown
+ @type last_got_ip: unknown
+ @ivar last_got_ip: unknown
+
+ """
+
def __init__(self):
self.upnp1 = _UPnP1()
self.upnp2 = _UPnP2()
@@ -221,6 +317,13 @@
return self.local_ip
def test(self, upnp_type):
+ """
+
+ @type upnp_type: unknown
+ @param upnp_type: unknown
+
+ """
+
if DEBUG:
print 'testing UPnP type '+str(upnp_type)
if not upnp_type or not _supported or self.get_ip() is None:
@@ -238,10 +341,24 @@
return 0
def open(self, p):
+ """
+
+ @type p: unknown
+ @param p: unknown
+
+ """
+
assert self.upnp, "must run UPnP_test() with the desired UPnP access type first"
return self.upnp.open(self.get_ip(), p)
def close(self, p):
+ """
+
+ @type p: unknown
+ @param p: unknown
+
+ """
+
assert self.upnp, "must run UPnP_test() with the desired UPnP access type first"
return self.upnp.close(p)
Modified: debtorrent/trunk/DebTorrent/parseargs.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/parseargs.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/parseargs.py (original)
+++ debtorrent/trunk/DebTorrent/parseargs.py Sun Jun 17 04:35:50 2007
@@ -1,14 +1,31 @@
# Written by Bill Bumgarner and Bram Cohen
# Modified by Cameron Dale
# see LICENSE.txt for license information
-
+#
# $Id$
+
+"""Functions for dealing with arguments, defaults and options."""
from types import *
from cStringIO import StringIO
def splitLine(line, COLS=80, indent=10):
+ """Split an output line to a screen width (with indenting).
+
+ @type line: C{string}
+ @param line: the output line to split
+ @type COLS: C{int}
+ @param COLS: the number of columns in the screen width
+ (optional, defaults to 80)
+ @type indent: C{int}
+ @param indent: the number of columns to indent the output lines with spaces
+ (optional, defaults to 10)
+ @rtype: C{string}
+ @return: the multiple lines formatted for output
+
+ """
+
indent = " " * indent
width = COLS - (len(indent) + 1)
if indent and width < 15:
@@ -30,6 +47,20 @@
return s.getvalue()
def formatDefinitions(options, COLS, presets = {}):
+ """Format configuration options for printing to the user.
+
+ @type options: C{list} of (C{string}, unknown, C{string})
+ @param options: the name, default value, and description for each of
+ the configuration options
+ @type COLS: C{int}
+ @param COLS: the width of the screen to format the output for
+ @type presets: C{dictionary}
+ @param presets: other default values to use instead (optional)
+ @rtype: C{string}
+ @return: the formatted options for output
+
+ """
+
s = StringIO()
for (longname, default, doc) in options:
s.write('--' + longname + ' <arg>\n')
@@ -47,10 +78,28 @@
def usage(str):
+ """Raise an error to indicate a problem.
+
+ @type str: C{string}
+ @param str: the error that occurred
+ @raise ValueError: always
+
+ """
+
raise ValueError(str)
def defaultargs(options):
+ """Make a dictionary of all the default options.
+
+ @type options: C{list} of (C{string}, unknown, C{string})
+ @param options: the name, default value, and description for each of
+ the configuration options
+ @rtype: C{dictionary}
+ @return: the default options, keys are the option names
+
+ """
+
l = {}
for (longname, default, doc) in options:
if default is not None:
@@ -59,6 +108,33 @@
def parseargs(argv, options, minargs = None, maxargs = None, presets = {}):
+ """Parse a list of input arguments and set the configuration options variable.
+
+ All configuration options must begin with '--', must be followed by a space
+ and then the new setting to use, and must appear in the options variable
+ keys. Non-options can appear anywhere in the arguments (except between an
+ option and it's setting), and there must be between minargs and maxargs of
+ them.
+
+ @type argv: C{list} of C{string}
+ @param argv: the input command-line arguments
+ @type options: C{list} of (C{string}, unknown, C{string})
+ @param options: the name, default value, and description for each of
+ the configuration options
+ @type minargs: C{int}
+ @param minargs: the minimum number of non-option arguments required
+ (optional, defaults to no minimum)
+ @type maxargs: C{int}
+ @param maxargs: the maximum number of non-option arguments required
+ (optional, defaults to no maximum)
+ @type presets: C{dictionary}
+ @param presets: other default values to use instead (optional)
+ @rtype: (C{dictionary}, C{list})
+ @return: the configuration options, and any remaining non-option arguments
+ @raise ValueError: by calling L{usage} if something goes wrong
+
+ """
+
config = {}
longkeyed = {}
for option in options:
@@ -104,6 +180,8 @@
return (config, args)
def test_parseargs():
+ """Test the L{parseargs} function for errors."""
+
assert parseargs(('d', '--a', 'pq', 'e', '--b', '3', '--c', '4.5', 'f'), (('a', 'x', ''), ('b', 1, ''), ('c', 2.3, ''))) == ({'a': 'pq', 'b': 3, 'c': 4.5}, ['d', 'e', 'f'])
assert parseargs([], [('a', 'x', '')]) == ({'a': 'x'}, [])
assert parseargs(['--a', 'x', '--a', 'y'], [('a', '', '')]) == ({'a': 'y'}, [])
Modified: debtorrent/trunk/DebTorrent/parsedir.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/parsedir.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/parsedir.py (original)
+++ debtorrent/trunk/DebTorrent/parsedir.py Sun Jun 17 04:35:50 2007
@@ -1,8 +1,15 @@
# Written by John Hoffman and Uoti Urpala
# Modified by Cameron Dale
# see LICENSE.txt for license information
-
+#
# $Id$
+
+"""Parse a directory for torrent files.
+
+ at type NOISY: C{boolean}
+ at var NOISY: whether to print additional status messages about the parsing
+
+"""
from bencode import bencode, bdecode
from download_bt1 import get_response
@@ -19,11 +26,43 @@
NOISY = True
def _errfunc(x):
+ """The default output printing function to use.
+
+ @type x: C{string}
+ @param x: the output message to print
+
+ """
+
print ":: "+x
def parsedir(directory, parsed, files, blocked,
exts = ['dtorrent','Packages'],
return_metainfo = False, errfunc = _errfunc):
+ """Parse a directory for torrent files.
+
+ @type directory: C{string}
+ @param directory: the directory to parse (somewhat recursively)
+ @type parsed: C{dictionary}
+ @param parsed: the torrent files that were previously found
+ @type files: C{dictionary}
+ @param files: the files that were previously found
+ @type blocked: C{dictionary}
+ @param blocked: the files that were previously blocked
+ @type exts: C{list} of C{string}
+ @param exts: the extensions to look for torrent files in
+ (optional, defaults to 'dtorrent' and 'Packages')
+ @type return_metainfo: C{boolean}
+ @param return_metainfo: whether to return the torrent metainfo
+ (optional, defaults to False)
+ @type errfunc: C{method}
+ @param errfunc: the method to call to print status/warning/error messages
+ (optional, defaults to the L{_errfunc} function)
+ @rtype: (C{dictionary}, C{dictionary}, C{dictionary}, C{dictionary}, C{dictionary})
+ @return: all the torrents found, all the files found, all the files blocked,
+ the new torrents that were found, the torrents that are now missing
+
+ """
+
if NOISY:
errfunc('checking dir')
dirs_to_check = [directory]
@@ -120,9 +159,22 @@
a['numfiles'] = nf
a['length'] = l
a['name'] = d.get('name', f)
+
def setkey(k, d = d, a = a):
+ """Set the key of a dictionary with the value from another dictionary.
+
+ @type k: unknown
+ @param k: the key to set
+ @type d: C{dictionary}
+ @param d: the dictionary to get the value from
+ @type a: C{dictionary}
+ @param a: the dictionary to set the {k: d[k]} value in
+
+ """
+
if d.has_key(k):
a[k] = d[k]
+
setkey('failure reason')
setkey('warning message')
setkey('announce-list')
Modified: debtorrent/trunk/DebTorrent/piecebuffer.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/piecebuffer.py?rev=114&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/piecebuffer.py (original)
+++ debtorrent/trunk/DebTorrent/piecebuffer.py Sun Jun 17 04:35:50 2007
@@ -1,8 +1,19 @@
# Written by John Hoffman
# Modified by Cameron Dale
# see LICENSE.txt for license information
+#
+# $Id$
-# $Id$
+"""Store buffers of piece data.
+
+ at type DEBUG: C{boolean}
+ at var DEBUG: whether to print debugging messages
+ at type _pool: L{BufferPool}
+ at var _pool: example buffer pool
+ at type PieceBuffer: L{SingleBuffer}
+ at var PieceBuffer: example buffer
+
+"""
from array import array
from threading import Lock
@@ -16,34 +27,69 @@
DEBUG = False
class SingleBuffer:
+ """A single piece buffer.
+
+ @type pool: L{BufferPool}
+ @ivar pool: the pool of all piece buffers
+ @type buf: C{array.array}
+ @ivar buf: the character buffer used to store the piece
+ @type length: C{int}
+ @ivar length: the amount of data in the piece buffer
+
+ """
+
def __init__(self, pool):
+ """Initialize the instance.
+
+ @type pool: L{BufferPool}
+ @param pool: the pool of all piece buffers
+
+ """
+
self.pool = pool
self.buf = array('c')
def init(self):
+ """Initialize the new piece buffer."""
if DEBUG:
print 'new/pooled buffer index:', self.count
- '''
- for x in xrange(6,1,-1):
- try:
- f = inspect.currentframe(x).f_code
- print (f.co_filename,f.co_firstlineno,f.co_name)
- del f
- except:
- pass
- print ''
- '''
self.length = 0
def append(self, s):
+ """Add new data to the end of the buffer.
+
+ @type s: C{string}
+ @param s: the new data to add
+
+ """
+
l = self.length+len(s)
self.buf[self.length:l] = array('c',s)
self.length = l
def __len__(self):
+ """Get the length of the buffer.
+
+ @rtype: C{int}
+ @return: the length of the data in the buffer
+
+ """
+
return self.length
def __getslice__(self, a, b):
+ """Get a slice of data from the buffer.
+
+ @type a: C{int}
+ @param a: the starting offset to get data from
+ @type b: C{int}
+ @param b: the ending offset to stop getting data at, can be negative
+ to count from the end of the buffer
+ @rtype: C{array.array}
+ @return: the requested data from the buffer
+
+ """
+
if b > self.length:
b = self.length
if b < 0:
@@ -53,22 +99,49 @@
return self.buf[a:b]
def getarray(self):
+ """Get al the data from the buffer.
+
+ @rtype: C{array.array}
+ @return: the requested data from the buffer
+
+ """
+
return self.buf[:self.length]
def release(self):
+ """Release this buffer to the pool for reuse."""
if DEBUG:
print 'released buffer with index:', self.count
self.pool.release(self)
class BufferPool:
+ """The pool of all created piece buffers.
+
+ @type pool: C{list} of L{SingleBuffer}
+ @ivar pool: the pooled buffers available for use
+ @type lock: C{threading.Lock}
+ @ivar lock: serializes access to the pool across different threads
+ @type count: C{int}
+ @ivar count: the number of created buffers (for debugging)
+
+ """
+
def __init__(self):
+ """Initialize the instance."""
self.pool = []
self.lock = Lock()
if DEBUG:
self.count = 0
def new(self):
+ """Get a SingleBuffer from the pool, or create a new one.
+
+ @rtype: L{SingleBuffer}
+ @return: a usable piece buffer
+
+ """
+
self.lock.acquire()
if self.pool:
x = self.pool.pop()
@@ -82,6 +155,13 @@
return x
def release(self, x):
+ """Add an existing buffer to the pool of available ones.
+
+ @type x: L{SingleBuffer}
+ @param x: the buffer to add to the pool
+
+ """
+
self.pool.append(x)
More information about the Debtorrent-commits
mailing list