It sounds like you've gotten past the first hurdle - figuring out how to have A and B interact at all. That's good, since for most people that's the biggest conceptual challenge. As for making it elegant, if you're after an approach that keeps your protocol code isolated from the application code driving it (ie, the "business logic"), there are several options. I'll give an example of one based on Deferreds.
Let's consider two POP3 clients. You want the first to retrieve a message list, then the second to retrieve the first message from the resulting list. This example
from twisted.internet import defer, protocol, reactor
from twisted.mail.pop3 import AdvancedPOP3Client
class MessageDownloader(object):
def __init__(self, host, port, user, password):
self.host = host
self.port = port
self.user = user
self.password = password
self.cc = ClientCreator(reactor, AdvancedPOP3Client)
def connect(self):
"""
Connect to the POP3 server and authenticate. Return a Deferred
which fires with the connected protocol instance.
"""
connDeferred = self.cc.connect(self.host, self.port)
def cbAuthenticate(proto):
loginDeferred = proto.login(user, password)
loginDeferred.addCallback(lambda ignored: proto)
return loginDeferred
connDeferred.addCallback(cbAuthenticate)
return connDeferred
def run(self):
connDeferred = self.connect()
connDeferred.addCallback(self.cbFirstConnection)
return connDeferred
def cbFirstConnection(self, firstProto):
listDeferred = firstProto.listUID()
def cbListed(uidList):
connDeferred = self.connect()
def cbConnected(secondProto):
return secondProto.retrieve(uidList[0])
connDeferred.addCallback(cbConnected)
listDeferred.addCallback(cbListed)
return listDeferred
if __name__ == '__main__':
import sys
MessageDownloader(*sys.argv[1:]).run()
reactor.run()
Here, all of the logic about retrieving a list of UIDs and setting up a new connection to retrieve a message is separate from the actual protocol implementation (which is entirely in Twisted). The Deferreds returned from almost all of the APIs used here allow events to be connected up however your application wants.