Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

import webmachine ui for wmtrace .

  • Loading branch information...
commit a041fc9d28594404969256e569bf534436b56b49 1 parent d997fc6
benoitc authored
View
1  MANIFEST.in
@@ -1,4 +1,5 @@
include LICENSE
include NOTICE
include README.rst
+recursive-include webmachine/media *
recursive-include webmachine/templates *
View
54 setup.py
@@ -4,6 +4,7 @@
# This file is part of dj-webmachine released under the Apache 2 license.
# See the NOTICE for more information.
+from distutils.command.install_data import install_data
import os
import sys
@@ -14,45 +15,25 @@
from webmachine import __version__
-popen3 = None
-try:#python 2.6, use subprocess
- import subprocess
- subprocess.Popen # trigger ImportError early
- closefds = os.name == 'posix'
-
- def popen3(cmd, mode='t', bufsize=0):
- p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
- stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- close_fds=closefds)
- p.wait()
- return (p.stdin, p.stdout, p.stderr)
-except ImportError:
- subprocess = None
- try:
- popen3 = os.popen3
- except ImportError:
- popen3 = None
-
-DEVELOP = "develop" in sys.argv
-
-version = __version__
-if DEVELOP and popen3 is not None:
- minor_tag = ""
- try:
- stdin, stdout, stderr = popen3("git rev-parse --short HEAD --")
- error = stderr.read()
- if not error:
- git_tag = stdout.read()[:-1]
- minor_tag = ".%s-git" % git_tag
- except OSError:
- pass
- version = "%s%s" % (version, minor_tag)
-
+data_files = []
+for root in ('webmachine/media', 'webmachine/templates'):
+ for dir, dirs, files in os.walk(root):
+ dirs[:] = [x for x in dirs if not x.startswith('.')]
+ files = [x for x in files if not x.startswith('.')]
+ data_files.append((os.path.join('webmachine', dir),
+ [os.path.join(dir, file_) for file_ in files]))
+
+class install_package_data(install_data):
+ def finalize_options(self):
+ self.set_undefined_options('install',
+ ('install_lib', 'install_dir'))
+ install_data.finalize_options(self)
+cmdclass = {'install_data': install_package_data }
setup(
name = 'dj-webmachine',
- version = version,
+ version = __version__,
description = 'Minimal Django Resource framework.',
long_description = file(
os.path.join(
@@ -80,7 +61,8 @@ def popen3(cmd, mode='t', bufsize=0):
zip_safe = False,
packages = find_packages(),
include_package_data = True,
-
+ data_files = data_files,
+ cmdclass=cmdclass,
install_requires = [
'setuptools',
'Django',
View
2  webmachine/__init__.py
@@ -4,7 +4,7 @@
# See the NOTICE for more information.
-version_info = (0, 2, 1)
+version_info = (0, 3, 0)
__version__ = ".".join(map(str, version_info))
View
BIN  webmachine/media/http-headers-status-v3.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  webmachine/media/map.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
107 webmachine/media/wmtrace.css
@@ -0,0 +1,107 @@
+body {
+ margin:0px;
+ padding:0px;
+}
+
+canvas#v3map {
+ margin-top:2em;
+ z-index: 1;
+}
+
+div#sizetest {
+ width:100%;
+}
+
+div#zoompanel {
+ height:2em;
+ position:fixed;
+ z-index:10;
+}
+
+div#preview {
+ position:absolute;
+ display:none;
+ background:#dddddd;
+ border:1px solid #999999;
+}
+
+div#preview ul {
+ padding: 0px 0px 0px 0.5em;
+ margin: 0px;
+ list-style: none;
+}
+
+div#infopanel {
+ z-index:20;
+ background:#dddddd;
+ position:fixed;
+ top:0px;
+ right:0px;
+ bottom:0px;
+ left:75%;
+ min-width:30em;
+ padding:5px;
+}
+
+div#infocontrols {
+ position:absolute;
+ top:0px;
+ bottom:0px;
+ left:-5px;
+ width:5px;
+ background:#999999;
+ cursor:ew-resize;
+}
+
+div#infocontrols div {
+ position:absolute;
+ left:-15px;
+ width:20px;
+ height:49px;
+ background:#999999;
+ cursor:pointer;
+}
+
+div#infocontrols div.selectedtab {
+ background:#dddddd;
+ border-top: 1px solid #999999;
+ border-left: 1px solid #999999;
+ border-bottom: 1px solid #999999;
+}
+
+div#requesttab {
+ top:2px;
+}
+
+div#responsetab {
+ top:54px;
+}
+
+div#decisiontab {
+ top:106px;
+}
+
+div#requestdetail, div#responsedetail, div#decisiondetail {
+ height:100%;
+}
+
+div#responsedetail, div#decisiondetail {
+ display:none;
+}
+
+div#infopanel ul {
+ list-style:none;
+ padding-left:0px;
+ height:5em;
+ overflow-y:scroll;
+}
+
+pre {
+ height:40%;
+ overflow:scroll;
+}
+
+div#responsebody, div#requestbody {
+ height:70%;
+ overflow-y:scroll;
+}
View
713 webmachine/media/wmtrace.js
@@ -0,0 +1,713 @@
+var HIGHLIGHT = '#cc00cc';
+var REGULAR = '#666666';
+
+var cols = {
+ 'a':173,
+ 'b':325,
+ 'c':589,
+ 'd':797,
+ 'e':1005,
+ 'f':1195,
+ 'g':1402,
+ 'gg':1515,
+ 'h':1572,
+ 'i':1799,
+ 'j':1893,
+ 'k':1988,
+ 'l':2157,
+ 'll':2346,
+ 'm':2403,
+ 'mm':2535,
+ 'n':2554,
+ 'o':2649,
+ 'oo':2781,
+ 'ooo':2801,
+ 'p':2894,
+ 'q':3007
+};
+
+var rows = {
+ '1':221,
+ '2':298,
+ '3':373,
+ '4':448,
+ '5':524,
+ '6':599,
+ '7':675,
+ '8':751,
+ '9':826,
+ '10':902,
+ '11':977,
+ '12':1053,
+ '13':1129,
+ '14':1204,
+ '15':1280,
+ '16':1355,
+ '17':1431,
+ '18':1506,
+ '19':1583,
+ '20':1658,
+ '21':1734,
+ '22':1809,
+ '23':1885,
+ '24':1961,
+ '25':2036,
+ '26':2112
+};
+
+var edges = {
+ 'b14b13':['b14','b13'],
+
+ 'b13b12':['b13','b12'],
+ 'b13503':['b13','503'],
+
+ 'b12b11':['b12','b11'],
+ 'b12501':['b12','501'],
+
+ 'b11b10':['b11','b10'],
+ 'b11414':['b11','414'],
+
+ 'b10b9':['b10','b9'],
+ 'b10405':['b10','405'],
+
+ 'b9b8':['b9','b8'],
+ 'b9400':['b9','400'],
+
+ 'b8b7':['b8','b7'],
+ 'b8401':['b8','401'],
+
+ 'b7b6':['b7','b6'],
+ 'b7403':['b7','403'],
+
+ 'b6b5':['b6','b5'],
+ 'b6501':['b6','501a'],
+
+ 'b5b4':['b5','b4'],
+ 'b5415':['b5','415'],
+
+ 'b4b3':['b4','b3'],
+ 'b4413':['b4','b4'],
+
+ 'b3c3':['b3','c3'],
+ 'b3200':['b3','200'],
+
+ 'c3c4':['c3','c4'],
+ 'c3d4':['c3','d3','d4'],
+
+ 'c4d4':['c4','d4'],
+ 'c4406':['c4','406'],
+
+ 'd4d5':['d4','d5'],
+ 'd4e5':['d4','e4','e5'],
+
+ 'd5e5':['d5','e5'],
+ 'd5406':['d5','d7','406'],
+
+ 'e5e6':['e5','e6'],
+ 'e5f6':['e5','f5','f6'],
+
+ 'e6f6':['e6','f6'],
+ 'e6406':['e6','e7','406'],
+
+ 'f6f7':['f6','f7'],
+ 'f6g7':['f6','g6','g7'],
+
+ 'f7g7':['f7','g7'],
+ 'f7406':['f7','406'],
+
+ 'g7g8':['g7','g8'],
+ 'g7h7':['g7','h7'],
+
+ 'g8g9':['g8','g9'],
+ 'g8h10':['g8','h8','h10'],
+
+ 'g9g11':['g9','g11'],
+ 'g9h10':['g9','gg9','gg10','h10'],
+
+ 'g11h10':['g11','gg11','gg10','h10'],
+ 'g11412':['g11','g18','412a'],
+
+ 'h7i7':['h7','i7'],
+ 'h7412':['h7','412'],
+
+ 'h10h11':['h10','h11'],
+ 'h10i12':['h10','i10','i12'],
+
+ 'h11h12':['h11','h12'],
+ 'h11i12':['h11','i11','i12'],
+
+ 'h12i12':['h12','i12'],
+ 'h12412':['h12','412a'],
+
+ 'i4p3':['i4','i3','p3'],
+ 'i4301':['i4','301'],
+
+ 'i7i4':['i7','i4'],
+ 'i7k7':['i7','k7'],
+
+ 'i12l13':['i12','l12','l13'],
+ 'i12i13':['i12','i13'],
+
+ 'i13k13':['i13','k13'],
+ 'i13j18':['i13','i17','j17','j18'],
+
+ 'j18412':['j18','412a'],
+ 'j18304':['j18','304'],
+
+ 'k5l5':['k5','l5'],
+ 'k5301':['k5','301'],
+
+ 'k7k5':['k7','k5'],
+ 'k7l7':['k7','l7'],
+
+ 'k13j18':['k13','k17','j17','j18'],
+ 'k13l13':['k13','l13'],
+
+ 'l5m5':['l5','m5'],
+ 'l5307':['l5','307'],
+
+ 'l7m7':['l7','m7'],
+ 'l7404':['l7','l8','404'],
+
+ 'l13l14':['l13','l14'],
+ 'l13m16':['l13','m13','m16'],
+
+ 'l14l15':['l14','l15'],
+ 'l14m16':['l14','m14','m16'],
+
+ 'l15l17':['l15','l17'],
+ 'l15m16':['l15','ll15','ll16','m16'],
+
+ 'l17m16':['l17','ll17','ll16','m16'],
+ 'l17304':['l17','304'],
+
+ 'm5n5':['m5','n5'],
+ 'm5410':['m5','m4','410'],
+
+ 'm7n11':['m7','n7','n11'],
+ 'm7404':['m7','404'],
+
+ 'm16m20':['m16','m20'],
+ 'm16n16':['m16','n16'],
+
+ 'm20o20':['m20','o20'],
+ 'm20202':['m20','202'],
+
+ 'n5n11':['n5','n11'],
+ 'n5410':['n5','410'],
+
+ 'n11p11':['n11','p11'],
+ 'n11303':['n11','303'],
+
+ 'n16n11':['n16','n11'],
+ 'n16o16':['n16','o16'],
+
+ 'o14p11':['o14','o11','p11'],
+ 'o14409':['o14','409a'],
+
+ 'o16o14':['o16','o14'],
+ 'o16o18':['o16','o18'],
+
+ 'o18200':['o18','200a'],
+ 'o18300':['o18','oo18','300'],
+
+ 'o20o18':['o20','o18'],
+ 'o20204':['o20','204'],
+
+ 'p3p11':['p3','p11'],
+ 'p3409':['p3','409'],
+
+ 'p11o20':['p11','p20','o20'],
+ 'p11201':['p11','q11','201']
+};
+
+var ends = {
+ '200': {col:'a', row:'3', width:190},
+ '200a': {col:'mm', row:'18', width:116},
+ '201': {col:'q', row:'12', width:154},
+ '202': {col:'m', row:'21', width:116},
+ '204': {col:'o', row:'21', width:152},
+
+ '300': {col:'oo', row:'19', width:152},
+ '301': {col:'k', row:'4', width:154},
+ '303': {col:'m', row:'11', width:116},
+ '304': {col:'l', row:'18', width:116},
+ '307': {col:'l', row:'4', width:154},
+
+ '400': {col:'a', row:'9', width:190},
+ '401': {col:'a', row:'8', width:190},
+ '403': {col:'a', row:'7', width:190},
+ '404': {col:'m', row:'8', width:116},
+ '405': {col:'a', row:'10', width:190},
+ '406': {col:'c', row:'7', width:152},
+ '409': {col:'p', row:'2', width:116},
+ '409a': {col:'oo', row:'14', width:116},
+ '410': {col:'n', row:'4', width:116},
+ '412': {col:'h', row:'6', width:152},
+ '412a': {col:'h', row:'18', width:152},
+ '413': {col:'a', row:'4', width:190},
+ '414': {col:'a', row:'11', width:190},
+ '415': {col:'a', row:'5', width:190},
+
+ '501a': {col:'a', row:'6', width:190},
+ '501': {col:'a', row:'12', width:190},
+ '503': {col:'a', row:'13', width:190}
+};
+
+var canvas;
+
+function decorateTrace() {
+ trace[0].x = cols[trace[0].d[0]];
+ trace[0].y = rows[trace[0].d.slice(1)];
+ trace[0].previewCalls = previewCalls(trace[0]);
+
+ for (var i = 1; i < trace.length; i++) {
+ trace[i].x = cols[trace[i].d[0]];
+ trace[i].y = rows[trace[i].d.slice(1)];
+ trace[i].previewCalls = previewCalls(trace[i]);
+
+ var path = edges[trace[i-1].d+trace[i].d];
+ if (path) {
+ trace[i].path = [path.length-1];
+ for (var p = 1; p < path.length; p++) {
+ trace[i].path[p-1] = getSeg(path[p-1], path[p], p == path.length-1);
+ }
+ } else {
+ trace[i].path = [];
+ }
+ }
+
+ var path = edges[trace[i-1].d+response.code];
+ if (path) {
+ var end = ends[path[path.length-1]];
+ response.x = cols[end.col];
+ response.y = rows[end.row];
+ response.width = end.width;
+ response.type = 'normal';
+
+ response.path = [path.length-1];
+ for (var p = 1; p < path.length; p++) {
+ response.path[p-1] = getSeg(path[p-1], path[p], p == path.length-1);
+ }
+ } else {
+ var ld = trace[trace.length-1];
+ response.x = ld.x+50;
+ response.y = ld.y-50;
+ response.width = 38;
+ response.type = 'other';
+
+ response.path = [
+ {x1: ld.x+10, y1: ld.y-10,
+ x2: ld.x+36, y2: ld.y-36}
+ ];
+ }
+};
+
+function previewCalls(dec) {
+ var prev = '';
+ for (var i = 0; i < dec.calls.length; i++) {
+ if (dec.calls[i].output != "wmtrace_not_exported")
+ prev += '<li>'+dec.calls[i].module+':'+dec.calls[i]['function']+'</li>';
+ }
+ return prev;
+};
+
+function drawTrace() {
+ drawDecision(trace[0]);
+ for (var i = 1; i < trace.length; i++) {
+ drawPath(trace[i].path);
+ drawDecision(trace[i]);
+ }
+
+ drawPath(response.path);
+ drawResponse();
+};
+
+function drawResponse() {
+ if (response.type == 'normal') {
+ var context = canvas.getContext('2d');
+ context.strokeStyle=HIGHLIGHT;
+ context.lineWidth=4;
+
+ context.beginPath();
+ context.rect(response.x-(response.width/2),
+ response.y-19,
+ response.width,
+ 38);
+ context.stroke();
+ } else {
+ var context = canvas.getContext('2d');
+ context.strokeStyle='#ff0000';
+ context.lineWidth=4;
+
+ context.beginPath();
+ context.arc(response.x, response.y, 19,
+ 0, 2*3.14159, false);
+ context.stroke();
+
+ }
+};
+
+function drawDecision(dec) {
+ var context = canvas.getContext('2d');
+
+ if (dec.previewCalls == '')
+ context.strokeStyle=REGULAR;
+ else
+ context.strokeStyle=HIGHLIGHT;
+ context.lineWidth=4;
+
+ context.beginPath();
+ context.moveTo(dec.x, dec.y-19);
+ context.lineTo(dec.x+19, dec.y);
+ context.lineTo(dec.x, dec.y+19);
+ context.lineTo(dec.x-19, dec.y);
+ context.closePath();
+ context.stroke();
+};
+
+function drawPath(path) {
+ var context = canvas.getContext('2d');
+ context.strokeStyle=REGULAR;
+ context.lineWidth=4;
+
+ context.beginPath();
+ context.moveTo(path[0].x1, path[0].y1);
+ for (var p = 0; p < path.length; p++) {
+ context.lineTo(path[p].x2, path[p].y2);
+ }
+ context.stroke();
+};
+
+function getSeg(p1, p2, last) {
+ var seg = {
+ x1:cols[p1[0]],
+ y1:rows[p1.slice(1)]
+ };
+ if (ends[p2]) {
+ seg.x2 = cols[ends[p2].col];
+ seg.y2 = rows[ends[p2].row];
+ } else {
+ seg.x2 = cols[p2[0]];
+ seg.y2 = rows[p2.slice(1)];
+ }
+
+ if (seg.x1 == seg.x2) {
+ if (seg.y1 < seg.y2) {
+ seg.y1 = seg.y1+19;
+ if (last) seg.y2 = seg.y2-19;
+ } else {
+ seg.y1 = seg.y1-19;
+ if (last) seg.y2 = seg.y2+19;
+ }
+ } else {
+ //assume seg.y1 == seg.y2
+ if (seg.x1 < seg.x2) {
+ seg.x1 = seg.x1+19;
+ if (last) seg.x2 = seg.x2-(ends[p2] ? (ends[p2].width/2) : 19);
+ } else {
+ seg.x1 = seg.x1-19;
+ if (last) seg.x2 = seg.x2+(ends[p2] ? (ends[p2].width/2) : 19);
+ }
+ }
+ return seg;
+};
+
+function traceDecision(name) {
+ for (var i = trace.length-1; i >= 0; i--)
+ if (trace[i].d == name) return trace[i];
+};
+
+var detailPanels = {};
+function initDetailPanels() {
+ var windowWidth = document.getElementById('sizetest').clientWidth;
+ var infoPanel = document.getElementById('infopanel');
+ var panelWidth = windowWidth-infoPanel.offsetLeft;
+
+ var panels = {
+ 'request': document.getElementById('requestdetail'),
+ 'response': document.getElementById('responsedetail'),
+ 'decision': document.getElementById('decisiondetail')
+ };
+
+ var tabs = {
+ 'request': document.getElementById('requesttab'),
+ 'response': document.getElementById('responsetab'),
+ 'decision': document.getElementById('decisiontab')
+ };
+
+ var decisionId = document.getElementById('decisionid');
+ var decisionCalls = document.getElementById('decisioncalls');
+ var callInput = document.getElementById('callinput');
+ var callOutput = document.getElementById('calloutput');
+
+ var lastUsedPanelWidth = windowWidth-infoPanel.offsetLeft;
+
+ var setPanelWidth = function(width) {
+ infoPanel.style.left = (windowWidth-width)+'px';
+ canvas.style.marginRight = (width+20)+'px';
+ panelWidth = width;
+ };
+ setPanelWidth(panelWidth);
+
+ var ensureVisible = function() {
+ if (windowWidth-infoPanel.offsetLeft < 10)
+ setPanelWidth(lastUsedPanelWidth);
+ };
+
+ var decChoices = '';
+ for (var i = 0; i < trace.length; i++) {
+ decChoices += '<option value="'+trace[i].d+'">'+trace[i].d+'</option>';
+ }
+ decisionId.innerHTML = decChoices;
+ decisionId.selectedIndex = -1;
+
+ decisionId.onchange = function() {
+ detailPanels.setDecision(traceDecision(decisionId.value));
+ }
+
+ detailPanels.setDecision = function(dec) {
+ decisionId.value = dec.d;
+
+ var calls = [];
+ for (var i = 0; i < dec.calls.length; i++) {
+ calls.push('<option value="'+dec.d+'-'+i+'">');
+ calls.push(dec.calls[i].module+':'+dec.calls[i]['function']);
+ calls.push('</option>');
+ }
+ decisionCalls.innerHTML = calls.join('');
+ decisionCalls.selectedIndex = 0;
+
+ decisionCalls.onchange();
+ };
+
+ detailPanels.show = function(name) {
+ for (p in panels) {
+ if (p == name) {
+ panels[p].style.display = 'block';
+ tabs[p].className = 'selectedtab';
+ }
+ else {
+ panels[p].style.display = 'none';
+ tabs[p].className = '';
+ }
+ }
+ ensureVisible();
+ };
+
+ detailPanels.hide = function() {
+ setPanelWidth(0);
+ }
+
+ decisionCalls.onchange = function() {
+ var val = decisionCalls.value;
+ if (val) {
+ var dec = traceDecision(val.substring(0, val.indexOf('-')));
+ var call = dec.calls[parseInt(val.substring(val.indexOf('-')+1, val.length))];
+
+ if (call.output != "wmtrace_not_exported") {
+ callInput.style.color='#000000';
+ callInput.innerHTML = call.input;
+ if (call.output != null) {
+ callOutput.style.color = '#000000';
+ callOutput.innerHTML = call.output;
+ } else {
+ callOutput.style.color = '#ff0000';
+ callOutput.textContent = 'Error: '+call.module+':'+call['function']+' never returned';
+ }
+ } else {
+ callInput.style.color='#999999';
+ callInput.textContent = call.module+':'+call['function']+' was not exported';
+ callOutput.textContent = '';
+ }
+ } else {
+ callInput.textContent = '';
+ callOutput.textContent = '';
+ }
+ };
+
+ var headersList = function(headers) {
+ var h = '';
+ for (n in headers) h += '<li>'+n+': '+headers[n];
+ return h;
+ };
+
+ document.getElementById('requestmethod').innerHTML = request.method;
+ document.getElementById('requestpath').innerHTML = request.path;
+ document.getElementById('requestheaders').innerHTML = headersList(request.headers);
+ document.getElementById('requestbody').innerHTML = request.body;
+
+ document.getElementById('responsecode').innerHTML = response.code;
+ document.getElementById('responseheaders').innerHTML = headersList(response.headers);
+ document.getElementById('responsebody').innerHTML = response.body;
+
+
+ var infoControls = document.getElementById('infocontrols');
+ var md = false;
+ var dragged = false;
+ var msoff = 0;
+ infoControls.onmousedown = function(ev) {
+ md = true;
+ dragged = false;
+ msoff = ev.clientX-infoPanel.offsetLeft;
+ };
+
+ infoControls.onclick = function(ev) {
+ if (dragged) {
+ lastUsedPanelWidth = panelWidth;
+ }
+ else if (panelWidth < 10) {
+ switch(ev.target.id) {
+ case 'requesttab': detailPanels.show('request'); break;
+ case 'responsetab': detailPanels.show('response'); break;
+ case 'decisiontab': detailPanels.show('decision'); break;
+ default: ensureVisible();
+ }
+ } else {
+ var name = 'none';
+ switch(ev.target.id) {
+ case 'requesttab': name = 'request'; break;
+ case 'responsetab': name = 'response'; break;
+ case 'decisiontab': name = 'decision'; break;
+ }
+
+ if (panels[name] && panels[name].style.display != 'block')
+ detailPanels.show(name);
+ else
+ detailPanels.hide();
+ }
+
+ return false;
+ };
+
+ document.onmousemove = function(ev) {
+ if (md) {
+ dragged = true;
+ panelWidth = windowWidth-(ev.clientX-msoff);
+ if (panelWidth < 0) {
+ panelWidth = 0;
+ infoPanel.style.left = windowWidth+"px";
+ }
+ else if (panelWidth > windowWidth-21) {
+ panelWidth = windowWidth-21;
+ infoPanel.style.left = '21px';
+ }
+ else
+ infoPanel.style.left = (ev.clientX-msoff)+"px";
+
+ canvas.style.marginRight = panelWidth+20+"px";
+ return false;
+ }
+ };
+
+ document.onmouseup = function() { md = false; };
+
+ window.onresize = function() {
+ windowWidth = document.getElementById('sizetest').clientWidth;
+ infoPanel.style.left = windowWidth-panelWidth+'px';
+ };
+};
+
+window.onload = function() {
+ canvas = document.getElementById('v3map');
+
+ initDetailPanels();
+
+ var scale = 0.25;
+ var coy = canvas.offsetTop;
+ function findDecision(ev) {
+ var x = (ev.clientX+window.pageXOffset)/scale;
+ var y = (ev.clientY+window.pageYOffset-coy)/scale;
+
+ for (var i = trace.length-1; i >= 0; i--) {
+ if (x >= trace[i].x-19 && x <= trace[i].x+19 &&
+ y >= trace[i].y-19 && y <= trace[i].y+19)
+ return trace[i];
+ }
+ };
+
+ var preview = document.getElementById('preview');
+ var previewId = document.getElementById('previewid');
+ var previewCalls = document.getElementById('previewcalls');
+ function previewDecision(dec) {
+ preview.style.left = (dec.x*scale)+'px';
+ preview.style.top = (dec.y*scale+coy+15)+'px';
+ preview.style.display = 'block';
+ previewId.textContent = dec.d;
+
+ previewCalls.innerHTML = dec.previewCalls;
+ };
+
+ function overResponse(ev) {
+ var x = (ev.clientX+window.pageXOffset)/scale;
+ var y = (ev.clientY+window.pageYOffset-coy)/scale;
+
+ return (x >= response.x-(response.width/2)
+ && x <= response.x+(response.width/2)
+ && y >= response.y-19 && y <= response.y+19);
+ };
+
+ decorateTrace();
+
+ var bg = new Image(3138, 2184);
+
+ function drawMap() {
+ var ctx = canvas.getContext("2d");
+
+ ctx.save();
+ ctx.scale(1/scale, 1/scale);
+ ctx.fillStyle = '#ffffff';
+ ctx.fillRect(0, 0, 3138, 2184);
+ ctx.restore();
+
+ ctx.drawImage(bg, 0, 0);
+ drawTrace();
+ };
+
+ bg.onload = function() {
+ canvas.getContext("2d").scale(scale, scale);
+ drawMap(scale);
+
+ canvas.onmousemove = function(ev) {
+ if (findDecision(ev)) {
+ canvas.style.cursor = 'pointer';
+ previewDecision(findDecision(ev));
+ }
+ else {
+ preview.style.display = 'none';
+ if (overResponse(ev))
+ canvas.style.cursor = 'pointer';
+ else
+ canvas.style.cursor = 'default';
+ }
+ };
+
+ canvas.onclick = function(ev) {
+ var dec = findDecision(ev);
+ if (dec) {
+ detailPanels.setDecision(dec);
+ detailPanels.show('decision');
+ } else if (overResponse(ev)) {
+ detailPanels.show('response');
+ }
+ };
+
+ document.getElementById('zoomin').onclick = function() {
+ scale = scale*2;
+ canvas.getContext("2d").scale(2, 2);
+ drawMap();
+ };
+
+ document.getElementById('zoomout').onclick = function() {
+ scale = scale/2;
+ canvas.getContext("2d").scale(0.5, 0.5);
+ drawMap();
+ };
+ };
+
+ bg.onerror = function() {
+ alert('Failed to load background image.');
+ };
+
+ bg.src = 'static/map.png';
+};
View
67 webmachine/resource/base.py
@@ -32,10 +32,20 @@ def f(self, req, resp):
be omitted as they have reasonable defaults.
"""
+from __future__ import with_statement
+from datetime import datetime
+import inspect
+import os
import re
import sys
+import traceback
import types
+try:
+ import json
+except ImportError:
+ import django.utils.simplejson as json
+
from django.http import HttpResponse
from django.utils.translation import activate, deactivate_all, get_language, \
string_concat
@@ -45,14 +55,65 @@ def f(self, req, resp):
from webmachine.http.wrappers import WMRequest, WMResponse
from webmachine.http.decisions import b13, TRANSITIONS, first_match
from webmachine.util import coerce_put_post, serialize_list
-from webmachine.wmtrace import update_trace, update_ex_trace, \
-write_trace
+
CHARSET_RE = re.compile(r';\s*charset=([^;]*)', re.I)
get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip()
DEFAULT_NAMES = ('verbose_name', 'app_label', 'resource_path')
+def update_trace(resource, state, req, resp, trace):
+ if not resource.trace:
+ # do nothing
+ return
+
+ infos = {
+ "request": {
+ "headers": req.headers.items(),
+ "get": [(k, req.GET.getlist(k)) for k in req.GET],
+ "post": [(k, req.POST.getlist(k)) for k in req.POST],
+ "cookies": [(k, req.COOKIES.get(k)) for k in req.COOKIES],
+ "url_args": req.url_args,
+ "url_kwarg": req.url_kwargs
+ },
+ "response": {
+ "code": resp.status_code,
+ "headers": resp.headerlist
+ }
+
+ }
+
+ if hasattr(req, 'session'):
+ infos['request'].update({
+ 'session': [(k, req.session.get(k)) for k in \
+ req.session.keys()]
+ })
+
+ if isinstance(state, int):
+ name = str(state)
+ else:
+ name = state.__name__
+
+ trace.append((name, infos))
+
+def update_ex_trace(trace, e):
+ trace.append(("error", traceback.format_exc()))
+
+def write_trace(res, trace):
+ if not res.trace:
+ return
+
+ if not res.trace_path:
+ trace_path = "/tmp"
+
+ now = datetime.now().replace(microsecond=0).isoformat() + 'Z'
+ fname = os.path.join(os.path.abspath(trace_path),
+ "wmtrace-%s-%s.json" % (res.__class__.__name__, now))
+
+ with open(fname, "w+b") as f:
+ f.write(json.dumps(trace))
+
+
class Options(object):
""" class based on django.db.models.options. We only keep
useful bits."""
@@ -171,7 +232,7 @@ class Resource(object):
csrf_exempt = True
url_regexp = r"^$"
- trace = True
+ trace = False
trace_path = None
def allowed_methods(self, req, resp):
View
13 webmachine/templates/wm/base.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8"/>
+ <title>dj-webmachine - {%block title %}{% endblock %}</title>
+ {% block head %}{% endblock %}
+</head>
+<body>
+ {% block content %}{% endblock %}
+ {% block jscripts %}{% endblock %}
+</body>
+</html>
+
View
62 webmachine/templates/wm/wmtrace.html
@@ -0,0 +1,62 @@
+{% extends "wm/base.html" %}
+
+{% block title %}Trace {{ fname }}{% endblock %}
+
+{% block head %}
+<link rel="stylesheet" href="static/wmtrace.css" />
+<script type="text/javascript" src="static/wmtrace.js"></script>
+
+<script>
+ var trace_log = {{ trace|safe|escape }};
+ var request = [];
+ var response = [];
+ var trace= [];
+</script>
+{% endblock head %}
+{% block content %}
+
+<div id="zoompanel">
+ <button id="zoomout">zoom out</button>
+ <button id="zoomin">zoom in</button>
+</div>
+<canvas id="v3map" width="3138" height="2184"></canvas>
+<div id="sizetest"></div>
+<div id="preview">
+ <div id="previewid">
+ <ul id="previewcalls"></ul>
+ </div>
+</div>
+<div id="infopanel">
+ <div id="infocontrols">
+ <div id="requesttab" class="selectedtab">Q</div>
+ <div id="responsetab">R</div>
+ <div id="decisiontab">D</div>
+ </div>
+ <div id="requestdetail">
+ <div>
+ <span id="requestmethod"> <span
+ id="requestpath"></span>
+ </div>
+ <ul id="requestheaders"></ul>
+ </div>
+ <div id="responsedetail">
+ <div id="responsecode"></div>
+ <ul id="responseheaders"><ul>
+
+ </div>
+ <div id="decisiondetail">
+ <div>
+ Decisions: <select id="decisionid"></select>
+ </div>
+ <div>
+ Calls: <select id="decisioncalls"></select>
+ </div>
+ <div>
+ Input: <pre id="callinput"></pre>
+ </div>
+ <div>
+ Output: <pre id="calloutput"></pre>
+ </div>
+ </div>
+</div>
+{% endblock %}
View
13 webmachine/templates/wm/wmtrace_list.html
@@ -0,0 +1,13 @@
+{% extends "wm/base.html" %}
+
+{% block title %}Trace List for {{ path }}{% endblock %}
+
+{% block content %}
+<h1>Traces in {{path}}</h1>
+
+<ul>
+ {% for file in files %}
+ <li><a href="{% url wmtrace file=file %}">wmtrace-{{ file }}</a></li>
+ {% endfor %}
+</ul>
+{% endblock %}
View
97 webmachine/wmtrace.py
@@ -3,63 +3,64 @@
# This file is part of dj-webmachine released under the MIT license.
# See the NOTICE for more information.
-from __future__ import with_statement
-
-from datetime import datetime
-import inspect
import os
-import json
-import traceback
+import os.path
+from glob import iglob
-def update_trace(resource, state, req, resp, trace):
- if not resource.trace:
- # do nothing
- return
+try:
+ import json
+except ImportError:
+ import django.utils.simplejson as json
- infos = {
- "request": {
- "headers": req.headers.items(),
- "get": [(k, req.GET.getlist(k)) for k in req.GET],
- "post": [(k, req.POST.getlist(k)) for k in req.POST],
- "cookies": [(k, req.COOKIES.get(k)) for k in req.COOKIES],
- "url_args": req.url_args,
- "url_kwarg": req.url_kwargs
- },
- "response": {
- "code": resp.status_code,
- "headers": resp.headerlist
- }
+from django.template.loader import render_to_string
+from django.utils.encoding import smart_str
+from django.views import static
+from webmachine import Resource
- }
+class WMTraceResource(Resource):
- if hasattr(req, 'session'):
- infos['request'].update({
- 'session': [(k, req.session.get(k)) for k in \
- req.session.keys()]
+ def __init__(self, path="/tmp"):
+ if path.endswith("/"):
+ path = path[:-1]
+ self.path = os.path.abspath(path)
+
+ def trace_list_html(self, req, resp):
+ files = [os.path.basename(f).split("wmtrace-")[1] for f in \
+ iglob("%s/wmtrace-*.*" % self.path)]
+ return render_to_string("wm/wmtrace_list.html", {
+ "path": self.path,
+ "files": files
})
- if isinstance(state, int):
- name = str(state)
- else:
- name = state.__name__
-
- trace.append((name, infos))
-
-def update_ex_trace(trace, e):
- trace.append(("error", traceback.format_exc()))
-
-def write_trace(res, trace):
- if not res.trace:
- return
+ def trace_html(self, req, resp):
+ fname = req.url_kwargs["file"]
+ fname = os.path.join(self.path, "wmtrace-%s" % fname)
+ with open(fname, "r+b") as f:
+ return render_to_string("wm/wmtrace.html", {
+ "fname": fname,
+ "trace": f.read()
+ })
- if not res.trace_path:
- trace_path = "/tmp"
+ def to_html(self, req, resp):
+ if "file" in req.url_kwargs:
+ return self.trace_html(req, resp)
+ return self.trace_list_html(req, resp)
- now = datetime.now().replace(microsecond=0).isoformat() + 'Z'
- fname = os.path.join(os.path.abspath(trace_path),
- "wmtrace-%s-%s.trace" % (res.__class__.__name__, now))
- with open(fname, "w+b") as f:
- f.write(json.dumps(trace))
+ def get_urls(self):
+ from django.conf.urls.defaults import patterns, url
+ media_path = os.path.abspath(os.path.join(__file__, "..",
+ "media"))
+ print media_path
+ urlpatterns = patterns('',
+ url(r'wmtrace-(?P<file>.+)$', self, name="wmtrace"),
+ url(r'^static/(?P<path>.*)', static.serve, {
+ 'document_root': media_path,
+ 'show_indexes': False
+ }),
+ url(r'$', self, name="wmtrace_list"),
+
+ )
+ return urlpatterns
Please sign in to comment.
Something went wrong with that request. Please try again.