Nevermind. I was missing 'self.dataReceived = self.interface_handler.dataReceived' in the __init__ of SSHSession and self.dataReceived = self._client.dataReceived in the __init__ of SftpClient. Maybe I need to reduce the abstraction a bit here, hmm.
Well hopefully this helps someone sometime.... On 9 February 2011 10:00, Brad Milne <brad.mi...@devx.runthered.com> wrote: > Hi all > > I've looked around for SFTP client doco, but it's come up pretty thin on > the ground. I've seen http://twistedmatrix.com/trac/wiki/TwistedConch and > everything under it. With it I've been able to connect via SSH to a server > and run a command (*a la* the 'cat' example from tutorial page and from > sshsimpleclient.py<http://twistedmatrix.com/documents/current/conch/examples/sshsimpleclient.py> > ). > > On the other hand, plenty of posts recommend checking out cftp.py in > scripts/. That uses the FileTransferClient, and appears to be more along the > lines of what is needed for a persistent SFTP connection and file transfers. > > What seems to be happening with the below is that the connection is being > created OK, but I haven't been able to utilise the _remoteGlob method (taken > from cftp.py). It simply hangs. > > My sandbox code is below. > > Any help greatly appreciated. > Brad > > <code> > import os > from twisted.python import failure > from twisted.internet import reactor, protocol, defer > from twisted.conch.ssh import transport, connection, userauth, channel, > common, filetransfer > import logging > from twisted.python import log > import sys > > class SimpleTransport(transport.SSHClientTransport): > def verifyHostKey(self, hostKey, fingerprint): > print 'host key fingerprint: %s' % fingerprint > return defer.succeed(1) > > def connectionSecure(self): > ''' > called when the encryption is set up and other services can be run > ''' > self.requestService(SimpleUserAuth(USERNAME,SimpleConnection())) > > class SimpleConnection(connection.SSHConnection): > def serviceStarted(self): > self.openChannel(SSHSession()) > > class SimpleUserAuth(userauth.SSHUserAuthClient): > def getPassword(self): > return defer.succeed(PASS) > > class SSHSession(channel.SSHChannel): > ''' > Things to do within the active SSH session. > ''' > name = 'session' > > def __init__(self, interface_handler=None, *args, **kwargs): > channel.SSHChannel.__init__(self, *args, **kwargs) > self.interface_handler = interface_handler or SftpClient(self) > > def channelOpen(self, ignoredData): > self.data = '' > # Create an sftp connection (stays open) > d = self.conn.sendRequest(self, 'subsystem', common.NS('sftp'), > wantReply=1) > d.addCallback(self._cbSubsystem) > > def _cbSubsystem(self, result): > self.interface_handler.getDirectoryContents('/tmp') > > def closeReceived(self): > logging.info('remote side closed %s' % self) > self.conn.sendClose(self) > reactor.stop() > > class SftpClient(object): > > def __init__(self, transport, *args, **kwargs): > super(SftpClient, self).__init__(*args, **kwargs) > self.transport = transport > self._client = filetransfer.FileTransferClient() > > @property > def client(self): > if not self._client.connected: > self._client.makeConnection(self.transport) > logging.debug("Made 'connection' with transport class") > return self._client > > def getDirectoryContents(self, path): > d = self._remoteGlob(path) > > def gotit(files): > print "Got %s: %s" % (type(files), files) > d.addCallback(gotit) > return d > > # Accessory methods. > # These are stolen from twisted.conch.scripts.cftp.py. We can't > # import that module as it contains unix-dependent imports. > def _remoteGlob(self, fullPath): > logging.debug('looking up %s' % fullPath) > head, tail = os.path.split(fullPath) > if '*' in tail or '?' in tail: > glob = 1 > else: > glob = 0 > if tail and not glob: # could be file or directory > # try directory first > logging.debug("Opening dir") > d = self.client.openDirectory(fullPath) > d.addCallback(self._cbOpenList, '') > d.addErrback(self._ebNotADirectory, head, tail) > else: > d = self.client.openDirectory(head) > d.addCallback(self._cbOpenList, tail) > return d > > def _cbOpenList(self, directory, glob): > logging.debug("Got dir") > files = [] > d = directory.read() > d.addBoth(self._cbReadFile, files, directory, glob) > return d > > def _ebNotADirectory(self, reason, path, glob): > logging.debug("Not a dir") > d = self.client.openDirectory(path) > d.addCallback(self._cbOpenList, glob) > return d > > def _cbReadFile(self, files, l, directory, glob): > logging.debug("Reading file") > if not isinstance(files, failure.Failure): > if glob: > raise NotImplementedError("don't have fnmatch available to > use on Windows so have commented this bit out") > # l.extend([f for f in files if fnmatch.fnmatch(f[0], > glob)]) > else: > l.extend(files) > d = directory.read() > d.addBoth(self._cbReadFile, l, directory, glob) > return d > else: > reason = files > reason.trap(EOFError) > directory.close() > return l > > if __name__=='__main__': > protocol.ClientCreator(reactor, SimpleTransport).connectTCP(HOST, 22) > log.startLogging(sys.stdout, setStdout=0) > reactor.run() > > </code> > -- Brad Milne | Run The Red | *brad.mi...@devx.runthered.com*
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python