#!/usr/bin/env python import subprocess from twisted.internet import defer, stdio, protocol, reactor from twisted.protocols import basic class Repl(basic.LineReceiver): delimiter = '\n' prompt_string = '>>> ' def prompt(self): self.transport.write(self.prompt_string) def connectionMade(self): self.sendLine('Welcome to Repl') # store factory and connector upon connection to the stdout self.factory = CFactory() self.connector = reactor.connectTCP( '127.0.0.1', 1234, self.factory) self.prompt() def lineReceived(self, line): if not line: self.prompt() return self.issueCommand(line) def issueCommand(self, command): # write to the connector's transport, not the one writing on stdout self.connector.transport.write("%s%s" % (command, self.delimiter)) # register the callback on the factory's deferred self.factory.deferred.addCallback(self._checkResponse) def _checkResponse(self, args): success, num_lines, data = args if num_lines > 20: self.lessify(data) else: self.sendLine(data) self.prompt() # recreate the deferred each time we have the response self.factory.deferred = defer.Deferred() def lessify(self, data): p = subprocess.Popen(["less"], stdin=subprocess.PIPE) p.stdin.write(data) p.stdin.close() p.wait() class Client(basic.LineReceiver): delimiter = '\n' def connectionMade(self): self.buffer = [] self.cmd_success = True def lineReceived(self, line): if line.startswith('OK'): return if line.startswith('ERR'): self.cmd_success = False return if line == 'END': self.responseFinished( len(self.buffer), "\n".join(self.buffer)) self.buffer = [] else: self.buffer.append(line) def responseFinished(self, num_lines, data): # just fire the callback self.factory.deferred.callback(( self.cmd_success, num_lines, data)) def connectionLost(self, reason): reactor.stop() class CFactory(protocol.ClientFactory): protocol = Client def __init__(self): self.deferred = defer.Deferred() if __name__ == "__main__": stdio.StandardIO(Repl()) reactor.run()