r343 - in /debtorrent/trunk: DebTorrent/BT1/track.py debian/changelog

camrdale-guest at users.alioth.debian.org camrdale-guest at users.alioth.debian.org
Wed Jan 23 05:19:24 UTC 2008


Author: camrdale-guest
Date: Wed Jan 23 05:19:23 2008
New Revision: 343

URL: http://svn.debian.org/wsvn/debtorrent/?sc=1&rev=343
Log:
Report more and better statistics on the tracker's info page.

Modified:
    debtorrent/trunk/DebTorrent/BT1/track.py
    debtorrent/trunk/debian/changelog

Modified: debtorrent/trunk/DebTorrent/BT1/track.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/track.py?rev=343&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/track.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/track.py Wed Jan 23 05:19:23 2008
@@ -160,12 +160,21 @@
                         raise ValueError
                     if type(info.get('requirecrypto')) not in (IntType,LongType):
                         raise ValueError
-        elif cname == 'completed':
-            if (type(cinfo) != DictType): # The 'completed' key is a dictionary of SHA hashes (torrent ids)
+        elif cname == 'stats':
+            if (type(cinfo) != DictType): # The 'stats' key is a dictionary of SHA hashes (torrent ids)
                 raise ValueError          # ... for keeping track of the total completions per torrent
             for y in cinfo.values():      # ... each torrent has an integer value
-                if type(y) not in (IntType,LongType):
+                if type(y) != DictType:
                     raise ValueError      # ... for the number of reported completions for that torrent
+                completed = y.get('completed')
+                if type(completed) not in (IntType,LongType) or completed < 0:
+                    raise ValueError
+                uploaded = y.get('uploaded', 0)
+                if type(uploaded) not in (IntType,LongType) or uploaded < 0:
+                    raise ValueError
+                downloaded = y.get('downloaded', 0)
+                if type(downloaded) not in (IntType,LongType) or downloaded < 0:
+                    raise ValueError
         elif cname == 'allowed':
             if (type(cinfo) != DictType): # a list of info_hashes and included data
                 raise ValueError
@@ -359,9 +368,9 @@
     @ivar downloads: keys are info hashes, values are dictionaries with keys the
         peer IDs of peers connected to that torrent and values the dictionaries
         of information about the peer
-    @type completed: C{dictionary}
-    @ivar completed: keys are info hashes, values are the number of peers that
-        have completed downloading the entire torrent
+    @type stats: C{dictionary}
+    @ivar stats: keys are info hashes, values are dictionaries containing
+        statistics related to the torrent
     @type becache: C{list} of C{list} of C{dictionary}
     @ivar becache: keys are the infohashes, values are the cached peer data.
         peer set format::
@@ -485,7 +494,7 @@
             except:
                 logger.warning('statefile corrupt; resetting')
         self.downloads = self.state.setdefault('peers', {})
-        self.completed = self.state.setdefault('completed', {})
+        self.stats = self.state.setdefault('stats', {})
 
         self.becache = {}
 
@@ -655,17 +664,21 @@
                 return (302, 'Found', {'Content-Type': 'text/html', 'Location': red},
                         '<A HREF="'+red+'">Click Here</A>')
             
+            # Write the document header
             s = StringIO()
