0
|
1 """
|
|
2 request dispatcher
|
|
3 """
|
|
4
|
|
5 __all__ = ['MapserverMiddleware', 'SVGSiteMap']
|
|
6
|
|
7 import os
|
1
|
8 import urlparse
|
0
|
9 from pygraphviz import AGraph
|
1
|
10 from webob import Request, Response, exc
|
0
|
11
|
|
12 class MapserverMiddleware(object):
|
|
13 """silly middleware to serve just the svg"""
|
|
14 def __init__(self, app, svgmap, path='/map'):
|
1
|
15 self.app = app
|
0
|
16 self.svgmap = svgmap
|
|
17 self.path = path
|
|
18
|
|
19 def __call__(self, environ, start_response):
|
|
20 request = Request(environ)
|
|
21 if request.path_info == self.path or not self.path:
|
1
|
22 if not os.path.exists(self.svgmap):
|
|
23 res = exc.HTTPNotFound()
|
|
24 return res(environ, start_response)
|
0
|
25 content = file(self.svgmap).read()
|
1
|
26 res = Response(content_type='image/svg+xml', body=content)
|
|
27 return res(environ, start_response)
|
|
28 return self.app(environ, start_response)
|
0
|
29
|
|
30
|
|
31 class SVGSiteMap(object):
|
|
32
|
|
33 ### class level variables
|
1
|
34 defaults = { 'name': '',
|
|
35 'hosts': '',
|
|
36 'external_referers': True,
|
2
|
37 'maxwidth': 5,
|
|
38 'minwidth': '0.01',
|
1
|
39
|
|
40 # input/output
|
|
41 'file': None, # .ini file
|
|
42 'output': None, # .svg file
|
|
43
|
|
44 # graph attributes
|
0
|
45 'bgcolor': 'black',
|
|
46 'fontcolor': 'white',
|
|
47 'fontname': 'Helvetica',
|
1
|
48 'fontsize': '10.0',
|
0
|
49 'nodecolor': 'aqua',
|
|
50 'edgecolor': 'lime',
|
1
|
51 'shape': 'box',
|
|
52 'len': '1.3',
|
|
53 'arrowsize': '0.5',
|
0
|
54 }
|
|
55
|
|
56 def __init__(self, app, **kw):
|
1
|
57
|
|
58 # boilerplate
|
0
|
59 self.app = app
|
|
60 self.edges = {}
|
1
|
61 self.max = 0
|
|
62
|
|
63 # set attrs from defaults
|
0
|
64 for key in self.defaults:
|
|
65 setattr(self, key, kw.get(key, self.defaults[key]))
|
1
|
66
|
|
67 # sanity checks + data fixing
|
0
|
68 assert self.output, "Please give an output file"
|
|
69 assert self.file, "Cannot save file!"
|
2
|
70 self.maxwidth = float(self.maxwidth)
|
1
|
71 if self.hosts:
|
|
72 self.hosts = self.hosts.split()
|
|
73 else:
|
|
74 self.hosts = []
|
|
75 if isinstance(self.external_referers, basestring):
|
|
76 self.external_referers = self.external_referers.lower() == 'true'
|
|
77
|
|
78 # open the graph
|
0
|
79 if os.path.exists(self.file):
|
1
|
80 self.graph = AGraph(self.file, name=self.name, splines=False, directed=True)
|
0
|
81 for edge in self.graph.edges():
|
1
|
82 count = int(edge.attr['label'])
|
|
83 self.edges[(edge[0], edge[1])] = count
|
|
84 if count > self.max:
|
|
85 self.max = count
|
0
|
86 else:
|
1
|
87 self.graph = AGraph(name=self.name, splines=False, directed=True)
|
|
88
|
|
89 # make it pretty
|
2
|
90 self.graph.graph_attr['name'] = self.name
|
0
|
91 self.graph.graph_attr['label'] = self.name
|
|
92 self.graph.graph_attr['fontname'] = self.fontname
|
|
93 self.graph.graph_attr['fontcolor'] = self.fontcolor
|
|
94 self.graph.graph_attr['bgcolor'] = self.bgcolor
|
|
95 self.graph.node_attr['color'] = self.nodecolor
|
|
96 self.graph.node_attr['fontcolor'] = self.fontcolor
|
1
|
97 self.graph.node_attr['fontname'] = self.fontname
|
|
98 self.graph.node_attr['fontsize'] = self.fontsize
|
0
|
99 self.graph.node_attr['shape'] = self.shape
|
1
|
100 self.graph.node_attr['width'] = '0.1'
|
|
101 self.graph.node_attr['height'] = '0.1'
|
0
|
102 self.graph.edge_attr['color'] = self.edgecolor
|
|
103 self.graph.edge_attr['fontcolor'] = self.fontcolor
|
1
|
104 self.graph.edge_attr['fontname'] = self.fontname
|
|
105 self.graph.edge_attr['fontsize'] = self.fontsize
|
|
106 self.graph.edge_attr['len'] = self.len
|
|
107 self.graph.edge_attr['arrowsize'] = self.arrowsize
|
0
|
108
|
|
109 def __call__(self, environ, start_response):
|
|
110 request = Request(environ)
|
1
|
111 if request.referer:
|
|
112
|
|
113 # parse the URLs
|
|
114 parsed_referer = urlparse.urlsplit(request.referer)
|
|
115 parsed_referee = urlparse.urlsplit(request.url)
|
|
116 islocal = False
|
|
117
|
|
118 # see if its local or not
|
|
119 localhosts = self.hosts[:]
|
|
120 if parsed_referee.hostname not in localhosts:
|
|
121 localhosts.append(parsed_referee.hostname)
|
|
122 for host in localhosts:
|
|
123 if parsed_referer.hostname == host or parsed_referer.hostname.endswith('.' + host):
|
|
124 islocal = True
|
|
125 break
|
|
126
|
|
127 # make the connection
|
|
128 if islocal:
|
|
129 self.add(parsed_referer.path, parsed_referee.path)
|
|
130 else:
|
|
131 if self.external_referers:
|
|
132 self.add(request.referer, parsed_referee.path)
|
|
133
|
0
|
134 return self.app(environ, start_response)
|
|
135
|
|
136 def add(self, from_url, to_url):
|
1
|
137 """add a conncection in the graph"""
|
|
138
|
|
139 if from_url == to_url:
|
|
140 return # don't do self-references
|
|
141
|
0
|
142 if (from_url, to_url) in self.edges:
|
|
143 count = self.edges[(from_url, to_url)]
|
|
144 count += 1
|
1
|
145 if count > self.max:
|
|
146 self.max = count
|
0
|
147 self.edges[(from_url, to_url)] = count
|
|
148 edge = self.graph.get_edge(from_url, to_url)
|
|
149 edge.attr['label'] = str(count)
|
|
150 else:
|
|
151 self.edges[(from_url, to_url)] = 1
|
|
152 self.graph.add_edge(from_url, to_url, label='1')
|
|
153
|
2
|
154 for edge in self.graph.edges():
|
|
155 count = self.edges[(edge[0], edge[1])]
|
|
156 width = self.maxwidth * count / self.max
|
|
157 if not width:
|
|
158 width = self.minwidth
|
|
159 edge.attr['style'] = 'setlinewidth(%s)' % width
|
|
160
|
0
|
161 for url in from_url, to_url:
|
|
162 node = self.graph.get_node(url)
|
|
163 node.attr['label'] = url
|
|
164 node.attr['href'] = url
|
|
165
|
|
166 if self.file:
|
|
167 self.graph.write(self.file)
|
|
168 if self.output:
|
1
|
169 self.graph.draw(self.output, prog='neato')
|