Mercurial > hg > WSGraph
annotate wsgraph/web.py @ 18:b710a2374c8d
more stubbing, goddamn content_type
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Mon, 10 Dec 2012 17:42:23 -0800 (2012-12-11) |
parents | 1053290ba067 |
children | 8162dc8dd93a |
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 | |
23 def format(self, _object): | |
24 return json.dumps(graph.node(node), sort_keys=self.sort_keys) | |
25 | |
26 def node(self, node, graph, request): | |
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
27 return Response(content_type=self.content_type, |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
28 body=self.format(graph.node(node))) |
7 | 29 |
17
1053290ba067
finish up this throwaway thing
Jeff Hammel <jhammel@mozilla.com>
parents:
16
diff
changeset
|
30 def edge(self, node1, node2, graph, request): |
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
31 return Response(content_type=self.content_type, |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
32 body=self.format(graph.edge(node))) |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
33 |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
34 def graph(self, graph, request): |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
35 return Response(content_type=self.content_type, |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
36 body='hello? is it me you\'re looking for?') |
0 | 37 |
38 class Dispatcher(object): | |
39 | |
40 def __init__(self, graph, | |
5 | 41 graph_formatters=None, |
42 node_formatters=None, | |
43 edge_formatters=None, | |
0 | 44 require_auth=False): |
45 self.graph = graph | |
46 self.require_auth = require_auth | |
5 | 47 |
48 # use JSON formatter by default | |
49 if graph_formatters is None: | |
50 graph_formatters = {None: JSONGraphFormatter} | |
13
7459702bf574
mostly spacing fix + comment
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
51 if node_formatters is None: |
5 | 52 node_formatters = {None: JSONFormatter} |
13
7459702bf574
mostly spacing fix + comment
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
53 if edge_formatters is None: |
5 | 54 edge_formatters = {None: JSONFormatter} |
55 | |
13
7459702bf574
mostly spacing fix + comment
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
56 # view formatters |
5 | 57 self.formatters = {GRAPH: graph_formatters, |
58 NODE: node_formatters, | |
59 EDGE: edge_formatters} | |
16 | 60 for key, value in self.formatters.items(): |
5 | 61 # ensure default formatter |
62 assert None in value | |
0 | 63 |
3 | 64 self.methods = dict([(i, getattr(self, i)) |
65 for i in dir(self) | |
66 if i.isupper()]) | |
67 | |
0 | 68 def __call__(self, environ, start_response): |
69 request = Request(environ) | |
3 | 70 method = self.methods.get(request.method) |
71 if method is None: | |
72 return exc.HTTPMethodNotAllowed()(environ, start_response) | |
73 response = method(request) | |
0 | 74 return response(environ, start_response) |
75 | |
76 @staticmethod | |
5 | 77 def path_segments(path): |
78 """split a path into segments""" | |
79 segments = path.strip('/').split('/') | |
80 if segments == ['']: | |
81 segments = [] | |
82 return segments | |
0 | 83 |
84 # HTTP methods | |
85 | |
86 def GET(self, request): | |
2
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
87 """ |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
88 respond to a GET request |
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 Formatters are keyed off of |
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 = {0: { |
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 |
4 | 95 A graph formatter takes the following arguments: |
96 | |
6 | 97 def sample_graph_formatter(graph, request): |
98 | |
99 A node formatter takes the following arguments: | |
100 | |
101 def sample_node_formatter(node, graph, request): | |
102 | |
103 An edge formatter takes the following arguments: | |
104 | |
105 def sample_edge_formatter(edge, graph, request): | |
4 | 106 |
2
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
107 API: |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
108 |
7a3b21cafc00
start to sketch out REST API
Jeff Hammel <jhammel@mozilla.com>
parents:
0
diff
changeset
|
109 ?format=<format> |
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 """ |
0 | 112 |
7 | 113 # get resource requestor |
5 | 114 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
|
115 rank = len(segments) |
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
116 if rank not in (0,1,2): |
4 | 117 return exc.HTTPNotFound() |
0 | 118 |
17
1053290ba067
finish up this throwaway thing
Jeff Hammel <jhammel@mozilla.com>
parents:
16
diff
changeset
|
119 # is resource in the graph? |
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
120 if (rank == EDGE) or (rank == NODE): |
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
121 if tuple(segments) not in self.graph: |
14 | 122 return exc.HTTPNotFound() |
7 | 123 |
0 | 124 # formatter |
125 formatter = self.formatters[len(segments)] | |
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
126 return formatter(*segments, self.graph, request) |
0 | 127 return Response(content_type='text/plain', |
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
128 body=content) |
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 |
4 | 139 return exc.HTTPSeeOther(location='/') # TODO: /path/to/self |
0 | 140 |
141 def HEAD(self, request): | |
142 """respond to a HEAD request""" | |
143 raise NotImplementedError | |
144 | |
3 | 145 def OPTIONS(self, request): |
4 | 146 return Response() # TODO: Allow=', '.join(self.methods); Content-Length=0 |
3 | 147 |
0 | 148 |
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
149 def main(args=sys.argv[1:]): |
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
150 """example web server""" |
3 | 151 |
0 | 152 # imports |
153 from wsgiref import simple_server | |
3 | 154 from model import MemoryCache |
155 from optparse import OptionParser | |
0 | 156 |
3 | 157 # parse command line options |
158 parser = OptionParser() | |
159 parser.add_option('-p', '--port', type='int', default=8080, | |
160 help="port to serve on") | |
161 options, args = parser.parse_args() | |
162 | |
163 # example model | |
0 | 164 graph = MemoryCache() |
165 | |
18
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
166 # example formatter(s) |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
167 # TODO |
b710a2374c8d
more stubbing, goddamn content_type
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
168 |
3 | 169 # WSGI app |
0 | 170 app = Dispatcher(graph=graph) |
3 | 171 server = simple_server.make_server(host='0.0.0.0', port=options.port, app=app) |
172 print 'http://localhost:%s/' % options.port | |
0 | 173 server.serve_forever() |
174 | |
12
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
175 if __name__ == '__main__': |
421d5119e324
reluctantly make this a CLI entry point
Jeff Hammel <jhammel@mozilla.com>
parents:
7
diff
changeset
|
176 main() |