-            s.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n' \
-                '<html><head><title>DebTorrent download info</title>\n')
+            s.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' \
+                    '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n' \
+                    '<html><head><title>DebTorrent tracker info</title>\n')
             if self.favicon is not None:
                 s.write('<link rel="shortcut icon" href="/favicon.ico">\n')
             s.write('</head>\n<body>\n' \
-                '<h3>DebTorrent download info</h3>\n'\
-                '<ul>\n'
-                '<li><strong>tracker version:</strong> %s</li>\n' \
-                '<li><strong>server time:</strong> %s</li>\n' \
-                '</ul>\n' % (version, isotime()))
+                    '<h3>DebTorrent tracker info</h3>\n'\
+                    '<ul>\n'
+                    '<li><strong>tracker version:</strong> %s</li>\n' \
+                    '<li><strong>server time:</strong> %s</li>\n' \
+                    '</ul>\n' % (version, isotime()))
+
+            # Collect the torrent hashes and names
             if self.config['allowed_dir']:
                 if self.show_names:
                     names = [ (self.allowed[hash]['name'],hash)
@@ -678,66 +691,98 @@
                     names = [ ('\n<br>'.join(self.torrent_names[hash]),hash) for hash in self.downloads.keys() ]
                 else:
                     names = [ (None,hash) for hash in self.downloads.keys() ]
+
             if not names:
                 s.write('<p>not tracking any files yet...</p>\n')
             else:
                 names.sort()
-                tn = 0
-                tc = 0
-                td = 0
-                tt = 0  # Total transferred
-                ts = 0  # Total size
-                nf = 0  # Number of files displayed
-                if self.config['allowed_dir'] and self.show_names:
-                    s.write('<table summary="files" border="1">\n' \
-                        '<tr><th>torrent name<br><code>info hash</code></th><th align="right">size</th><th align="right">complete</th><th align="right">downloading</th><th align="right">downloaded</th><th align="right">transferred</th></tr>\n')
-                else:
-                    s.write('<table summary="files">\n' \
-                        '<tr><th>torrent name<br><code>info hash</code></th><th align="right">complete</th><th align="right">downloading</th><th align="right">downloaded</th></tr>\n')
+                number_files = 0
+                total_peers = 0
+                total_uploaded = 0L
+                total_downloaded = 0L
+                total_size = 0L
+                
+                # Write the table headers
+                s.write('<table summary="files" border="1">\n\n' \
+                        '<tr><th>torrent name/<br><code>    info hash</code></th>\n')
+                if self.config['allowed_dir']:
+                    s.write('<th align="right">size</th>\n')
+                s.write('<th align="right">peers</th>\n' \
+                        '<th align="right">downloaded</th>\n' \
+                        '<th align="right">uploaded</th>\n' \
+                        '<th align="right">saved</th></tr>\n\n')
+
+                # Display a table row for each torrent
                 for name,hash in names:
-                    l = self.downloads[hash]
-                    n = self.completed.get(hash, 0)
-                    tn = tn + n
-                    c = self.seedcount[hash]
-                    tc = tc + c
-                    d = len(l) - c
-                    td = td + d
-                    if self.config['allowed_dir'] and self.show_names:
-                        if self.allowed.has_key(hash):
-                            nf = nf + 1
-                            sz = self.allowed[hash]['length']  # size
-                            ts = ts + sz
-                            szt = sz * n   # Transferred for this torrent
-                            tt = tt + szt
-                            if self.allow_get == 1:
-                                linkname = '<a href="/file?info_hash=' + quote(hash) + '">' + name + '</a>'
-                            else:
-                                linkname = name
-                            s.write('<tr><td>%s<br><code>%s</code></td><td align="right">%s</td><td align="right">%i</td><td align="right">%i</td><td align="right">%i</td><td align="right">%s</td></tr>\n' \
-                                % (linkname, b2a_hex(hash), size_format(sz), c, d, n, size_format(szt)))
+                    # Get the stats for this torrent
+                    uploaded = self.stats.get(hash, {}).get('uploaded', 0)
+                    total_uploaded += uploaded
+                    downloaded = self.stats.get(hash, {}).get('downloaded', 0)
+                    total_downloaded += downloaded
+                    saved = 0.0
+                    if downloaded > 0:
+                        saved = 100.0 * float(uploaded) / float(downloaded)
+                    peers = len(self.downloads[hash])
+                    total_peers += peers
+
+                    # Display is different if we are using allowed_dir
+                    if self.config['allowed_dir'] and self.allowed.has_key(hash):
+                        number_files += 1
+                        size = self.allowed[hash]['length']  # size
+                        total_size += long(size)
+                        if self.allow_get == 1:
+                            linkname = '<a href="/file?info_hash=' + quote(hash) + '">' + name + '</a>'
+                        else:
+                            linkname = name
+                        s.write('<tr><td>%s<br><code>    %s</code></td>\n' \
+                                '<td align="right">%s</td>\n' \
+                                '<td align="right">%i</td>\n' \
+                                '<td align="right">%s</td>\n' \
+                                '<td align="right">%s</td>\n' \
+                                '<td align="right">%0.1f %%</td></tr>\n\n' \
+                                % (linkname, b2a_hex(hash), size_format(size),
+                                   peers, size_format(downloaded),
+                                   size_format(uploaded), saved))
                     else:
+                        number_files += 1
                         s.write('<tr><td>')
                         if name:
                             s.write('%s<br>' % name)
-                        s.write('<code>%s</code></td><td align="right"><code>%i</code></td><td align="right"><code>%i</code></td><td align="right"><code>%i</code></td></tr>\n' \
-                            % (b2a_hex(hash), c, d, n))
-                if self.config['allowed_dir'] and self.show_names:
-                    s.write('<tr><td align="right">%i files</td><td align="right">%s</td><td align="right">%i</td><td align="right">%i</td><td align="right">%i</td><td align="right">%s</td></tr>\n'
-                            % (nf, size_format(ts), tc, td, tn, size_format(tt)))
-                else:
-                    s.write('<tr><td align="right">%i files</td><td align="right">%i</td><td align="right">%i</td><td align="right">%i</td></tr>\n'
-                            % (nf, tc, td, tn))
+                        s.write('<code>    %s</code></td>\n' \
+                                '<td align="right">%i</td>\n' \
+                                '<td align="right">%s</td>\n' \
+                                '<td align="right">%s</td>\n' \
+                                '<td align="right">%0.1f %%</td></tr>\n\n' \
+                                % (b2a_hex(hash), peers, size_format(downloaded),
+                                   size_format(uploaded), saved))
+
+                # The table footer with summary statistics
+                saved = 0.0
+                if total_downloaded > 0:
+                    saved = 100.0 * float(total_uploaded) / float(total_downloaded)
+                s.write('<tr><td align="right">%i torrents</td>\n' % number_files)
+                if self.config['allowed_dir']:
+                    s.write('<td align="right">%s</td>\n' % size_format(total_size))
+                s.write('<td align="right">%i</td>\n' \
+                        '<td align="right">%s</td>\n' \
+                        '<td align="right">%s</td>\n' \
+                        '<td align="right">%0.1f %%</td></tr>\n\n'
+                        % (total_peers, size_format(total_downloaded),
+                           size_format(total_uploaded), saved))
+
+                # Write a rudimentary legend
                 s.write('</table>\n' \
                     '<ul>\n' \
-                    '<li><em>info hash:</em> SHA1 hash of the "info" section of the metainfo (*.dtorrent)</li>\n' \
-                    '<li><em>complete:</em> number of connected clients with the complete file</li>\n' \
-                    '<li><em>downloading:</em> number of connected clients still downloading</li>\n' \
-                    '<li><em>downloaded:</em> reported complete downloads</li>\n' \
-                    '<li><em>transferred:</em> torrent size * total downloaded (does not include partial transfers)</li>\n' \
+                    '<li><em>torrent name:</em> possible names for the torrent</li>\n' \
+                    '<li><em>info hash:</em> torrent identifier</li>\n' \
+                    '<li><em>peers:</em> number of connected clients</li>\n' \
+                    '<li><em>downloaded:</em> amount of data downloaded by all peers, this data may have been downloaded from a mirror or another peer</li>\n' \
+                    '<li><em>uploaded:</em> amount of data uploaded by all peers, this is the amount of bandwidth that was saved from the mirrors</li>\n' \
+                    '<li><em>saved:</em> percentage of data that was NOT downloaded from a mirror</li>\n' \
                     '</ul>\n')
 
             s.write('</body>\n' \
-                '</html>\n')
+                    '</html>\n')
             return (200, 'OK', {'Content-Type': 'text/html; charset=iso-8859-1'}, s.getvalue())
         except:
             logger.exception('Error generating info page')
