Mercurial > hg > WSGraph
annotate wsgraph/web.py @ 54:a10582739c9c
http://igraph.sourceforge.net/
| author | Jeff Hammel <jhammel@mozilla.com> |
|---|---|
| date | Tue, 25 Jun 2013 10:25:36 -0700 (2013-06-25) |
| parents | 24d57daaca21 |
| children |
| rev | line source |
|---|---|
| 0 | 1 #!/usr/bin/env python |
| 2 | |
| 3 """ | |
| 4 web handler for WSGraph | |
| 5 """ | |
| 6 | |
| 7 import json | |
|
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
8 import sys |
| 0 | 9 from webob import Request, Response, exc |
| 10 | |
| 5 | 11 # rank constants |
| 4 | 12 GRAPH = 0 |
| 13 NODE = 1 | |
| 14 EDGE = 2 | |
| 15 | |
|
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
16 # XXX stubbing hack |
| 7 | 17 class JSONformatter(object): |
|
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
18 |
|
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
19 def __init__(self, content_type='application/json', sort_keys=True): |
|
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
20 self.content_type = content_type |
| 7 | 21 self.sort_keys = sort_keys |
| 22 | |
| 19 | 23 def format(self, instance): |
| 24 """front-end to json.dumps""" | |
| 25 return json.dumps(instance, sort_keys=self.sort_keys) | |
| 7 | 26 |
|
20
542232f858a9
rearrange this all around for argument order
Jeff Hammel <jhammel@mozilla.com>
parents:
19
diff
changeset
|
27 def node(self, request, graph, node): |
|
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
28 return Response(content_type=self.content_type, |
|
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
29 body=self.format(graph.node(node))) |
| 7 | 30 |
|
20
542232f858a9
rearrange this all around for argument order
Jeff Hammel <jhammel@mozilla.com>
parents:
19
diff
changeset
|
31 def edge(self, request, graph, node1, node2): |
|
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
32 return Response(content_type=self.content_type, |
|
20
542232f858a9
rearrange this all around for argument order
Jeff Hammel <jhammel@mozilla.com>
parents:
19
diff
changeset
|
33 body=self.format(graph.edge(node1, node2))) |
|
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
34 |
|
20
542232f858a9
rearrange this all around for argument order
Jeff Hammel <jhammel@mozilla.com>
parents:
19
diff
changeset
|
35 def graph(self, request, graph): |
|
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
36 return Response(content_type=self.content_type, |
|
23
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
37 body = self.format(graph())) |
| 0 | 38 |
|
20
542232f858a9
rearrange this all around for argument order
Jeff Hammel <jhammel@mozilla.com>
parents:
19
diff
changeset
|
39 |
| 0 | 40 class Dispatcher(object): |
| 41 | |
| 42 def __init__(self, graph, | |
|
21
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
43 graph_formatters, |
|
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
44 node_formatters, |
|
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
45 edge_formatters, |
| 0 | 46 require_auth=False): |
| 47 self.graph = graph | |
| 48 self.require_auth = require_auth | |
| 5 | 49 |
|
13
7459702bf574
mostly spacing fix + comment
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
50 # view formatters |
| 5 | 51 self.formatters = {GRAPH: graph_formatters, |
| 52 NODE: node_formatters, | |
| 53 EDGE: edge_formatters} | |
| 16 | 54 for key, value in self.formatters.items(): |
| 5 | 55 # ensure default formatter |
| 56 assert None in value | |
| 22 | 57 # ensure all formatters are callable |
| 0 | 58 |
| 3 | 59 self.methods = dict([(i, getattr(self, i)) |
| 60 for i in dir(self) | |
| 61 if i.isupper()]) | |
| 62 | |
| 0 | 63 def __call__(self, environ, start_response): |
| 64 request = Request(environ) | |
| 3 | 65 method = self.methods.get(request.method) |
| 66 if method is None: | |
| 67 return exc.HTTPMethodNotAllowed()(environ, start_response) | |
| 68 response = method(request) | |
| 0 | 69 return response(environ, start_response) |
| 70 | |
| 71 @staticmethod | |
| 5 | 72 def path_segments(path): |
| 73 """split a path into segments""" | |
| 74 segments = path.strip('/').split('/') | |
| 75 if segments == ['']: | |
| 76 segments = [] | |
| 77 return segments | |
| 0 | 78 |
|
23
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
79 |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
80 def formatter(self, rank, request): |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
81 """returns the formatter for a request""" |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
82 formatters = self.formatters[rank] |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
83 format = request.GET.get('format') |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
84 return formatters.get(format, formatters[None]) |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
85 |
| 0 | 86 # HTTP methods |
| 87 | |
| 88 def GET(self, request): | |
|
2
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
89 """ |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
90 respond to a GET request |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
91 |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
92 Formatters are keyed off of |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
93 |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
94 formatters = {0: { |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
95 } |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
96 |
| 4 | 97 A graph formatter takes the following arguments: |
| 98 | |
| 6 | 99 def sample_graph_formatter(graph, request): |
| 100 | |
| 101 A node formatter takes the following arguments: | |
| 102 | |
| 103 def sample_node_formatter(node, graph, request): | |
| 104 | |
| 105 An edge formatter takes the following arguments: | |
| 106 | |
| 107 def sample_edge_formatter(edge, graph, request): | |
| 4 | 108 |
|
2
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
109 API: |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
110 |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
111 ?format=<format> |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
112 |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
113 """ |
| 0 | 114 |
| 7 | 115 # get resource requestor |
| 5 | 116 segments = self.path_segments(request.path_info) |
|
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
117 rank = len(segments) |
|
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
118 if rank not in (0,1,2): |
| 4 | 119 return exc.HTTPNotFound() |
| 0 | 120 |
|
17
1053290ba067
finish up this throwaway thing
Jeff Hammel <jhammel@mozilla.com>
parents:
16
diff
changeset
|
121 # is resource in the graph? |
|
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
122 if (rank == EDGE) or (rank == NODE): |
|
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
123 if tuple(segments) not in self.graph: |
| 14 | 124 return exc.HTTPNotFound() |
| 7 | 125 |
| 0 | 126 # formatter |
|
23
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
127 formatter = self.formatter(rank, request) |
|
20
542232f858a9
rearrange this all around for argument order
Jeff Hammel <jhammel@mozilla.com>
parents:
19
diff
changeset
|
128 return formatter(request, self.graph, *segments) |
| 0 | 129 |
| 130 def POST(self, request): | |
|
2
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
131 """ |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
132 respond to a POST request |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
133 |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
134 API: |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
135 |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
136 ?update : |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
137 """ |
|
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
138 |
|
23
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
139 # check authorization |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
140 if self.require_auth: |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
141 raise NotImplementedError |
|
24d57daaca21
well, now the request dispatches
Jeff Hammel <jhammel@mozilla.com>
parents:
22
diff
changeset
|
142 |
| 4 | 143 return exc.HTTPSeeOther(location='/') # TODO: /path/to/self |
| 0 | 144 |
| 145 def HEAD(self, request): | |
| 146 """respond to a HEAD request""" | |
| 147 raise NotImplementedError | |
| 148 | |
| 3 | 149 def OPTIONS(self, request): |
| 4 | 150 return Response() # TODO: Allow=', '.join(self.methods); Content-Length=0 |
| 3 | 151 |
| 0 | 152 |
|
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
153 def main(args=sys.argv[1:]): |
|
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
154 """example web server""" |
| 3 | 155 |
| 0 | 156 # imports |
| 157 from wsgiref import simple_server | |
| 3 | 158 from model import MemoryCache |
| 159 from optparse import OptionParser | |
| 0 | 160 |
| 3 | 161 # parse command line options |
| 162 parser = OptionParser() | |
| 163 parser.add_option('-p', '--port', type='int', default=8080, | |
| 164 help="port to serve on") | |
| 165 options, args = parser.parse_args() | |
| 166 | |
| 167 # example model | |
| 0 | 168 graph = MemoryCache() |
| 169 | |
|
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
170 # example formatter(s) |
|
21
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
171 formatter = JSONformatter(content_type='text/plain') |
|
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
172 _formatters = {} |
|
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
173 _formatters = dict([('%s_formatters' % i, {None: getattr(formatter, i)}) |
|
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
174 for i in 'graph', 'node', 'edge']) |
|
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
175 |
| 3 | 176 # WSGI app |
|
21
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
177 app = Dispatcher(graph=graph, **_formatters) |
| 3 | 178 server = simple_server.make_server(host='0.0.0.0', port=options.port, app=app) |
| 179 print 'http://localhost:%s/' % options.port | |
| 0 | 180 server.serve_forever() |
| 181 | |
|
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
182 if __name__ == '__main__': |
|
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
183 main() |
