Move the normalization of key lengths from the HashObject to the DHT.
authorCameron Dale <camrdale@gmail.com>
Fri, 29 Feb 2008 21:10:46 +0000 (13:10 -0800)
committerCameron Dale <camrdale@gmail.com>
Fri, 29 Feb 2008 21:10:46 +0000 (13:10 -0800)
apt_dht/Hash.py
apt_dht/apt_dht.py
apt_dht/interfaces.py
apt_dht_Khashmir/DHT.py

index a7a8e40fcc587038ab18abacc0d571a147a24102..c0f73e397e1f0a09a46e1f011134bcd92d694144 100644 (file)
@@ -63,18 +63,6 @@ class HashObject:
         self.done = True
         self.result = None
         
         self.done = True
         self.result = None
         
-    def _norm_hash(self, hashString, bits=None, bytes=None):
-        if bits is not None:
-            bytes = (bits - 1) // 8 + 1
-        else:
-            if bytes is None:
-                raise HashError, "you must specify one of bits or bytes"
-        if len(hashString) < bytes:
-            hashString = hashString + '\000'*(bytes - len(hashString))
-        elif len(hashString) > bytes:
-            hashString = hashString[:bytes]
-        return hashString
-
     #### Methods for returning the expected hash
     def expected(self):
         """Get the expected hash."""
     #### Methods for returning the expected hash
     def expected(self):
         """Get the expected hash."""
@@ -86,15 +74,6 @@ class HashObject:
             self.expHex = b2a_hex(self.expHash)
         return self.expHex
     
             self.expHex = b2a_hex(self.expHash)
         return self.expHex
     
-    def normexpected(self, bits=None, bytes=None):
-        """Normalize the binary hash for the given length.
-        
-        You must specify one of bits or bytes.
-        """
-        if self.expNormHash is None and self.expHash is not None:
-            self.expNormHash = self._norm_hash(self.expHash, bits, bytes)
-        return self.expNormHash
-
     #### Methods for hashing data
     def new(self, force = False):
         """Generate a new hashing object suitable for hashing a file.
     #### Methods for hashing data
     def new(self, force = False):
         """Generate a new hashing object suitable for hashing a file.
@@ -186,15 +165,6 @@ class HashObject:
             self.fileHex = b2a_hex(self.digest())
         return self.fileHex
         
             self.fileHex = b2a_hex(self.digest())
         return self.fileHex
         
-    def norm(self, bits=None, bytes=None):
-        """Normalize the binary hash for the given length.
-        
-        You must specify one of bits or bytes.
-        """
-        if self.fileNormHash is None:
-            self.fileNormHash = self._norm_hash(self.digest(), bits, bytes)
-        return self.fileNormHash
-
     def verify(self):
         """Verify that the added file data hash matches the expected hash."""
         if self.result is None and self.fileHash is not None and self.expHash is not None:
     def verify(self):
         """Verify that the added file data hash matches the expected hash."""
         if self.result is None and self.fileHash is not None and self.expHash is not None:
@@ -280,27 +250,9 @@ class TestHashObject(unittest.TestCase):
     if sys.version_info < (2, 4):
         skip = "skippingme"
     
     if sys.version_info < (2, 4):
         skip = "skippingme"
     
-    def test_normalize(self):
-        h = HashObject()
-        h.set(h.ORDER[0], b2a_hex('12345678901234567890'), '0')
-        self.failUnless(h.normexpected(bits = 160) == '12345678901234567890')
-        h = HashObject()
-        h.set(h.ORDER[0], b2a_hex('12345678901234567'), '0')
-        self.failUnless(h.normexpected(bits = 160) == '12345678901234567\000\000\000')
-        h = HashObject()
-        h.set(h.ORDER[0], b2a_hex('1234567890123456789012345'), '0')
-        self.failUnless(h.normexpected(bytes = 20) == '12345678901234567890')
-        h = HashObject()
-        h.set(h.ORDER[0], b2a_hex('1234567890123456789'), '0')
-        self.failUnless(h.normexpected(bytes = 20) == '1234567890123456789\000')
-        h = HashObject()
-        h.set(h.ORDER[0], b2a_hex('123456789012345678901'), '0')
-        self.failUnless(h.normexpected(bits = 160) == '12345678901234567890')
-
     def test_failure(self):
         h = HashObject()
         h.set(h.ORDER[0], b2a_hex('12345678901234567890'), '0')
     def test_failure(self):
         h = HashObject()
         h.set(h.ORDER[0], b2a_hex('12345678901234567890'), '0')
-        self.failUnlessRaises(HashError, h.normexpected)
         self.failUnlessRaises(HashError, h.digest)
         self.failUnlessRaises(HashError, h.hexdigest)
         self.failUnlessRaises(HashError, h.update, 'gfgf')
         self.failUnlessRaises(HashError, h.digest)
         self.failUnlessRaises(HashError, h.hexdigest)
         self.failUnlessRaises(HashError, h.update, 'gfgf')
