changeset 1:084088505eea

almost working
author Jeff Hammel <jhammel@mozilla.com>
date Tue, 28 Dec 2010 16:23:07 -0800
parents 7a60bacc6a22
children 30d03e830354
files example/example.py svgsitemap/middleware.py
diffstat 2 files changed, 98 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/example/example.py	Mon Dec 27 22:09:09 2010 -0800
+++ b/example/example.py	Tue Dec 28 16:23:07 2010 -0800
@@ -1,3 +1,4 @@
+import os
 from svgsitemap import *
 from webob import Request, Response
 
@@ -5,14 +6,18 @@
     link = '<a href="/%s">%s</a>'
     body = '<br/>'.join([link % (i,i) for i in range(30)])
     body = '<html><body>%s</body></html>' % body
-    response = Response(content_type='text/plain', body=body)
+    response = Response(content_type='text/html', body=body)
     return response(environ, start_response)
 
 def factory():
-    import pdb; pdb.set_trace()
-    app = MapserverMiddleware(example)
+    dirname = os.path.dirname(os.path.abspath(__file__))
+    inifile = os.path.join(dirname, 'example.gv.txt')
+    svgfile = os.path.join(dirname, 'example.svg')
+    app = MapserverMiddleware(example, svgfile)
+    app = SVGSiteMap(app, file=inifile, output=svgfile)
+    return app
 
 if __name__ == '__main__':
     from wsgiref import simple_server
-    server = simple_server.make_server(host=host, port=int(54321), app=factory())
+    server = simple_server.make_server(host='0.0.0.0', port=int(54321), app=factory())
     server.serve_forever() 
--- a/svgsitemap/middleware.py	Mon Dec 27 22:09:09 2010 -0800
+++ b/svgsitemap/middleware.py	Tue Dec 28 16:23:07 2010 -0800
@@ -5,77 +5,149 @@
 __all__ = ['MapserverMiddleware', 'SVGSiteMap']
 
 import os
+import urlparse
 from pygraphviz import AGraph
-from webob import Request, exc
+from webob import Request, Response, exc
 
 class MapserverMiddleware(object):
     """silly middleware to serve just the svg"""
     def __init__(self, app, svgmap, path='/map'):
-        self.app
+        self.app = app
         self.svgmap = svgmap
         self.path = path
 
     def __call__(self, environ, start_response):
         request = Request(environ)
         if request.path_info == self.path or not self.path:
+            if not os.path.exists(self.svgmap):
+                res = exc.HTTPNotFound()
+                return res(environ, start_response)
             content = file(self.svgmap).read()
-            return Response(content_type='image/svg+xml', body=content)
-        return app(environ, start_response)
+            res = Response(content_type='image/svg+xml', body=content)
+            return res(environ, start_response)
+        return self.app(environ, start_response)
     
 
 class SVGSiteMap(object):
 
     ### class level variables
