Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """A WSGI middleware that run the application in a green thread.
- THIS SOFTWARE IS UNDER MIT LICENSE.
- Copyright (c) 2010 Manlio Perillo (manlio.perillo@gmail.com)
- """
- import sys
- from greenlet import getcurrent, greenlet
- from mako.template import Template
- class GState(tuple):
- pass
- GCONTINUE = 0
- GSUSPEND = 1
- class middleware(object):
- """A middleware that use greenlet to provide non linear control flow.
- """
- def __init__(self, application):
- self.app = application
- def __call__(self, environ, start_response):
- def _start_response(status, headers):
- start_response(status, headers)
- return self.write
- # Initialize greenlet and state
- gp = greenlet(self.app)
- self.in_app_iter = False
- r = gp.switch(environ, _start_response)
- while isinstance(r, GState):
- buf, status = r
- if status == GSUSPEND:
- # TODO: async WSGI extension
- # environ['wsgiorg.suspend']()
- # TODO: store environ as a per green thread state
- # gp.environ = environ
- pass
- yield buf
- r = gp.switch()
- # The application returned the app_iter object
- self.in_app_iter = True
- for buf in r:
- yield buf
- def write(self, buf):
- """WSGI "safe" write callable.
- """
- gp = getcurrent()
- if self.in_app_iter:
- exc = ValueError(
- 'write callable called from application iterator')
- gp.throw(exc)
- else:
- gp.parent.switch(GState((buf, GCONTINUE)))
- def flush(ctx):
- """A Mako function that flush the current buffer and return data
- to the caller thread.
- """
- gp = getcurrent()
- body = ctx._buffer_stack[0].getvalue()
- # TODO: get encoding to use from WSGI environ, stored in green
- # thread instance
- buf = body.encode('us-ascii')
- # XXX assume FastEncodingBuffer is used
- ctx._buffer_stack[0].data[:] = []
- gp.parent.switch(GState((buf, GCONTINUE)))
- return ''
- @middleware
- def application(environ, start_response):
- """A sample WSGI application that use Mako.
- """
- headers = [('Content-Type', 'text/html')]
- write = start_response('200 OK', headers)
- write('some data from write callable\n')
- buf = tmpl.render_unicode(body='Body')
- return [buf]
- tmpl = Template("""
- <%namespace name="greenlet" module="__main__" />
- <html>
- <head>
- <title>Mako example</title>
- </head>
- <body>
- <div>Header</div>
- ${greenlet.flush()}
- ## TODO: async subrequest
- <div>${body}</div>
- ${greenlet.flush()}
- <div>Footer</div>
- </body>
- </html>
- """)
- if __name__ == '__main__':
- def start_response(status, headers):
- def write(buf):
- raise NotImplementedError
- print 'status:', status
- print 'headers', headers
- return write
- environ = {}
- r = application(environ, start_response)
- for i, buf in enumerate(r):
- print 'chunk #%d' % i
- sys.stdout.write(buf)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement