| Author: | Dave Kuhlman |
|---|---|
| Address: | dkuhlman@rexx.com http://www.rexx.com/~dkuhlman |
| Revision: | 1.1d |
| Date: | Jan. 21, 2004 |
| Copyright: | Copyright (c) 2004 Dave Kuhlman. This documentation is covered by The MIT License: http://www.opensource.org/licenses/mit-license. |
Abstract
Documentation on how to set up Quixote with Medusa.
Medusa is a 'server platform' -- it provides a framework for implementing asynchronous socket-based servers (TCP/IP and on Unix, Unix domain, sockets).
For our purposes, Medusa provides an HTTP 1.1 Web server.
This document explains how to use Medusa in support of Quixote.
Down-load Medusa from http://www.amk.ca/python/code/medusa.html.
Unroll it with something like:
tar xvzf medusa-0.5.4.tar.gz
Install Medusa with the following (You may have to become root to do this.):
cd medusa-0.5.4 python setup.py install
Here is a sample, taken from qxdemo, the Quixote demo application:
#!/usr/bin/env python
try:
from medusa import http_server, xmlrpc_handler
except ImportError:
print '\n' + '='*50
print 'medusa/ package not found; fetch it from '
print ' http://www.amk.ca/files/python/'
print 'and install it.'
print '='*50
raise
import asyncore
from quixote.publish import Publisher
from quixote.server import medusa_http
from quixote import enable_ptl
enable_ptl()
# Server that exposes the links demo program on port 8080
PORT = 8080 # [1]
print 'Now serving the qxdemo.links demo on port %i' % PORT
server = http_server.http_server('', PORT)
publisher = Publisher('qxdemo.ui.links') # [2]
publisher.config.debug_log = "/tmp/debug" # [3]
publisher.config.error_log = "/tmp/error"
publisher.setup_logs()
dh = medusa_http.QuixoteHandler(publisher, 'qxdemo/links server', server) # [4]
server.install_handler(dh)
try:
asyncore.loop()
except KeyboardInterrupt: # [5]
pass
Notes and customization (see [n] comments in the code):
Change the port that you want to receive requests on.
Change the Python path to your application. If the root of your application is in a __init__.py file, specify the path to the directory (package) that contains it, for example:
publisher = Publisher('qxdemo.ui')
If the root of your application is in a plain Python source file such as qxdemo/ui/links.py, specify the path to that module, for example:
publisher = Publisher('qxdemo.ui.links')
You can also specify log files (and a lot more) in a Quixote configuration file. In order to do so:
Copy the default configuration script config.py from the Quixote distribution to a location of your choice.
Edit your copy of the configuration file. The default configuration script contains comments to help with this task.
Replace the lines containing publisher.config. ... with the following line containing the path to your configuration script:
publisher.read_config('myconfig.py')
Change the server name string. In our sample script above, the value of the SERVER_SOFTWARE environment variable will be "qxdemo/links server".
The try:except: block enables us to catch a break (Ctrl-C) and perform any needed clean-up. For example, had we subclassed the Publisher class and created any connections, proxies, etc, this would allow us to close connections etc.
Note: You will need to add the directory containing your application to your PYTHONPATH before running the following code.
In order to start your server, run your driver script. For example, if the name of your driver script is server-medusa.py, the following will start your server:
python server-medusa.py
In some applications it is useful to create and reuse things like database connections, proxies for XML-RPC and SOAP client access, etc. Here is a more extensive Medusa driver script that shows how to do this:
#!/usr/bin/env python
#
# Medusa server that exposes the skeleton program.
#
from optparse import OptionParser
try:
from medusa import http_server, xmlrpc_handler
except ImportError:
print '\n' + '='*50
print 'medusa/ package not found; fetch it from '
print ' http://www.amk.ca/files/python/'
print 'and install it.'
print '='*50
raise
import asyncore
from quixote.publish import Publisher
from quixote.server import medusa_http
from pyPgSQL import PgSQL
import xmlrpclib
from quixote import enable_ptl
enable_ptl()
# Warning: Must import SOAPpy *after* enable_ptl. I don't know why.
from SOAPpy import SOAPProxy
# Default port to listen on.
PORT = 8080
CONNECT_ARGS_FILE = 'connection_args.txt'
#
# A container for persistent connections etc.
#
class PersistentContainer:
pass
class MyPublisher(Publisher):
def __init__(self, root_namespace, config=None):
Publisher.__init__(self, root_namespace, config)
self.container = PersistentContainer()
connectionFile = file(CONNECT_ARGS_FILE, 'r')
connectionArgs = connectionFile.read().strip()
connectionFile.close()
self.container.dbConnection = PgSQL.connect(connectionArgs)
self.container.xmlrpcProxy = xmlrpclib.ServerProxy('http://localhost:8082')
self.container.soapProxy = SOAPProxy(str("http://localhost:8083/"))
meerkatURI = "http://www.oreillynet.com/meerkat/xml-rpc/server.php"
self.container.meerkatServer = xmlrpclib.Server(meerkatURI)
def cleanup(self):
self.container.dbConnection.close()
def start_request(self, request):
Publisher.start_request(self, request)
request.container = self.container
def start_server(port):
print 'Now serving the skeleton services on port %i' % port
server = http_server.http_server('', port)
publisher = MyPublisher('skeleton.ui')
publisher.read_config('config.py')
publisher.setup_logs()
dh = medusa_http.QuixoteHandler(publisher, 'skeleton/services on medusa server', server)
server.install_handler(dh)
try:
asyncore.loop()
except KeyboardInterrupt:
publisher.cleanup()
USAGE_TEXT = """
python %prog [options]
example:
python %prog -p 8081"""
def usage(parser):
parser.print_help()
sys.exit(-1)
def main():
global Verbose
parser = OptionParser(USAGE_TEXT)
parser.add_option("-p", "--port", type="int",
dest="port", help="port to listen on")
(options, args) = parser.parse_args()
port = PORT
if options.port:
port = options.port
if len(args) == 0:
start_server(port)
else:
usage(parser)
if __name__ == "__main__":
main()
Explanation:
ReusingConnections: The Quixote Wiki section ReusingConnections describes start-up scripts, how to reuse resources, and how to clean-up resources and connections when the server shuts down.