Re: [Twisted-Python] Guidance on Proxy-type Application
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
On 01:23 am, asb.bush@gmail.com wrote:
Thanks for asking! I apologize for the delay in my answer. I started writing up a simple example (attached) but was discouraged to find that it was 100 lines long and required too much explaining. Then I started documenting it and explaining every line but that was a very long, tedious message. So, it doesn't have much in the way of explanation; I hope you will find it useful regardless.
The application has the following model:
This is *almost* a FAQ. At least, you may find this to be a useful answer: <http://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#HowdoImakeinputo...>
The example that I've attached does basically this. Run it and then run 'telnet localhost 4322', and type some lines; you will see that they are transformed and echoed back to you, both by the proxy and by the protocol being proxied. At a high level, the answer to your question is so simple that it's hard to express. Basically, you just need to have all the relevant objects having references to each other, and calling methods to achieve the desired effect. The less magic, the better. More precisely, you need an object responsible for managing your outgoing connections to your legacy server, so that it can handle disconnection and reconnection, queueing messages and so on. Then you need your proxy server factory to hold a reference to that object, so that it can create references from each proxy server protocol connection object to the connection manager. This is related to another recent thread - you can see my message in that thread here: http://thread.gmane.org/gmane.comp.python.twisted/18377/focus=18385
I'm not sure why hex-dump port-forwarding is particularly relevant to this example. Is it just because this is an application that connects from one host to another?
This part of your question is almost exactly the FAQ I mentioned above :). To reiterate that answer, you just need to have references between objects, and call methods on the objects you want to do stuff. If you have a client connection object, just get a reference to that from the relevant server connection object and call methods on the client object to emit messages on the client protocol, handling any responses appropriately. Deferreds can help with that latter part. It is always better if you can establish that reference as simply as possible; for example, by passing parameters to the __init__ of various classes. Again, for reasons that have nothing to do with Twisted specifically, it's a bad idea to try to establish these references by having global variables floating around. Here's a very very simple example of the "good way" to propagate some data to protocol instances that need it: class MyProtocol(Protocol): def __init__(self, data): self.data = data class MyFactory(Factory): def __init__(self, data): self.data = data def buildProtocol(self, addr): return MyProtocol(self.data) reactor.listenTCP(8765, MyFactory("some data")) and here's a simple example of a really bad way (don't do this!): class MyProtocol(Protocol): def connectionMade(self): self.bleh = bleh bleh = "some data" f = Factory() f.protocol = MyProtocol reactor.listenTCP(9876, f) Even in C, I'm pretty sure it's better style to pass structures to functions than to abuse piles of local variables :). I only illustrate this bad style here because it seems to be a common antipattern. The Protocol class itself doesn't take any parameters to __init__, and Twisted's users don't always realize that protocols and factories and so on are just regular objects, with no special rules; they just get methods called on them by the reactor.
Based on what you've said so far, I think you're basically on the right track. Good luck!
![](https://secure.gravatar.com/avatar/147e9f4a7f91ec6b3fd86532214c0273.jpg?s=120&d=mm&r=g)
Semi, OT: Having glyph's example (or one like it) would've probably shaved a week off my initial foray into Twisted. I respectfully recommend that a version containing a docstring or two be included somewhere on the site, possibly alongside the "Finger" tutorial under the heading "a simple example of how to use Twisted for people with a deadline." Also, this comment:
should be prominently featured somewhere. -Dan
![](https://secure.gravatar.com/avatar/bb9a47b903805fa0ed7f001b7a16d252.jpg?s=120&d=mm&r=g)
2009/5/28 <glyph@divmod.com>
Thanks for the very interesting example which I mainly follow apart from the lineReceived method in the ProxyClient, don't we need to add a callback to the deferred before appending it to the requestQueue? class ProxyClient(LineReceiver): def connectionMade(self): self.requestQueue = [] def forwardLine(self, line): self.sendLine(line) d = Deferred() self.requestQueue.append(d) return d def lineReceived(self, line): self.requestQueue.pop(0).callback(line) Thanks, Michael
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
On 08:24 am, michaelnt@gmail.com wrote:
2009/5/28 <glyph@divmod.com>
Definitely not! That would defeat the purpose. The Deferred doesn't have a value yet: you're waiting for the other side of the connection to respond with an echo line. As you can see, the result becomes available in lineReceived:
And we callback the Deferred when it is available:
HTH, -glyph
![](https://secure.gravatar.com/avatar/b068e4b3e91a8f98dc7e95a3b312c3f9.jpg?s=120&d=mm&r=g)
glyph, Sorry for the delayed response. I wanted to thank you for providing such a complete example. This is excellent. Now I just need to wrap by head around how it all goes together and works. The logic of the queue append and pop of a deferred in ProxyClient forwardLine and lineRecieve are throwing me for a loop. I'll keep tracing it and get it down. Thanks Again! -ab On Thu, May 28, 2009 at 6:58 PM, <glyph@divmod.com> wrote:
![](https://secure.gravatar.com/avatar/147e9f4a7f91ec6b3fd86532214c0273.jpg?s=120&d=mm&r=g)
Semi, OT: Having glyph's example (or one like it) would've probably shaved a week off my initial foray into Twisted. I respectfully recommend that a version containing a docstring or two be included somewhere on the site, possibly alongside the "Finger" tutorial under the heading "a simple example of how to use Twisted for people with a deadline." Also, this comment:
should be prominently featured somewhere. -Dan
![](https://secure.gravatar.com/avatar/bb9a47b903805fa0ed7f001b7a16d252.jpg?s=120&d=mm&r=g)
2009/5/28 <glyph@divmod.com>
Thanks for the very interesting example which I mainly follow apart from the lineReceived method in the ProxyClient, don't we need to add a callback to the deferred before appending it to the requestQueue? class ProxyClient(LineReceiver): def connectionMade(self): self.requestQueue = [] def forwardLine(self, line): self.sendLine(line) d = Deferred() self.requestQueue.append(d) return d def lineReceived(self, line): self.requestQueue.pop(0).callback(line) Thanks, Michael
![](https://secure.gravatar.com/avatar/d6328babd9f9a98ecc905e1ccac2495e.jpg?s=120&d=mm&r=g)
On 08:24 am, michaelnt@gmail.com wrote:
2009/5/28 <glyph@divmod.com>
Definitely not! That would defeat the purpose. The Deferred doesn't have a value yet: you're waiting for the other side of the connection to respond with an echo line. As you can see, the result becomes available in lineReceived:
And we callback the Deferred when it is available:
HTH, -glyph
![](https://secure.gravatar.com/avatar/b068e4b3e91a8f98dc7e95a3b312c3f9.jpg?s=120&d=mm&r=g)
glyph, Sorry for the delayed response. I wanted to thank you for providing such a complete example. This is excellent. Now I just need to wrap by head around how it all goes together and works. The logic of the queue append and pop of a deferred in ProxyClient forwardLine and lineRecieve are throwing me for a loop. I'll keep tracing it and get it down. Thanks Again! -ab On Thu, May 28, 2009 at 6:58 PM, <glyph@divmod.com> wrote:
participants (4)
-
Aaron Bush
-
Dan
-
glyph@divmod.com
-
Michael Thompson