Twisted's Components: Interfaces and Adapters
http://twistedmatrix.com/projects/core/documentation/howto/components.html
Usage of Component based architecture in txrabbitmqctl
To see a real world usage of Twisted's Component based architecture, you need only to understand the basic functionality of the following 4 files from txrabbitmqctl, and how they tie together. (Note: each [...SNIP...] denotes removed code that adds nothing to the understanding of the core patterns involved)
Explanation of the fundamental role of each file:
- irabbitmqctl.py - (The Interface definition)
- rabbitmqctl_service.py - (An implementation of the Interface using TwOTP - in the form of a Twisted Service)
- webui.py - (An Adapter implementation, and the framework Registration of the Adapter's ability to adapt implementations of 1 specific interface implementation to 1 or more other interfaces)
- webui-example.tac.py - (Real world usage of the (http) Adapter (RabbitMQControlWebUI) for the interface implementation (RabbitMQControlService))
irabbitmqctl.py
class IRabbitMQControlService(Interface): """ Functionality of 'rabbitmqctl' exposed as a Twisted Service. """ def add_user(username, password): """add new user with given password""" def delete_user(username): """delete user""" [...SNIP...]
rabbitmqctl_service.py
class RabbitMQControlService(service.Service):
"""Service that communicates with RabbitMQ via the Erlang node protocol.
Provides access to RabbitMQ meta-data such as the number of exchanges, queues, etc
as well as the ability to do management functions like add users and vhosts, etc.
The communication happens with Twotp, which implements the Erlang node protocol for Twisted.
"""
implements(IRabbitMQControlService)
def __init__(self, process, nodename="rabbit", module="rabbit_access_control"):
self.process = process
self.nodename = nodename
self.module = module
@inlineCallbacks
def add_user(self, username, password):
"""add new user with given password"""
username, password = Binary(username), Binary(password)
result = yield self.process.callRemote(self.nodename, self.module, "add_user", username, password)
print result
response = {"command":"add_user", "username":username.value, "result":result.value}
returnValue(response)
@inlineCallbacks
def delete_user(self, username):
"""delete user"""
username = Binary(username)
result = yield self.process.callRemote(self.nodename, self.module, "delete_user", username)
response = {"command":"delete_user", "username":username.value, "result":result.value}
returnValue(response)
[...SNIP...]
webui.py
from twisted.web import resource [...SNIP...] class RabbitMQControlWebUI(resource.Resource): [...SNIP...] components.registerAdapter(RabbitMQControlWebUI, IRabbitMQControlService, resource.IResource)
webui-example.tac.py
import os
import sys
import time
from twisted.application import internet, service
from twisted.web import resource, server
from twotp import Process, readCookie, buildNodeName
from rabbitmqctl_service import RabbitMQControlService
from webui.webui import RabbitMQControlWebUI
WEBLOGPATH = "/tmp/txrabbitmqctl.web.%d.log" % int(time.time())
cookie = open(os.path.join(os.path.expanduser("~"), ".erlang.cookie.local")).read().strip()
nodeName = buildNodeName("twotp-rabbit")
process = Process(nodeName, cookie)
rservice = RabbitMQControlService(process)
site = server.Site(resource.IResource(rservice), logPath=WEBLOGPATH)
application = service.Application('rabbitmqctl')
serviceCollection = service.IServiceCollection(application)
internet.TCPServer(8000, site).setServiceParent(serviceCollection)