176 lines
5.1 KiB
Python
176 lines
5.1 KiB
Python
"""
|
|
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[:]):
|
|
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
|
|
|
|
|
|
class NotFoundError(ValueError):
|
|
pass
|
|
|
|
|
|
class ShippingCostApp(object):
|
|
|
|
def __call__(self, environ, start_response):
|
|
try:
|
|
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)))
|
|
])
|
|
return [ret]
|
|
|
|
|
|
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)
|
|
|
|
|
|
class PlaintextShippingOptionsResponse(object):
|
|
_head = ''
|
|
_record = '{service}: {price} USD'
|
|
_tail = ''
|
|
_content_type = 'text/plain'
|
|
|
|
def __init__(self, shipping_options):
|
|
self._shipping_options = shipping_options
|
|
|
|
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)
|
|
|
|
|
|
class XMLShippingOptionsResponse(PlaintextShippingOptionsResponse):
|
|
_head = '<options>'
|
|
_record = ('<option><service>{service}</service>'
|
|
'<price>{price}</price></option>')
|
|
_tail = '</options>'
|
|
_content_type = 'text/xml'
|
|
|
|
|
|
class CrossdomainXMLResponse(PlaintextShippingOptionsResponse):
|
|
_content_type = 'text/xml'
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
def __str__(self):
|
|
return (
|
|
'<cross-domain-policy>'
|
|
'<allow-access-from domain="*"/>'
|
|
'</cross-domain-policy>'
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|
|
|
|
# vim:filetype=python
|