Fixed some bugs in the new hashing scheme and tests.
[quix0rs-apt-p2p.git] / apt_dht / apt_dht.py
1
2 from binascii import b2a_hex
3
4 from twisted.internet import defer
5 from twisted.web2 import server, http, http_headers
6 from twisted.python import log
7
8 from apt_dht_conf import config
9 from PeerManager import PeerManager
10 from HTTPServer import TopLevel
11 from MirrorManager import MirrorManager
12 from Hash import HashObject
13
14 class AptDHT:
15     def __init__(self, dht):
16         log.msg('Initializing the main apt_dht application')
17         self.dht = dht
18         self.http_server = TopLevel(config.get('DEFAULT', 'cache_dir'), self)
19         self.http_site = server.Site(self.http_server)
20         self.peers = PeerManager()
21         self.mirrors = MirrorManager(config.get('DEFAULT', 'cache_dir'))
22     
23     def getSite(self):
24         return self.http_site
25     
26     def check_freshness(self, path, modtime, resp):
27         log.msg('Checking if %s is still fresh' % path)
28         d = self.peers.get([path], "HEAD", modtime)
29         d.addCallback(self.check_freshness_done, path, resp)
30         return d
31     
32     def check_freshness_done(self, resp, path, orig_resp):
33         if resp.code == 304:
34             log.msg('Still fresh, returning: %s' % path)
35             return orig_resp
36         else:
37             log.msg('Stale, need to redownload: %s' % path)
38             return self.get_resp(path)
39     
40     def get_resp(self, path):
41         d = defer.Deferred()
42         
43         log.msg('Trying to find hash for %s' % path)
44         findDefer = self.mirrors.findHash(path)
45         
46         findDefer.addCallbacks(self.findHash_done, self.findHash_error, 
47                                callbackArgs=(path, d), errbackArgs=(path, d))
48         findDefer.addErrback(log.err)
49         return d
50     
51     def findHash_error(self, failure, path, d):
52         log.err(failure)
53         self.findHash_done(HashObject(), path, d)
54         
55     def findHash_done(self, hash, path, d):
56         if hash.expected() is None:
57             log.msg('Hash for %s was not found' % path)
58             self.download_file([path], hash, path, d)
59         else:
60             log.msg('Found hash %s for %s' % (hash.hexexpected(), path))
61             # Lookup hash from DHT
62             key = hash.normexpected(bits = config.getint(config.get('DEFAULT', 'DHT'), 'HASH_LENGTH'))
63             lookupDefer = self.dht.getValue(key)
64             lookupDefer.addCallback(self.lookupHash_done, hash, path, d)
65             
66     def lookupHash_done(self, locations, hash, path, d):
67         if not locations:
68             log.msg('Peers for %s were not found' % path)
69             self.download_file([path], hash, path, d)
70         else:
71             log.msg('Found peers for %s: %r' % (path, locations))
72             # Download from the found peers
73             self.download_file(locations, hash, path, d)
74             
75     def download_file(self, locations, hash, path, d):
76         getDefer = self.peers.get(locations)
77         getDefer.addCallback(self.mirrors.save_file, hash, path)
78         getDefer.addErrback(self.mirrors.save_error, path)
79         getDefer.addCallbacks(d.callback, d.errback)