Mercurial > hg > WSGraph
annotate wsgraph/web.py @ 22:a401bf63c938
note to self
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Mon, 10 Dec 2012 17:51:50 -0800 |
parents | f56d27f03e4a |
children | 24d57daaca21 |
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, |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
37 body='hello? is it me you\'re looking for?') |
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 |
79 # HTTP methods | |
80 | |
81 def GET(self, request): | |
2
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
82 """ |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
83 respond to a GET request |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
84 |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
85 Formatters are keyed off of |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
86 |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
87 formatters = {0: { |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
88 } |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
89 |
4 | 90 A graph formatter takes the following arguments: |
91 | |
6 | 92 def sample_graph_formatter(graph, request): |
93 | |
94 A node formatter takes the following arguments: | |
95 | |
96 def sample_node_formatter(node, graph, request): | |
97 | |
98 An edge formatter takes the following arguments: | |
99 | |
100 def sample_edge_formatter(edge, graph, request): | |
4 | 101 |
2
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
102 API: |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
103 |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
104 ?format=<format> |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
105 |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
106 """ |
0 | 107 |
7 | 108 # get resource requestor |
5 | 109 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
|
110 rank = len(segments) |
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
111 if rank not in (0,1,2): |
4 | 112 return exc.HTTPNotFound() |
0 | 113 |
17
1053290ba067
finish up this throwaway thing
Jeff Hammel <jhammel@mozilla.com>
parents:
16
diff
changeset
|
114 # is resource in the graph? |
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
115 if (rank == EDGE) or (rank == NODE): |
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
116 if tuple(segments) not in self.graph: |
14 | 117 return exc.HTTPNotFound() |
7 | 118 |
0 | 119 # formatter |
120 formatter = self.formatters[len(segments)] | |
20
542232f858a9
rearrange this all around for argument order
Jeff Hammel <jhammel@mozilla.com>
parents:
19
diff
changeset
|
121 return formatter(request, self.graph, *segments) |
0 | 122 return Response(content_type='text/plain', |
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
123 body=content) |
0 | 124 |
125 def POST(self, request): | |
2
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
126 """ |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
127 respond to a POST request |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
128 |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
129 API: |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
130 |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
131 ?update : |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
132 """ |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
133 |
4 | 134 return exc.HTTPSeeOther(location='/') # TODO: /path/to/self |
0 | 135 |
136 def HEAD(self, request): | |
137 """respond to a HEAD request""" | |
138 raise NotImplementedError | |
139 | |
3 | 140 def OPTIONS(self, request): |
4 | 141 return Response() # TODO: Allow=', '.join(self.methods); Content-Length=0 |
3 | 142 |
0 | 143 |
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
144 def main(args=sys.argv[1:]): |
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
145 """example web server""" |
3 | 146 |
0 | 147 # imports |
148 from wsgiref import simple_server | |
3 | 149 from model import MemoryCache |
150 from optparse import OptionParser | |
0 | 151 |
3 | 152 # parse command line options |
153 parser = OptionParser() | |
154 parser.add_option('-p', '--port', type='int', default=8080, | |
155 help="port to serve on") | |
156 options, args = parser.parse_args() | |
157 | |
158 # example model | |
0 | 159 graph = MemoryCache() |
160 | |
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
161 # 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
|
162 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
|
163 _formatters = {} |
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
164 _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
|
165 for i in 'graph', 'node', 'edge']) |
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
166 |
3 | 167 # WSGI app |
21
f56d27f03e4a
pretend we are slick but we can be so much slicker
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
168 app = Dispatcher(graph=graph, **_formatters) |
3 | 169 server = simple_server.make_server(host='0.0.0.0', port=options.port, app=app) |
170 print 'http://localhost:%s/' % options.port | |
0 | 171 server.serve_forever() |
172 | |
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
173 if __name__ == '__main__': |
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
174 main() |