-    defaults = { 'app': None,
-                 'name': 'k0s.org',
-                 'file': None,
-                 'output': None,
+    defaults = { 'name': '',
+                 'hosts': '',
+                 'external_referers': True,
+                 'maxwidth': 20
+
+                 # input/output
+                 'file': None, # .ini file
+                 'output': None, # .svg file
+
+                 # graph attributes
                  'bgcolor': 'black',
                  'fontcolor': 'white',
                  'fontname': 'Helvetica',
+                 'fontsize': '10.0',
                  'nodecolor': 'aqua',
                  'edgecolor': 'lime',
-                 'shape': 'box'
+                 'shape': 'box',
+                 'len': '1.3',
+                 'arrowsize': '0.5',
                  }
 
     def __init__(self, app, **kw):
+
+        # boilerplate
         self.app = app
         self.edges = {}
+        self.max = 0
+
+        # set attrs from defaults
         for key in self.defaults:
             setattr(self, key, kw.get(key, self.defaults[key]))
+
+        # sanity checks + data fixing
         assert self.output, "Please give an output file"
         assert self.file, "Cannot save file!"
+        if self.hosts:
+            self.hosts = self.hosts.split()
+        else:
+            self.hosts = []
+        if isinstance(self.external_referers, basestring):
+            self.external_referers = self.external_referers.lower() == 'true'
+
+        # open the graph
         if os.path.exists(self.file):
-            self.graph = AGraph(self.file, directed=True)
+            self.graph = AGraph(self.file, name=self.name, splines=False, directed=True)
             for edge in self.graph.edges():
-                self.edges[(edge[0], edge[1])] = int(edge.attr['label'])
+                count = int(edge.attr['label'])
+                self.edges[(edge[0], edge[1])] = count
+                if count > self.max:
+                    self.max = count
         else:
-            self.graph = AGraph(directed=True)
-        self.graph.graph_attr['title'] = self.name
+            self.graph = AGraph(name=self.name, splines=False, directed=True)
+
+        # make it pretty
         self.graph.graph_attr['label'] = self.name
         self.graph.graph_attr['fontname'] = self.fontname
         self.graph.graph_attr['fontcolor'] = self.fontcolor
         self.graph.graph_attr['bgcolor'] = self.bgcolor
         self.graph.node_attr['color'] = self.nodecolor
         self.graph.node_attr['fontcolor'] = self.fontcolor
-        self.graph.node_attr[
+        self.graph.node_attr['fontname'] = self.fontname
+        self.graph.node_attr['fontsize'] = self.fontsize
         self.graph.node_attr['shape'] = self.shape
+        self.graph.node_attr['width'] = '0.1'
+        self.graph.node_attr['height'] = '0.1'
         self.graph.edge_attr['color'] = self.edgecolor
         self.graph.edge_attr['fontcolor'] = self.fontcolor
+        self.graph.edge_attr['fontname'] = self.fontname
+        self.graph.edge_attr['fontsize'] = self.fontsize
+        self.graph.edge_attr['len'] = self.len
+        self.graph.edge_attr['arrowsize'] = self.arrowsize
         
-    ### methods dealing with HTTP
     def __call__(self, environ, start_response):
         request = Request(environ)
-        import pdb; pdb.set_trace()
+        if request.referer:
+
+            # parse the URLs
+            parsed_referer = urlparse.urlsplit(request.referer)
+            parsed_referee = urlparse.urlsplit(request.url)
+            islocal = False
+
+            # see if its local or not
+            localhosts = self.hosts[:]
+            if parsed_referee.hostname not in localhosts:
+                localhosts.append(parsed_referee.hostname)
+            for host in localhosts:
+                if parsed_referer.hostname == host or parsed_referer.hostname.endswith('.' + host):
+                    islocal = True
+                break
+
+            # make the connection
+            if islocal:
+                self.add(parsed_referer.path, parsed_referee.path)
+            else:
+                if self.external_referers:
+                    self.add(request.referer, parsed_referee.path)
+                    
         return self.app(environ, start_response)
 
     def add(self, from_url, to_url):
+        """add a conncection in the graph"""
+
+        if from_url == to_url:
+            return # don't do self-references
+        
         if (from_url, to_url) in self.edges:
             count = self.edges[(from_url, to_url)]
             count += 1
+            if count > self.max:
+                self.max = count
             self.edges[(from_url, to_url)] = count
             edge = self.graph.get_edge(from_url, to_url)
             edge.attr['label'] =  str(count)
+            width = self.maxwidth * (count / self.max)
+            if not width:
+                width = 1
+            edge.attr['style'] = 'setlinewidth(%d)' % width
         else:
             self.edges[(from_url, to_url)] = 1
             self.graph.add_edge(from_url, to_url, label='1')
@@ -88,4 +160,4 @@
         if self.file:
             self.graph.write(self.file)
         if self.output:
-            self.graph.draw(self.output, prog='dot')
+            self.graph.draw(self.output, prog='neato')