[Twisted-Python] two twisted clients, how can I trigger the other one's callback in one's callback?
I have 2 clients, one gets a message from a server, once I get the message, I want to send it with the other client to another server. how can i do this? can I add some customized events and notice the other client? Thanks. --------------------------------- Get the free Yahoo! toolbar and rest assured with the added security of spyware protection.
On Wed, 20 Jun 2007 03:35:37 -0700 (PDT), slowtech chen <slowtech.chen@yahoo.com> wrote:
I have 2 clients, one gets a message from a server, once I get the message, I want to send it with the other client to another server. how can i do this? can I add some customized events and notice the other client? Thanks.
You need to build this system yourself. Any protocol instance which needs to be able to interact with another protocol instance needs a reference to that other protocol instance, either directly (for example, as an attribute on itself) or indirectly (for example, as an attribute on its factory). With this, methods on the other protocol instance can be invoked to send messages. Here's a trivial example: from twisted.internet.protocol import Protocol, ServerFactory from twisted.trial.unittest import TestCase class BroadcastProtocol(Protocol): """ Protocol which echos received bytes back to all connected BroadcastProtocols. """ def dataReceived(self, bytes): """ Handle received bytes by dispatching them to my factory for broadcast to all clients. """ self.factory.sendMessage(bytes) def sendMessage(self, bytes): """ Write the given bytes to my transport. """ self.transport.write(bytes) class BroadcastFactory(ServerFactory): """ Serve and track BroadcastProtocol instances. @ivar connectedProtocols: A list of all protocol instances which have been returned by buildProtocol. """ protocol = BroadcastProtocol def __init__(self): self.connectedProtocols = [] def buildProtocol(self, addr): """ Instantiate my protocol class, append it to my tracking list, and return it. """ protocol = ServerFactory.buildProtocol(self, addr) self.connectedProtocols.append(protocol) return protocol def sendMessage(self, bytes): """ Send the given bytes to all tracked protocols. """ for proto in self.connectedProtocols: proto.sendMessage(bytes) class BroadcastProtocolTests(TestCase): """ BroadcastProtocol should send all bytes it receives to all other connected BroadcastProtocol instances. """ def test_buildProtocol(self): """ BroadcastFactory.buildProtocol should return an instance of BroadcastProtocol and add that instance to its tracking list. """ factory = BroadcastFactory() protocol = factory.buildProtocol(None) self.assertEqual(factory.connectedProtocols, [protocol]) def test_factorySendMessage(self): """ BroadcastFactory.sendMessage should call sendMessage on each of the protocols in its tracking list. """ class StubProtocol(object): """ Mimick the message-sending interface of BroadcastProtocol. """ def __init__(self): self.messages = [] def sendMessage(self, message): self.messages.append(message) factory = BroadcastFactory() protocol = StubProtocol() factory.connectedProtocols = [protocol] message = object() factory.sendMessage(message) self.assertEqual(protocol.messages, [message]) def test_dataReceived(self): """ BroadcastProtocol.dataReceived should pass whatever bytes it is called with to the factory's sendMessage method. """ class StubFactory(object): """ Mimick the message-sending interface of BroadcastFactory. """ def __init__(self): self.messages = [] def sendMessage(self, message): self.messages.append(message) factory = StubFactory() protocol = BroadcastProtocol() protocol.factory = factory message = object() protocol.dataReceived(message) self.assertEqual(factory.messages, [message]) def test_protocolSendMessage(self): """ BroadcastProtocol.sendMessage should write the bytes it is called with to its transport. """ class StubTransport(object): """ Mimick a transport sufficiently for the purposes of simple writes. """ def __init__(self): self.messages = [] def write(self, bytes): self.messages.append(bytes) protocol = BroadcastProtocol() transport = StubTransport() protocol.makeConnection(transport) message = object() protocol.sendMessage(message) self.assertEqual(transport.messages, [message]) Jean-Paul
On 6/20/07, slowtech chen <slowtech.chen@yahoo.com> wrote:
I have 2 clients, one gets a message from a server, once I get the message, I want to send it with the other client to another server. how can i do this? can I add some customized events and notice the other client? Thanks.
Are they both running in the same process? This is my first non-question post on this list, so please forgive me if I'm giving bad advice - hopefully someone will correct me if I am. If they're both in the same process you can just make calls between them normally. from twisted.internet.protocol import Protocol from twisted.internet import reactor, protocol class YourProtocol(Protocol): def connectionMade(self): self.factory.connections.append(self) print "connected" def connectionLost(self, reason): self.factory.connections.remove(self) print "disconnected" def dataReceived(self, data): # repeat the data to all other connections print "relaying data" for conn in self.factory.connections: if conn != self: conn.transport.write(data) class YourClientFactory(protocol.ClientFactory): protocol = YourProtocol def __init__(self): self.connections = [] if __name__ == '__main__': f = YourClientFactory() reactor.connectTCP("hostname1", 10001, f) reactor.connectTCP("hostname2", 10002, f) reactor.run()
Thanks guys, It helped a lot, but still something I haven't figured out, what I do is like: reactor.connectTCP(host1, port1, factory1) reactor.connectTCP(host2, port2, factory2) using different protocols, so I can't do it the way Arnar does. my confusion is how to get the *valid* protocol instance to refer, I tried factory2.buildProtocol(None) in protocol1's callback, but the instance I get has a None transport attribute. I guess the instance is not the same with the one reactor.connectTCP(host2, port2, factory2) is actually using. thanks for any help. --------------------------------- Fussy? Opinionated? Impossible to please? Perfect. Join Yahoo!'s user panel and lay it on us.
On 6/21/07, slowtech chen <slowtech.chen@yahoo.com> wrote:
Thanks guys, It helped a lot, but still something I haven't figured out, what I do is like:
reactor.connectTCP(host1, port1, factory1) reactor.connectTCP(host2, port2, factory2)
using different protocols, so I can't do it the way Arnar does.
Assuming you pass data from host1 to host2, you can store a reference to factory2 in factory1. from twisted.internet.protocol import Protocol from twisted.internet import reactor, protocol class InputProtocol(Protocol): def connectionMade(self): print "Input connected" def connectionLost(self, reason): print "Input disconnected" def dataReceived(self, data): # repeat the data to all output connections print "relaying data" for conn in self.factory.output_factory.connections: conn.transport.write(data) class OutputProtocol(Protocol): def connectionMade(self): print "Output connected" self.factory.connections.append(self) def connectionLost(self, reason): print "Output disconnected" self.factory.connections.remove(self) class InputFactory(protocol.ClientFactory): protocol = InputProtocol def __init__(self, output_factory): self.output_factory = output_factory class OutputFactory(protocol.ClientFactory): protocol = OutputProtocol def __init__(self): self.connections = [] if __name__ == '__main__': of = OutputFactory() if = InputFactory(of) reactor.connectTCP("sourcehost", 10001, if) reactor.connectTCP("destinationhost", 10002, of) reactor.run() (totally untested) Arnar
participants (3)
-
Arnar Birgisson -
Jean-Paul Calderone -
slowtech chen