Hi, after spending a few hours grooking the FTPClient API (with good help from Exarkun on IRC) I thought I'd post the fruits of my work.
I hope this may help someone. If the code is usefull enough feel free to add it to the examples in the docs.
If you see errors or got ideas on how this could be done different, feel free to answer :-)
""" A class for uploading multiple files to a ftp host. Usage:
ftp = FtpFileSave(ftpFiles=['/etc/passwd', '/etc/magic'], _pass="something", _username = "something", host="localhost") ftp.save(somecallback, errorcallback)
This will upload multiple files to the ftpserver. @caveat 1: as it stands the class does not change directory or anything like that before uploading the files. This should be easy to add though. """
_pass = "" _username = "" port = 21 host = "localhost"
def __init__(self, **kwargs): """Create a ftpfilesaver using the ftp client fromtwisted @param ftpFiles list of paths to the files to upload. """ self.__dict__.update(kwargs) self.nextfile = 0
def save(self, success,error): """Uploads a set of tiles to the ftpserver. @param success: the callback to be called on success @param error: the callback to be called on error """ self.success = success
FTPClient.debug = True creator = ClientCreator(reactor, FTPClient, self._username, self._pass, passive=True) defer = creator.connectTCP(self.host,self.port) self.error = error defer.addCallback(self.connectionMade).addErrback(self.error) return defer
def connectionMade(self,ftpClient): "Checks if there are more files to upload and uploads them. The main point with this method is that you have to collect the defereds of each command and wait until they succeed. " deffereds =  "We'll need the client to do a disconnect later" self.client = ftpClient " Create defereds for each of the different files to be uploaded" for upfile in self.ftpFiles: if not os.path.exists(upfile): raise Exception("File %s not found" % upfile) store, finish = ftpClient.storeFile("./%s" % os.path.basename(upfile)) finish.addCallback(self.end).addErrback(self.error) store.addCallback(self.send_file).addErrback(self.error) deffereds.append(store) deffereds.append(finish) return defer.gatherResults(deffereds)
def end(self, ftpResult): """Close the connection when all files have been uploaded. @param ftpResult a list of the protocol info we get. Not very interesting. @todo: check the list for errors. """ if (len(self.ftpFiles) <= self.nextfile): self.client.quit() self.client.transport.loseConnection() return defer.succeed(self.success()) return
def send_file(self, sender): """Open and send the file """ #print "Storefile %d : %s" % (self.nextfile, self.ftpFiles[self.nextfile]) filename = self.ftpFiles[self.nextfile] fp = open(filename,'r') sender.transport.write(fp.read()) sender.finish() "increase the nextfile count so end() knows when it's done" self.nextfile += 1