Yesterday and today I've been working on an auto-update system for a game project. I've just pushed the server-side script to the server, and it seems to work great. Since this is public-facing code, though, I certainly wouldn't mind a few more eyes on it before I actually deploy it and changes get exponentially more painful.It's intended to be used by multiple client applications at once; one text file per application. Later revisions might include some way to download previous versions, hence why their paths are stored in the file.'''Created on Nov 3, 2014@author: SchilcoteProtocol:1. Client opens TCP connection to server @ port 73632. Client pushes version code (hash, build date, version number, arbitrary id; implementation irrelevant) followed by newline to server3a. If version code invalid, connection assumed to be hostile (port scan), connection is closed, server MAY ban IP3b. If version code valid and most recent, connection is closed3c. If version code valid and not most recent, MD5 hash of new version archive sent to client4. Client prepares to receive update file and sends one byte, 0x06 (ASCII ACK) to server5. Server transmits archive to client and closes connection.The version ID __latest__ is reserved; do not use it.Client should, of course, check the MD5 hash against the downloaded file before overwriting itself.Server reads ids and filenames from version files. These files have the following format:versionid:filename [newline]One versionid-filename pair per line. Data file should not contain leading or trailing whitespace.First line is assumed to be the most recent version; this is what will be pushed downstream.'''import socketserverimport hashlibimport globimport os.pathimport collectionsimport datetimeclass AutoUpdateHandler(socketserver.StreamRequestHandler):    def handle(self):        instream = self.rfile        outstream = self.wfile        print(Handling request from ,self.client_address[0],@,datetime.datetime.now(),.)        version=instream.readline().decode(ASCII).strip(\n)        print(Client running version ID,version)        archive=None        for thevdata in vdatas:            try:                thevdata[version]                print(Valid ID; maps to,archive)                latest=thevdata[__latest__]                if version==latest:                    print(Client has latest version. Closing connection.)                    return                else:                    print(Version ID,latest,is more recent.)                    archive=thevdata[latest]                    break            except KeyError:                pass        if not archive:            print(Invalid version ID. Closing connection.)            #ban(self.client_address[0])            return        with open(archive, rb) as archivehandle:            #Grab the entire contents of the file            data=archivehandle.read()        print(Sending hash.)        #Create a hasher, fill it with data, and grab the digest        hash=hashlib.md5(data).digest()        outstream.write(hash)        #Now wait for ACK (0x06)        if not instream.read(1) == b'\x06':            print(Invalid hash acceptance code (client should send 0x06).)            return        print(Sending ,archive,...)        #Finally, push the entire contents of the archive down the pipe        outstream.write(data)        print(Done @ ,datetime.datetime.now(),.\n)        returndef load_versions(filename):    Load version data file into a dict mapping versionids to filenames and returns said dict.    versions=collections.OrderedDict()    with open(filename,r) as file:        latest=None        for line in file:            line=line.strip()            version, archivename = line.split(:)            versions[version]=archivename            if not latest:                #first line read is considered latest version                latest=version                versions[__latest__]=latest    return versionsif __name__ == '__main__':    global vdatas    vdatas=[]    print(Server starting @,datetime.datetime.now(),.)    print(Preparing to load version data.)    vdglob = glob.glob(*.txt)    for thefilename in vdglob:        print(Loading version data from,thefilename,...)        vdata=load_versions(thefilename)        vdatas.append(vdata)        print(Loaded,len(vdata)-1,id-file pairs.)    print()    print(Initializing & grabbing port.)    server=socketserver.ThreadingTCPServer((localhost,7363), AutoUpdateHandler)    print(Accepting connections...)    server.serve_forever()    print(Server shutting down @,datetime.datetime.now(),...)I'm not particularly concerned with style criticisms (I know, the imports are in the wrong order & I should be using str.format), though I'll accept them; I'm more looking for potentially dangerous edge-cases I missed or clearly stupid decisions I made. Oh, and I'm aware md5 isn't really intended for what I'm using it for and not recommended for its intended purpose anyway; by the time I remembered that the code was already written and unless I'm very mistaken, it doesn't really matter.
Auto-update server
python;python 3.x;server