@@ -758,7 +803,7 @@
         """
         
         l = self.downloads[hash]
-        n = self.completed.get(hash, 0)
+        n = self.stats.get(hash, {}).get('completed', 0)
         c = self.seedcount[hash]
         d = len(l) - c
         f = {'complete': c, 'incomplete': d, 'downloaded': n}
@@ -896,7 +941,9 @@
         
         peers = self.downloads.setdefault(infohash, {})
         ts = self.times.setdefault(infohash, {})
-        self.completed.setdefault(infohash, 0)
+        stats = self.stats.setdefault(infohash, {'completed': 0,
+                                                 'uploaded': 0L,
+                                                 'downloaded': 0L})
         self.seedcount.setdefault(infohash, 0)
         torrent_name = self.torrent_names.setdefault(infohash, [])
 
@@ -934,8 +981,8 @@
         left = long(params('left',''))
         if left < 0:
             raise ValueError, 'invalid amount left'
-        uploaded = long(params('uploaded',''))
-        downloaded = long(params('downloaded',''))
+        uploaded = long(params('uploaded', 0L))
+        downloaded = long(params('downloaded', 0L))
         if params('supportcrypto'):
             supportcrypto = 1
             try:
@@ -967,12 +1014,20 @@
 
         if event == 'stopped':
             if peer:
+                if uploaded > peer['uploaded']:
+                    stats['uploaded'] += uploaded - peer['uploaded']
+                    peer['uploaded'] = uploaded
+                if downloaded > peer['downloaded']:
+                    stats['downloaded'] += downloaded - peer['downloaded']
+                    peer['downloaded'] = downloaded
+
                 if auth:
                     self.delete_peer(infohash,myid)
         
         elif not peer:
             ts[myid] = clock()
             peer = { 'ip': ip, 'port': port, 'left': left,
+                     'uploaded': uploaded, 'downloaded': downloaded,
                      'supportcrypto': supportcrypto,
                      'requirecrypto': requirecrypto }
             if mykey:
@@ -994,7 +1049,7 @@
             else:
                 peer['nat'] = 2**30
             if event == 'completed':
-                self.completed[infohash] += 1
+                stats['completed'] += 1
             if not left:
                 self.seedcount[infohash] += 1
                 
@@ -1006,7 +1061,7 @@
 
             ts[myid] = clock()
             if not left and peer['left']:
-                self.completed[infohash] += 1
+                stats['completed'] += 1
                 self.seedcount[infohash] += 1
                 if not peer.get('nat', -1):
                     for bc in self.becache[infohash]:
@@ -1014,7 +1069,7 @@
                             bc[1][myid] = bc[0][myid]
                             del bc[0][myid]
             elif left and not peer['left']:
-                self.completed[infohash] -= 1
+                stats['completed'] -= 1
                 self.seedcount[infohash] -= 1
                 if not peer.get('nat', -1):
                     for bc in self.becache[infohash]:
@@ -1022,6 +1077,13 @@
                             bc[0][myid] = bc[1][myid]
                             del bc[1][myid]
             peer['left'] = left
+            
+            if uploaded > peer['uploaded']:
+                stats['uploaded'] += uploaded - peer['uploaded']
+                peer['uploaded'] = uploaded
+            if downloaded > peer['downloaded']:
+                stats['downloaded'] += downloaded - peer['downloaded']
+                peer['downloaded'] = downloaded
 
             if port:
                 recheck = False
@@ -1608,8 +1670,16 @@
     
     if (s < 1024):
         r = str(s) + 'B'
+    elif (s < 10485):
+        r = str(int((s/1024.0)*100.0)/100.0) + 'KiB'
+    elif (s < 104857):
+        r = str(int((s/1024.0)*10.0)/10.0) + 'KiB'
     elif (s < 1048576):
         r = str(int(s/1024)) + 'KiB'
+    elif (s < 10737418L):
+        r = str(int((s/1048576.0)*100.0)/100.0) + 'MiB'
+    elif (s < 107374182L):
+        r = str(int((s/1048576.0)*10.0)/10.0) + 'MiB'
     elif (s < 1073741824L):
         r = str(int(s/1048576)) + 'MiB'
     elif (s < 1099511627776L):

Modified: debtorrent/trunk/debian/changelog
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/debian/changelog?rev=343&op=diff
==============================================================================
--- debtorrent/trunk/debian/changelog (original)
+++ debtorrent/trunk/debian/changelog Wed Jan 23 05:19:23 2008
@@ -6,7 +6,8 @@
     - currently supported only by debian testing and unstable
     - see http://wiki.debian.org/DebTorrent/UniquePieces for more info
   * Add torrent names to the tracker display
-  * Make the download/upload statistics last over restarts
+  * Make the download/upload statistics persist over restarts
+  * Report more and better statistics on the tracker's info page
 
  -- Cameron Dale <camrdale at gmail.com>  Tue, 22 Jan 2008 19:19:35 -0800
 




More information about the Debtorrent-commits mailing list