Better handling and logging for intermittent HTTP client submission errors.
[quix0rs-apt-p2p.git] / apt_p2p_Khashmir / util.py
1 ## Copyright 2002-2003 Andrew Loewenstern, All Rights Reserved
2 # see LICENSE.txt for license information
3
4 """Some utitlity functions for use in apt-p2p's khashmir DHT."""
5
6 from twisted.trial import unittest
7
8 from khash import HASH_LENGTH
9
10 def bucket_stats(l):
11     """Given a list of khashmir instances, finds min, max, and average number of nodes in tables."""
12     max = avg = 0
13     min = None
14     def count(buckets):
15         c = 0
16         for bucket in buckets:
17             c = c + len(bucket.l)
18         return c
19     for node in l:
20         c = count(node.table.buckets)
21         if min == None:
22             min = c
23         elif c < min:
24             min = c
25         if c > max:
26             max = c
27         avg = avg + c
28     avg = avg / len(l)
29     return {'min':min, 'max':max, 'avg':avg}
30
31 def uncompact(s):
32     """Extract the contact info from a compact node representation.
33     
34     @type s: C{string}
35     @param s: the compact representation
36     @rtype: C{dictionary}
37     @return: the node ID, IP address and port to contact the node on
38     @raise ValueError: if the compact representation doesn't exist
39     """
40     if (len(s) != HASH_LENGTH+6):
41         raise ValueError
42     id = s[:HASH_LENGTH]
43     host = '.'.join([str(ord(i)) for i in s[HASH_LENGTH:(HASH_LENGTH+4)]])
44     port = (ord(s[HASH_LENGTH+4]) << 8) | ord(s[HASH_LENGTH+5])
45     return {'id': id, 'host': host, 'port': port}
46
47 def compact(id, host, port):
48     """Create a compact representation of node contact info.
49     
50     @type id: C{string}
51     @param id: the node ID
52     @type host: C{string}
53     @param host: the IP address of the node
54     @type port: C{int}
55     @param port: the port number to contact the node on
56     @rtype: C{string}
57     @return: the compact representation
58     @raise ValueError: if the compact representation doesn't exist
59     """
60     
61     s = id + ''.join([chr(int(i)) for i in host.split('.')]) + \
62           chr((port & 0xFF00) >> 8) + chr(port & 0xFF)
63     if len(s) != 26:
64         raise ValueError
65     return s
66
67 def byte_format(s):
68     """Format a byte size for reading by the user.
69     
70     @type s: C{long}
71     @param s: the number of bytes
72     @rtype: C{string}
73     @return: the formatted size with appropriate units
74     """
75     if (s < 1):
76         r = str(int(s*1000.0)/1000.0) + 'B'
77     elif (s < 10):
78         r = str(int(s*100.0)/100.0) + 'B'
79     elif (s < 102):
80         r = str(int(s*10.0)/10.0) + 'B'
81     elif (s < 1024):
82         r = str(int(s)) + 'B'
83     elif (s < 10485):
84         r = str(int((s/1024.0)*100.0)/100.0) + 'KiB'
85     elif (s < 104857):
86         r = str(int((s/1024.0)*10.0)/10.0) + 'KiB'
87     elif (s < 1048576):
88         r = str(int(s/1024)) + 'KiB'
89     elif (s < 10737418L):
90         r = str(int((s/1048576.0)*100.0)/100.0) + 'MiB'
91     elif (s < 107374182L):
92         r = str(int((s/1048576.0)*10.0)/10.0) + 'MiB'
93     elif (s < 1073741824L):
94         r = str(int(s/1048576)) + 'MiB'
95     elif (s < 1099511627776L):
96         r = str(int((s/1073741824.0)*100.0)/100.0) + 'GiB'
97     else:
98         r = str(int((s/1099511627776.0)*100.0)/100.0) + 'TiB'
99     return(r)
100
101 class TestUtil(unittest.TestCase):
102     """Tests for the utilities."""
103     
104     timeout = 5
105     myid = '\xca\xec\xb8\x0c\x00\xe7\x07\xf8~])\x8f\x9d\xe5_B\xff\x1a\xc4!'
106     host = '165.234.1.34'
107     port = 61234
108
109     def test_compact(self):
110         d = uncompact(compact(self.myid, self.host, self.port))
111         self.failUnlessEqual(d['id'], self.myid)
112         self.failUnlessEqual(d['host'], self.host)
113         self.failUnlessEqual(d['port'], self.port)
114