Richard Jones' Log: Ugly python made better
Fri, 17 Dec 2004
Yeah, it bugged me too... so here's an eminently more readable version of tinyp2p.py. With a couple of bugfixes thrown in too :)
It's still a bit more compact than I guess I'd like, but it's certainly much easier to understand what the code does now.
# simplep2p.py v1.1 (C) 2004, Richard Jones # with litle touch from Leonardo Santagada # A slightly more readable version of tinyp2p.py (C) 2004, E.W. Felten # (also handles binary transmissions now too) # license: http://creativecommons.org/licenses/by-nc-sa/2.0 # Usage: # python simplep2p.py password server hostname portnum [otherurl] # or # python simplep2p.py password client serverurl pattern import os, SimpleXMLRPCServer, re, hmac, sets, base64 from sys import argv from xmlrpclib import ServerProxy def gen_password(url): return hmac.new(argv[1], url).hexdigest() def ls(pat=""): ''' List the files in the current working directory that optionall match a regular expression "pat". ''' return [fn for fn in os.listdir(os.getcwd()) if not pat or re.search(pat, fn)] if argv[2] == "server": my_url = "http://"+argv[3]+":"+argv[4] # keep a list of servers we know about servers = sets.Set([my_url] + argv[5:]) def update_servers(new_servers=[]): servers.union_update(sets.Set(new_servers)) return list(servers) def discover(other_url): if other_url == my_url: return servers pw = gen_password(other_url) server = ServerProxy(other_url) return update_servers(server.list_servers(pw, update_servers())) # ask all our known servers about the servers *they* know about if servers: [discover(url) for url in list(servers)] # serve up the files def list_servers(password, arg=[]): if password == gen_password(my_url): return update_servers(arg) def list_files(password, arg): if password == gen_password(my_url): return ls(arg) def get_file(password, arg): if password == gen_password(my_url): f = file(arg) try: return base64.encodestring(f.read()) finally: f.close() server = SimpleXMLRPCServer.SimpleXMLRPCServer((argv[3], int(argv[4]))) server.register_function(list_servers) server.register_function(list_files) server.register_function(get_file) server.serve_forever() # client - contact our server for url in ServerProxy(argv[3]).list_servers(gen_password(argv[3])): # ask for the files we want, that we don't already have files = sets.Set(ServerProxy(url).list_files(gen_password(url), argv[4])) my_files = sets.Set(ls()) for fn in files - my_files: # and fetch c = ServerProxy(url).get_file(gen_password(url), fn) f = file(fn, "wb") f.write(base64.decodestring(c)) f.close()
Update: v1.1 incorporates some feedback from Leonardo Santagada.
Note: simplep2p.py will not talk with tinyp2p.py servers.
It's unlikely I'll find time to revisit this, sorry.
Thanks for decrypting the original script!
If you have the time, could you explain how the lambda's used in the original map onto/do the same functionality as this clearer script?
Cheers!!
Julian