getting the WSGI app dressed up for the ball
This commit is contained in:
parent
6249efbac8
commit
f40357c79d
@ -1,37 +1,66 @@
|
||||
"""
|
||||
standalone WSGI application for serving plaintext and xml suitable
|
||||
for the Adobe Flex "Getting Started" tutorial, "Part II. Exchanging Data"
|
||||
|
||||
For the plaintext data flex app, set the HTTPService url to:
|
||||
|
||||
http://<hostname>:<port>/text
|
||||
|
||||
For the xml data flex app, set the HTTPService url to:
|
||||
|
||||
http://<hostname>:<port>/xml
|
||||
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import cgi
|
||||
import optparse
|
||||
from wsgiref.simple_server import make_server
|
||||
|
||||
__author__ = 'Dan Buch dbuch@ag.com'
|
||||
__license__ = 'AGI'
|
||||
|
||||
USAGE = """\
|
||||
%prog [options]
|
||||
Run a standalone WSGI app for the Adobe Flex Tutorial
|
||||
"Getting Started", "Part II. Exchanging Data"
|
||||
"""
|
||||
|
||||
|
||||
def main(sysargs=sys.argv[:]):
|
||||
port = 18080
|
||||
server = make_server('0.0.0.0', port, shipping_app)
|
||||
print('serving {0.__name__} on port {1}'.format(shipping_app, port))
|
||||
parser = optparse.OptionParser(usage=USAGE)
|
||||
parser.add_option('-p', '--port', dest='port', type='int',
|
||||
help='port number on which to serve app, default=%default',
|
||||
default=18080)
|
||||
parser.add_option('-i', '--interface', dest='interface',
|
||||
help='interface on which to serve app, default=%default',
|
||||
default='0.0.0.0')
|
||||
|
||||
opts = parser.parse_args(sysargs[1:])[0]
|
||||
|
||||
server = make_server(opts.interface, opts.port, ShippingCostApp())
|
||||
print('serving {0.__name__} on '
|
||||
'port {1}'.format(ShippingCostApp, opts.port))
|
||||
server.serve_forever()
|
||||
return 0
|
||||
|
||||
|
||||
def shipping_app(environ, start_response):
|
||||
path_info = environ.get('PATH_INFO', '').strip('/')
|
||||
class NotFoundError(ValueError):
|
||||
pass
|
||||
|
||||
handler = {
|
||||
'text': plaintext_handler,
|
||||
'xml': xml_handler,
|
||||
'crossdomain.xml': crossdomain_xml_handler,
|
||||
}.get(path_info)
|
||||
|
||||
if handler:
|
||||
class ShippingCostApp(object):
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
try:
|
||||
return handler(environ, start_response)
|
||||
except Exception:
|
||||
start_response('500 Internal Server Error', [
|
||||
('content-type', 'text/plain'),
|
||||
])
|
||||
return ['OUCH']
|
||||
else:
|
||||
ret = 'nothin at {0!r}'.format(path_info)
|
||||
return ShippingCostHandler(environ, start_response).handle()
|
||||
except NotFoundError:
|
||||
return self._handle_404(environ, start_response)
|
||||
|
||||
@classmethod
|
||||
def _handle_404(cls, environ, start_response):
|
||||
ret = 'nothin at {0!r}'.format(environ.get('PATH_INFO', '/'))
|
||||
start_response('404 Not Found', [
|
||||
('content-type', 'text/plain'),
|
||||
('content-length', str(len(ret)))
|
||||
@ -39,72 +68,105 @@ def shipping_app(environ, start_response):
|
||||
return [ret]
|
||||
|
||||
|
||||
def get_params(environ):
|
||||
params = cgi.parse(fp=environ.get('wsgi.input'), environ=environ)
|
||||
for key, value in params.iteritems():
|
||||
if len(value) == 1:
|
||||
params[key] = value[0]
|
||||
return params
|
||||
class ShippingCostHandler(object):
|
||||
_shipping_options = None
|
||||
_zipcode = 0
|
||||
_pounds = 0
|
||||
_handler_method = ''
|
||||
|
||||
def __init__(self, environ, start_response):
|
||||
self.environ = environ
|
||||
self.start_response = start_response
|
||||
self._path_info = self.environ.get('PATH_INFO', '').strip('/')
|
||||
self._handler_method = \
|
||||
'_handle_{0}'.format(self._path_info.replace('.', '_'))
|
||||
|
||||
def _get_params(self):
|
||||
"""some dumb param fetching, ignores multiple values for
|
||||
same var name, e.g. query of "zipcode=12345&zipcode=90210"
|
||||
would effectively discard the 90210 value
|
||||
"""
|
||||
params = cgi.parse_qs(self.environ.get('QUERY_STRING', ''))
|
||||
|
||||
for intvar in ('zipcode', 'pounds'):
|
||||
if params.get(intvar):
|
||||
value = int(float(params.get(intvar)[0]))
|
||||
setattr(self, '_{0}'.format(intvar), value)
|
||||
|
||||
def _get_shipping_options(self):
|
||||
base_cost = (float(self._zipcode) / 10000.0) + (self._pounds * 5.0)
|
||||
self._shipping_options = {
|
||||
"Next Day": int(base_cost * 4),
|
||||
"Two Day Air": int(base_cost * 2),
|
||||
"Saver Ground": int(base_cost)
|
||||
}
|
||||
|
||||
def handle(self):
|
||||
if hasattr(self, self._handler_method):
|
||||
self._get_params()
|
||||
self._get_shipping_options()
|
||||
return getattr(self, self._handler_method)()
|
||||
else:
|
||||
raise NotFoundError
|
||||
|
||||
def _handle_xml(self):
|
||||
response = XMLShippingOptionsResponse(self._shipping_options)
|
||||
return response(self.environ, self.start_response)
|
||||
|
||||
def _handle_text(self):
|
||||
response = PlaintextShippingOptionsResponse(self._shipping_options)
|
||||
return response(self.environ, self.start_response)
|
||||
|
||||
def _handle_crossdomain_xml(self):
|
||||
response = CrossdomainXMLResponse()
|
||||
return response(self.environ, self.start_response)
|
||||
|
||||
|
||||
def xml_handler(environ, start_response):
|
||||
params = get_params(environ)
|
||||
zipcode = int(float(params.get('zipcode', 0)))
|
||||
pounds = int(float(params.get('pounds', 0)))
|
||||
class PlaintextShippingOptionsResponse(object):
|
||||
_head = ''
|
||||
_record = '{service}: {price} USD'
|
||||
_tail = ''
|
||||
_content_type = 'text/plain'
|
||||
|
||||
ret = ['<options>']
|
||||
for service, price in get_shipping_options(zipcode, pounds).iteritems():
|
||||
ret.append('<option><service>{service}</service>'
|
||||
'<price>{price}</price></option>'.format(**locals()))
|
||||
ret.append('</options>')
|
||||
body = '\n'.join(ret)
|
||||
def __init__(self, shipping_options):
|
||||
self._shipping_options = shipping_options
|
||||
|
||||
start_response('200 OK', [
|
||||
('content-type', 'text/xml'),
|
||||
('content-length', str(len(body)))
|
||||
])
|
||||
return [body]
|
||||
def __call__(self, environ, start_response):
|
||||
body = str(self)
|
||||
start_response('200 OK', [
|
||||
('content-type', self._content_type),
|
||||
('content-length', str(len(body))),
|
||||
])
|
||||
return [body]
|
||||
|
||||
def __str__(self):
|
||||
ret = [self._head]
|
||||
for service, price in self._shipping_options.iteritems():
|
||||
ret.append(self._record.format(service=service, price=price))
|
||||
ret.append(self._tail)
|
||||
return '\n'.join(ret)
|
||||
|
||||
|
||||
def plaintext_handler(environ, start_response):
|
||||
params = get_params(environ)
|
||||
zipcode = int(float(params.get('zipcode', 0)))
|
||||
pounds = int(float(params.get('pounds', 0)))
|
||||
|
||||
ret = []
|
||||
for service, price in get_shipping_options(zipcode, pounds).iteritems():
|
||||
ret.append('{service}: {price} USD'.format(**locals()))
|
||||
body = '\n'.join(ret)
|
||||
|
||||
start_response('200 OK', [
|
||||
('content-type', 'text/plain'),
|
||||
('content-length', str(len(body)))
|
||||
])
|
||||
return [body]
|
||||
class XMLShippingOptionsResponse(PlaintextShippingOptionsResponse):
|
||||
_head = '<options>'
|
||||
_record = ('<option><service>{service}</service>'
|
||||
'<price>{price}</price></option>')
|
||||
_tail = '</options>'
|
||||
_content_type = 'text/xml'
|
||||
|
||||
|
||||
def crossdomain_xml_handler(environ, start_response):
|
||||
start_response('200 OK', [
|
||||
('content-type', 'text/xml'),
|
||||
('content-length', str(len(XD_XML))),
|
||||
])
|
||||
return [XD_XML]
|
||||
class CrossdomainXMLResponse(PlaintextShippingOptionsResponse):
|
||||
_content_type = 'text/xml'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
XD_XML = """\
|
||||
<cross-domain-policy>
|
||||
<allow-access-from domain="*"/>
|
||||
</cross-domain-policy>
|
||||
"""
|
||||
|
||||
|
||||
def get_shipping_options(zipcode, pounds):
|
||||
base_cost = (float(zipcode) / 10000.0) + (pounds * 5.0)
|
||||
return {
|
||||
"Next Day": int(base_cost * 4),
|
||||
"Two Day Air": int(base_cost * 2),
|
||||
"Saver Ground": int(base_cost)
|
||||
}
|
||||
def __str__(self):
|
||||
return (
|
||||
'<cross-domain-policy>'
|
||||
'<allow-access-from domain="*"/>'
|
||||
'</cross-domain-policy>'
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
Loading…
Reference in New Issue
Block a user