index 94260bd4c396a4c216e2952c9094ae2a1cdaf0cb..9fa79cdcbbbb1cc9611d14f84ae18a1e768f599b 100644 (file)
@@ -152,7 +152,7 @@ class AptDHT:
 
     def lookupHash(self, hash, path, d):
         log.msg('Looking up hash in DHT for file: %s' % path)
 
     def lookupHash(self, hash, path, d):
         log.msg('Looking up hash in DHT for file: %s' % path)
-        key = hash.normexpected(bits = config.getint(config.get('DEFAULT', 'DHT'), 'HASH_LENGTH'))
+        key = hash.expected()
         lookupDefer = self.dht.getValue(key)
         lookupDefer.addCallback(self.lookupHash_done, hash, path, d)
 
         lookupDefer = self.dht.getValue(key)
         lookupDefer.addCallback(self.lookupHash_done, hash, path, d)
 
@@ -195,7 +195,7 @@ class AptDHT:
             
     def store(self, hash):
         """Add a file to the DHT."""
             
     def store(self, hash):
         """Add a file to the DHT."""
-        key = hash.norm(bits = config.getint(config.get('DEFAULT', 'DHT'), 'HASH_LENGTH'))
+        key = hash.digest()
         value = {'c': self.my_contact}
         pieces = hash.pieceDigests()
         if len(pieces) <= 1:
         value = {'c': self.my_contact}
         pieces = hash.pieceDigests()
         if len(pieces) <= 1:
index 446cd02f99cc6bb05977d26735537759f81531a3..8cb2e69c95e2f421593c452f32d59ccec8b18d66 100644 (file)
@@ -32,10 +32,15 @@ class IDHT(Interface):
         
     def getValue(self, key):
         """Get a value from the DHT for the specified key.
         
     def getValue(self, key):
         """Get a value from the DHT for the specified key.
+        
+        The length of the key may be adjusted for use with the DHT.
 
         @rtype: C{Deferred}
         @return: a deferred that will fire with the stored values
         """
         
     def storeValue(self, key, value):
 
         @rtype: C{Deferred}
         @return: a deferred that will fire with the stored values
         """
         
     def storeValue(self, key, value):
-        """Store a value in the DHT for the specified key."""
+        """Store a value in the DHT for the specified key.
+
+        The length of the key may be adjusted for use with the DHT.
+        """
index 48ae1f4fe5843e06050d358dab1181623f0139cd..5f08dae07498962759264b4dfb1c07169b5da059 100644 (file)
@@ -125,12 +125,27 @@ class DHT:
             self.joined = False
             self.khashmir.shutdown()
         
             self.joined = False
             self.khashmir.shutdown()
         
+    def _normKey(self, key, bits=None, bytes=None):
+        bits = self.config["HASH_LENGTH"]
+        if bits is not None:
+            bytes = (bits - 1) // 8 + 1
+        else:
+            if bytes is None:
+                raise DHTError, "you must specify one of bits or bytes for normalization"
+        if len(key) < bytes:
+            key = key + '\000'*(bytes - len(key))
+        elif len(key) > bytes:
+            key = key[:bytes]
+        return key
+
     def getValue(self, key):
         """See L{apt_dht.interfaces.IDHT}."""
         if self.config is None:
             raise DHTError, "configuration not loaded"
         if not self.joined:
             raise DHTError, "have not joined a network yet"
     def getValue(self, key):
         """See L{apt_dht.interfaces.IDHT}."""
         if self.config is None:
             raise DHTError, "configuration not loaded"
         if not self.joined:
             raise DHTError, "have not joined a network yet"
+        
+        key = self._normKey(key)
 
         d = defer.Deferred()
         if key not in self.retrieving:
 
         d = defer.Deferred()
         if key not in self.retrieving:
@@ -158,6 +173,7 @@ class DHT:
         if not self.joined:
             raise DHTError, "have not joined a network yet"
 
         if not self.joined:
             raise DHTError, "have not joined a network yet"
 
+        key = self._normKey(key)
         bvalue = bencode(value)
 
         if key in self.storing and bvalue in self.storing[key]:
         bvalue = bencode(value)
 
         if key in self.storing and bvalue in self.storing[key]:
@@ -217,6 +233,18 @@ class TestSimpleDHT(unittest.TestCase):
         d.addCallback(self.lastDefer.callback)
         return self.lastDefer
 
         d.addCallback(self.lastDefer.callback)
         return self.lastDefer
 
+    def test_normKey(self):
+        h = self.a._normKey('12345678901234567890')
+        self.failUnless(h == '12345678901234567890')
+        h = self.a._normKey('12345678901234567')
+        self.failUnless(h == '12345678901234567\000\000\000')
+        h = self.a._normKey('1234567890123456789012345')
+        self.failUnless(h == '12345678901234567890')
+        h = self.a._normKey('1234567890123456789')
+        self.failUnless(h == '1234567890123456789\000')
+        h = self.a._normKey('123456789012345678901')
+        self.failUnless(h == '12345678901234567890')
+
     def value_stored(self, result, value):
         self.stored -= 1
         if self.stored == 0:
     def value_stored(self, result, value):
         self.stored -= 1
         if self.stored == 0: