diff globalneighbors/web.py @ 0:5dba84370182

initial commit; half-working prototype
author Jeff Hammel <k0scist@gmail.com>
date Sat, 24 Jun 2017 12:03:39 -0700
parents
children 1b94f3bf97e5
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/globalneighbors/web.py	Sat Jun 24 12:03:39 2017 -0700
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+
+"""
+web handler for GlobalNeighbors
+"""
+
+# imports
+import argparse
+import json
+import sys
+import time
+from webob import Request, Response, exc
+from wsgiref import simple_server
+from .locations import locations
+from .locations import city_dict
+from .read import read_cities
+from .read import read_city_list
+from .schema import fields
+from .schema import name
+
+
+class Handler(object):
+    """base class for HTTP handler"""
+
+    def __call__(self, environ, start_response):
+        request = Request(environ)
+        method = getattr(self, request.method, None)
+        response = None
+        if method is not None:
+            response = method(request)
+        if response is None:
+            response = exc.HTTPNotFound()
+        return response(environ, start_response)
+
+
+class CitiesHandler(Handler):
+    """cities ReST API"""
+
+    content_type = 'application/json'
+
+    def __init__(self, locations, cities):
+        self.locations = locations
+        self._cities = cities
+
+
+    def cities(self, startswith=None):
+        """return list of cities"""
+
+        if startswith:
+            return sorted([i[name] for i in self._cities
+                           if i[name].startswith(startswith)])
+        else:
+            return sorted([i[name] for i in self._cities])
+
+    def GET(self, request):
+        return Response(content_type=self.content_type,
+                        body=json.dumps(self.cities(
+                            startswith=request.GET.get('q'))))
+
+
+class GlobalHandler(Handler):
+    """WSGI HTTP Handler"""
+
+    content_type = 'text/plain'
+
+    def __init__(self, datafile):
+        self.datafile = datafile
+
+        # parse data
+        self.cities = read_city_list(self.datafile,
+                                     fields=fields)
+        self.locations = locations(self.cities)
+
+        # TODO: declare handlers
+        self.handlers = {'/cities':
+                         CitiesHandler(self.locations,
+                                       self.cities)}
+
+
+    def GET(self, request):
+        if request.path_info in ('', '/'):
+            # Landing page
+            return Response(content_type=self.content_type,
+                            body="""Global Neighbors
+                            Serving {} cities""".format(len(self.cities)))
+        else:
+            handler = self.handlers.get(request.path_info)
+            if handler:
+                return request.get_response(handler)
+
+
+
+def main(args=sys.argv[1:]):
+    """CLI"""
+
+    # parse command line
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('cities',
+                        help="cities1000 data file")
+    parser.add_argument('-p', '--port', dest='port',
+                        type=int, default=8080,
+                        help="port to serve on")
+    parser.add_argument('--hostname', dest='hostname',
+                        default='localhost',
+                        help="host name [DEFAULT: %(default)]")
+    options = parser.parse_args(args)
+
+    # instantiate WSGI handler
+    app = GlobalHandler(datafile=options.cities)
+
+    # serve it (Warning! Single threaded!)
+    server = simple_server.make_server(host='0.0.0.0',
+                                       port=options.port,
+                                       app=app)
+    try:
+        print ("Serving on http://{hostname}:{port}/".format(**options.__dict__))
+        server.serve_forever()
+    except KeyboardInterrupt:
+        pass
+
+
+if __name__ == '__main__':
+    main()
+