Start development series 0.1-post
[0share.git] / client.py
blob5bc29cf840d718cf461bb28292423a2bcc12ca53
1 # Copyright (C) 2008, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 from logging import info, debug
5 import socket, sys, select, tempfile, shutil
6 import httplib
8 from zeroinstall.zerostore import Stores, NotStored
10 port = 38339
12 stores = Stores()
14 def fetch(host, digests):
15 if not digests:
16 print >>sys.stderr, "No digests given!"
17 sys.exit(1)
19 client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
21 if host is None:
22 host = '<broadcast>'
23 if host == '<broadcast>':
24 info("Broadcasting query for %s on local network...", digests)
25 client.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
26 else:
27 info("Sending query for %s to %s...", digests, host)
29 client.sendto('0share\n' + '\n'.join(digests), (host or '<broadcast>', port))
31 needed = set(digests)
33 n_responses = 0
34 while needed:
35 r = select.select([client], [], [], 1)[0]
36 if r:
37 data, addr = client.recvfrom(128)
38 addr = addr[0]
39 lines = data.split('\n')
40 if lines[0] == '0share-reply':
41 n_responses += 1
42 for d in lines[1:]:
43 print "%s has %s" % (addr, d)
44 if d in needed:
45 fetch_impl(d, addr)
46 needed.remove(d)
47 else:
48 info("Don't need %s now", d)
49 else:
50 info("Invalid reply from %s: %s", addr, repr(data))
51 else:
52 break
53 if needed:
54 if n_responses:
55 info("No further responses for one second")
56 else:
57 info("No responses within one second")
58 for x in needed:
59 print "Failed to fetch", x
60 else:
61 print "Success"
63 def fetch_impl(digest, addr):
64 try:
65 path = stores.lookup(digest)
66 info("Already have %s - not fetching", path)
67 return
68 except NotStored:
69 pass
71 info("Connecting to %s to request %s", addr, digest)
72 client = httplib.HTTPConnection(addr, port, strict = True)
73 url = '/implementation/' + digest
74 client.request('GET', url)
75 response = client.getresponse()
76 type = response.getheader('Content-Type')
77 if not type:
78 raise Exception("Missing Content-Type in response")
80 if response.status != 200:
81 raise Exception("Error fetching implementation (%d): %s" % (response.status, response.reason))
83 tmp = tempfile.TemporaryFile(prefix = '0share-')
84 try:
85 shutil.copyfileobj(response, tmp)
86 tmp.seek(0)
87 stores.add_archive_to_cache(digest, tmp, url, type = type)
88 finally:
89 tmp.close()
90 client.close()