[Twisted-Python] Conch SFTP client help
Brad Milne
brad.milne at devx.runthered.com
Tue Feb 8 20:45:31 MST 2011
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.milne at 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.milne at devx.runthered.com*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20110209/531636b3/attachment.html>
More information about the Twisted-Python
mailing list