Introduction
Twisted is a powerful Internet framework allowing you to develop networked applications quickly.
PyAMF features the TwistedGateway that allows you to bridge the gap between your Twisted application and AMF based programs.
The following example is the ‘classic’ way of setting up a Twisted web service, where you import the reactor manually and start it yourself. For the current, canonical way of setting up a service, see the next section.
The example below is a complete standalone twisted.web server that exposes various functions via PyAMF. We added comments to attempt to explain all relevant lines of code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | from twisted.internet import reactor, defer
from twisted.web import server, static, resource
from pyamf.remoting.gateway.twisted import TwistedGateway
from pyamf.remoting.gateway import expose_request
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s'
)
class example:
"""
An example class that can be used as a PyAMF service.
"""
def test1(self):
return "Test 1 Success!"
@expose_request
def testn(self, request, n):
"""
This function is decorated to expose the underlying HTTP request,
which provides access to things such as the requesting client's IP.
"""
ip = request.getClientIP()
return "%s said %s!" % (ip, n)
# A standalone function that can be bound to a service.
def add(a, b):
return a + b
# Create a dictionary mapping the service namespaces to a function
# or class instance
services = {
'example': example(),
'myadd': add
}
# Place the namespace mapping into a TwistedGateway
gateway = TwistedGateway(services, logger=logging, expose_request=False,
debug=True)
# A base root resource for the twisted.web server
root = resource.Resource()
# Publish the PyAMF gateway at the root URL
root.putChild('', gateway)
# Start the twisted reactor and listen on HTTP port 8080
print 'Running AMF gateway on http://localhost:8080'
reactor.listenTCP(8080, server.Site(root))
reactor.run()
|
The gateway supports returning a deferred from your callable. If you are not familiar with deferreds you should check out the Twisted documentation.
Hopefully this gives you a basic understanding of how to expose functions within Twisted.
Here is the same service, designed to be run with twistd:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | from twisted.web import resource, server
from twisted.application import service, strports
from pyamf.remoting.gateway.twisted import TwistedGateway
from pyamf.remoting.gateway import expose_request
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s'
)
class example:
"""
An example class that can be used as a PyAMF service.
"""
def test1(self, n):
return "Test 1 Success!"
@expose_request
def testn(self, request, n):
"""
This function is decorated to expose the underlying HTTP request,
which provides access to things such as the requesting client's IP.
"""
ip = request.getClientIP()
return "%s said %s!" % (ip, n)
# A standalone function that can be bound to a service.
def add(a, b):
return a + b
# Create a dictionary mapping the service namespaces to a function
# or class instance
services = {
'example': example(),
'myadd': add
}
# Ideally, just the imports and the code below this comment would be
# in the .tac file; the AMF service would be defined in a module of
# your making
# Place the namespace mapping into a TwistedGateway
gateway = TwistedGateway(services, logger=logging, expose_request=False,
debug=True)
# A base root resource for the twisted.web server
root = resource.Resource()
# Publish the PyAMF gateway at the root URL
root.putChild('', gateway)
print 'Running AMF gateway on http://localhost:8080'
application = service.Application('PyAMF Sample Remoting Server')
server = strports.service('tcp:8080', server.Site(root))
server.setServiceParent(application)
|
You can also use Twisted WSGI support in combination with PyAMF WSGIGateway like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | import logging
from pyamf.remoting.gateway.wsgi import WSGIGateway
from pyamf.remoting.gateway import expose_request
from twisted.web import server
from twisted.web.wsgi import WSGIResource
from twisted.python.threadpool import ThreadPool
from twisted.internet import reactor
from twisted.application import service, strports
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s'
)
class example:
"""
An example class that can be used as a PyAMF service.
"""
def test1(self, n):
return "Test 1 Success!"
@expose_request
def testn(self, request, n):
"""
This function is decorated to expose the underlying HTTP request,
which provides access to things such as the requesting client's IP.
"""
ip = request['REMOTE_ADDR']
return "%s said %s!" % (ip, n)
# A standalone function that can be bound to a service.
def add(a, b):
return a + b
# Create a dictionary mapping the service namespaces to a function
# or class instance
services = {
'example': example(),
'myadd': add
}
# Create and start a thread pool,
wsgiThreadPool = ThreadPool()
wsgiThreadPool.start()
# ensuring that it will be stopped when the reactor shuts down
reactor.addSystemEventTrigger('after', 'shutdown', wsgiThreadPool.stop)
# PyAMF gateway
gateway = WSGIGateway(services, logger=logging, expose_request=False,
debug=True)
# Create the WSGI resource
wsgiAppAsResource = WSGIResource(reactor, wsgiThreadPool, gateway)
site = server.Site(wsgiAppAsResource)
server = strports.service('tcp:8080', site)
# Hooks for twistd
application = service.Application('PyAMF Sample Remoting Server')
server.setServiceParent(application)
|
Save this in a file called something like mytest.tac and then start the web server with the following command:
twistd -noy mytest.tac
Using Twisted’s twistd commandline tool and a .tac file is good for many reasons. Here are some highlights:
To test the gateway you can use a Python AMF client like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from pyamf.remoting.client import RemotingService
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s'
)
url = 'http://localhost:8080'
client = RemotingService(url, logger=logging, debug=True)
service1 = client.getService('example')
print service1.testn('Hello World')
service2 = client.getService('myadd')
print service2(1,2)
|