Zope2 Sprint
»
TwistedZope
»
ChrisHacksDonovansCode
import os import sys import string #import base64 #from cStringIO import StringIO from twisted.protocols import http from twisted.python import log from twisted.web import static, server, twcgi, resource from twisted.application import service, internet here = os.path.abspath(os.path.dirname(__file__)) sys.path.insert(0, os.path.join(here, 'lib', 'python')) from ZPublisher.Publish import publish_module from ZPublisher import HTTPResponse #log.startLogging(file('twisted.log', 'w')) def setupzope(): import Zope Zope.configure(os.path.join(here, 'etc', 'zope.conf')) Zope.startup() __version__ = 1 port = 6969 class ZopeResource(resource.Resource): """ A very minimal twisted Resource """ def __init__(self, data): self.response = data class ZopeRequest(server.Request): """ Adapt twisted Requests to zope """ def render(self, resource): """ Override twisted's server.Request.render method to do what Zope needs with the response """ response = resource.response self.transport.write('HTTP/1.1 %s %s\r\n' % ( response.status, http.responses[response.status])) self.transport.write(str(response)) self.transport.loseConnection() def get_cgi_env(self): """ Setup the special CGI environment variables Zope needs in order to function properly """ script_name = "/"+string.join(self.prepath, '/') python_path = string.join(sys.path, os.pathsep) serverName = string.split(self.getRequestHostname(), ':')[0] auth = self.getHeader('Authorization') cookie = self.getHeader('cookie') referer = self.getHeader('referer') query = '' try: query = self.uri.split('?', 1)[1] except: query = '' env = { "SERVER_SOFTWARE": 'ZTwisted' , # server.version, "SERVER_NAME": serverName, "GATEWAY_INTERFACE": "CGI/1.1", "SERVER_PROTOCOL": self.clientproto, "SERVER_PORT": str(self.getHost()[2]), "REQUEST_METHOD": self.method, "SCRIPT_NAME": script_name, # XXX "REQUEST_URI": self.uri, "PATH_INFO": self.path, "HTTP_AUTHORIZATION": auth, "HTTP_COOKIE": cookie, "HTTP_REFERER": referer, "QUERY_STRING": query, } ct = self.getHeader('content-type') if ct: env['CONTENT_TYPE'] = ct cl = self.getHeader('content-length') if cl: env['CONTENT_LENGTH'] = cl return env class Dummy: """ This is used later to redirect stdout """ def write(self, data): """ like /dev/null """ pass class ZopeSite(server.Site): """ Twisted representation of a Zope app """ requestFactory = ZopeRequest def getResourceFor(self, request): """ get a twisted ZopeResource (HTTP Response data) by using ZPublisher to traverse Zope objects """ stdout = Dummy() env = request.get_cgi_env() request.content.seek(0,0) response = HTTPResponse.HTTPResponse() publish_module('Zope', stdin=request.content, stdout=stdout, environ=env, response=response) return ZopeResource(response) """ Note that in the Twisted paradigm, the previous code would be in a .py file and the following code would be in a separate .tac file which would import the code above and be run with twistd; see example code from the Nevow project and Twisted documentation for details. One of the major missing thing is obviously the equivalent of ZRendezvous to do thread pool management. Right now, it's single- threaded. """ if __name__ == '__main__': print 'ERROR: Run this via twistd -noy %s' % __file__ sys.exit(1) setupzope() application = service.Application("twisted-zope") internet.TCPServer(port, ZopeSite(None)).setServiceParent(application)