view wsgraph/web.py @ 12:421d5119e324

reluctantly make this a CLI entry point
author Jeff Hammel <jhammel@mozilla.com>
date Mon, 10 Dec 2012 17:30:44 -0800
parents 9016b126aa87
children 7459702bf574
line wrap: on
line source

#!/usr/bin/env python

"""
web handler for WSGraph
"""

import json
import sys
from webob import Request, Response, exc

# rank constants
GRAPH = 0
NODE = 1
EDGE = 2

# XXX stubbing hacks
class JSONformatter(object):
    def __init__(self, sort_keys=True):
        self.sort_keys = sort_keys

    def format(self, _object):
        return json.dumps(graph.node(node), sort_keys=self.sort_keys)

    def node(self, node, graph, request):
        return Response(body=self.format(graph.node(node)))

def JSONFormatter(node, graph, request):
    return json.dumps(graph.node(node), sort_keys=True)
def JSONGraphFormatter(graph, request):
    return json.dumps({'nodes': graph.nodes(),
                       'edges': graph.edges()},
                      sort_keys=True)

class Dispatcher(object):

    def __init__(self, graph,
                 graph_formatters=None,
                 node_formatters=None,
                 edge_formatters=None,
                 require_auth=False):
        self.graph = graph
        self.require_auth = require_auth

        # use JSON formatter by default
        if graph_formatters is None:
            graph_formatters = {None: JSONGraphFormatter}
         if node_formatters is None:
            node_formatters = {None: JSONFormatter}
         if edge_formatters is None:
            edge_formatters = {None: JSONFormatter}

        self.formatters = {GRAPH: graph_formatters,
                           NODE: node_formatters,
                           EDGE: edge_formatters}
        for key, value in formatters.items():
            # ensure default formatter
            assert None in value

        self.methods = dict([(i, getattr(self, i))
                             for i in dir(self)
                             if i.isupper()])

    def __call__(self, environ, start_response):
        request = Request(environ)
        method = self.methods.get(request.method)
        if method is None:
            return exc.HTTPMethodNotAllowed()(environ, start_response)
        response = method(request)
        return response(environ, start_response)

    @staticmethod
    def path_segments(path):
        """split a path into segments"""
        segments = path.strip('/').split('/')
        if segments == ['']:
            segments = []
        return segments

    # HTTP methods

    def GET(self, request):
        """
        respond to a GET request

        Formatters are keyed off of

        formatters = {0: {
        }

        A graph formatter takes the following arguments:

            def sample_graph_formatter(graph, request):

        A node formatter takes the following arguments:

            def sample_node_formatter(node, graph, request):

        An edge formatter takes the following arguments:

            def sample_edge_formatter(edge, graph, request):

        API:

        ?format=<format>

        """

        # get resource requestor
        segments = self.path_segments(request.path_info)
        rank = len(segments)
        if rank not in (0,1,2):
            return exc.HTTPNotFound()


        # is resource in the graph? [TODO]
        if (rank == EDGE) or (rank == NODE):
            if tuple(segments) not in self.graph:
                retun exc.HTTPNotFound()

        # formatter
        formatter = self.formatters[len(segments)]
        return Response(content_type='text/plain',
                        body="WSGraph")

    def POST(self, request):
        """
        respond to a POST request

        API:

        ?update :
        """

        return exc.HTTPSeeOther(location='/') # TODO: /path/to/self

    def HEAD(self, request):
        """respond to a HEAD request"""
        raise NotImplementedError

    def OPTIONS(self, request):
        return Response() # TODO: Allow=', '.join(self.methods); Content-Length=0


def main(args=sys.argv[1:]):
    """example web server"""

    # imports
    from wsgiref import simple_server
    from model import MemoryCache
    from optparse import OptionParser

    # parse command line options
    parser = OptionParser()
    parser.add_option('-p', '--port', type='int', default=8080,
                      help="port to serve on")
    options, args = parser.parse_args()

    # example model
    graph = MemoryCache()

    # WSGI app
    app = Dispatcher(graph=graph)
    server = simple_server.make_server(host='0.0.0.0', port=options.port, app=app)
    print 'http://localhost:%s/' % options.port
    server.serve_forever()

if __name__ == '__main__':
    main()