You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
386 lines
10 KiB
386 lines
10 KiB
var colors=["green", "red", "sienna", "orange", "black", "purple", "chocolate", "olivedrab", "darkred", "darkslategrey", "midnightblue", "maroon", "teal", "goldenrod", "gray", "darkolivegreen", "darkcyan", "brown", "peru", "mediumorchild", "navy", "saddlebrown", "coral"];
|
|
|
|
function line_color(d)
|
|
{
|
|
return colors[d];
|
|
}
|
|
|
|
var aliases = { };
|
|
|
|
function classToAlias(c)
|
|
{
|
|
var alias = aliases[c];
|
|
|
|
if (alias == undefined)
|
|
{
|
|
alias = c;
|
|
}
|
|
|
|
return alias;
|
|
}
|
|
|
|
function receiver(d, considerports)
|
|
{
|
|
var rc = d.dst_ip;
|
|
|
|
if (considerports)
|
|
{
|
|
rc += ":" + d.dst_port;
|
|
}
|
|
|
|
return classToAlias(rc);
|
|
}
|
|
|
|
function sender(d, considerports)
|
|
{
|
|
var rc = d.src_ip;
|
|
|
|
if (considerports)
|
|
{
|
|
rc += ":" + d.src_port;
|
|
}
|
|
|
|
return classToAlias(rc);
|
|
}
|
|
|
|
function prepareData(data, considerports)
|
|
{
|
|
console.log("prepare data");
|
|
|
|
data.frames.forEach(function(m, i) {
|
|
m.hidden = false;
|
|
m.drawable = true;
|
|
});
|
|
|
|
data.frames.forEach(function(m, i) {
|
|
|
|
var i = (sender(m, considerports) == receiver(m, considerports))
|
|
|
|
m.internal = i;
|
|
m.drawable = !i;
|
|
});
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
function hostPortToClass(c)
|
|
{
|
|
return "class-" + classToAlias(c).replace(/\./g, "_").replace(":", "_");
|
|
}
|
|
|
|
function toggleSVG(node)
|
|
{
|
|
console.log(node);
|
|
var x = document.getElementsByClassName(node);
|
|
|
|
console.log(x.length);
|
|
var i; for (i = 0; i < x.length; i++)
|
|
{
|
|
x[i].style.display = (x[i].style.display == 'none') ? 'block' : 'none';
|
|
}
|
|
}
|
|
|
|
function createSvg(container)
|
|
{
|
|
var width = parseInt(d3.select(container).style("width"), 10);
|
|
|
|
return d3.select(container).append("svg").attr("width", width );
|
|
}
|
|
|
|
function redraw(data, considerports)
|
|
{
|
|
var svg = d3.selectAll("svg");
|
|
svg.remove();
|
|
draw_sequence_diagram(data, considerports);
|
|
}
|
|
|
|
function hidePackets(rawdata, pattern, considerports)
|
|
{
|
|
console.log("hide packets", pattern);
|
|
|
|
rawdata.frames.forEach(function(item, i)
|
|
{
|
|
if (sender(item, considerports) == pattern || receiver(item, considerports) == pattern)
|
|
{
|
|
item.hidden = !item.hidden;
|
|
}
|
|
});
|
|
|
|
redraw(rawdata, considerports);
|
|
}
|
|
|
|
function getNodes(data, considerports)
|
|
{
|
|
var senders = d3.set(data.map(function(d){ return sender(d, considerports); })).values();
|
|
var receivers = d3.set(data.map(function(d){ return receiver(d, considerports); })).values();
|
|
return _.union(senders, receivers);
|
|
}
|
|
|
|
function considerPortsClick(rawdata, considerports)
|
|
{
|
|
console.log("consider ports click");
|
|
prepareData(rawdata, !considerports);
|
|
redraw(rawdata, !considerports);
|
|
}
|
|
|
|
function draw_sequence_diagram(rawdata, considerports)
|
|
{
|
|
var chartName = rawdata.call;
|
|
var data = rawdata.frames;
|
|
|
|
function considerPorts()
|
|
{
|
|
considerPortsClick(rawdata, considerports);
|
|
}
|
|
|
|
var message_frame = d3.select("#message-frame");
|
|
|
|
function showMessageBody(m)
|
|
{
|
|
message_frame.html("<textarea>" + "packet# " + m.id + "\n" + m.payload + "</textarea>");
|
|
}
|
|
|
|
function listClasses(m, considerports)
|
|
{
|
|
return hostPortToClass(sender(m, considerports)) + " " +
|
|
hostPortToClass(receiver(m, considerports)) + " " +
|
|
"class-message";
|
|
}
|
|
|
|
function classClick(node)
|
|
{
|
|
console.log("class click", node);
|
|
|
|
// FIXME reimplement with d3
|
|
// toggleSVG(hostPortToClass(node));
|
|
hidePackets(rawdata, node, considerports);
|
|
|
|
}
|
|
|
|
function initAliases(nodes, preAliases)
|
|
{
|
|
if (_.isEmpty(aliases))
|
|
{
|
|
var nodes1 = nodes.slice();
|
|
|
|
if (typeof preAliases !== 'undefined')
|
|
{
|
|
for (var key in preAliases)
|
|
{
|
|
var index = nodes1.indexOf(key);
|
|
if (index != -1)
|
|
{
|
|
nodes1[index] = preAliases[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
dictedit.init("nodeEditor", null, nodes, nodes1);
|
|
aliases = dictedit.value("nodeEditor");
|
|
applyNodeEdit();
|
|
}
|
|
}
|
|
|
|
var button1 = d3.select("#considerPortsButton").on("click", considerPorts);
|
|
var expand = d3.select("#expandEditor").on("click", expandEditor);
|
|
var apply = d3.select("#applyNodeEdit").on("click", applyNodeEdit);
|
|
|
|
function applyNodeEdit() {
|
|
aliases = dictedit.value("nodeEditor");
|
|
redraw(rawdata, considerports);
|
|
};
|
|
|
|
function expandEditor() {
|
|
$("#editorDiv").slideToggle(200);
|
|
};
|
|
|
|
var header = createSvg("#diagram_header");
|
|
var svg = createSvg("#diagram");
|
|
|
|
var margin = { top: 20, right: 20, bottom: 20, left: 20 },
|
|
width = +svg.attr('width') - margin.left - margin.right,
|
|
height = +svg.attr('height') - margin.top - margin.bottom,
|
|
g = header.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
|
|
|
|
// Graph title
|
|
g.append('text')
|
|
.attr('x', (width / 2))
|
|
.attr('y', 0 - (margin.top / 4))
|
|
.attr('class', 'class-title')
|
|
.text(chartName);
|
|
|
|
var nodes = getNodes(data, considerports);
|
|
|
|
initAliases(nodes, rawdata.aliases);
|
|
|
|
var XPAD = 200; // horizontal padding for vertical lines/messages/labels
|
|
var YPAD = 3;
|
|
var VERT_SPACE = parseInt(width/nodes.length);
|
|
|
|
var MESSAGE_SPACE = 25;
|
|
svg.attr("height", (data.length+2)*MESSAGE_SPACE);
|
|
|
|
var MESSAGE_LABEL_X_OFFSET = -50;
|
|
var MESSAGE_LABEL_Y_OFFSET = 10;
|
|
var MESSAGE_ARROW_Y_OFFSET = 15;
|
|
|
|
var CLASS_WIDTH = 120;
|
|
var CLASS_LABEL_X_OFFSET = -30;
|
|
var CLASS_LABEL_Y_OFFSET = 25;
|
|
|
|
// Draw vertical lines
|
|
nodes.forEach(function(c, i) {
|
|
var line = svg.append("line")
|
|
.attr("class", "class-vertical-line")
|
|
.attr("x1", XPAD + i * VERT_SPACE)
|
|
.attr("y1", 0) // YPAD + MESSAGE_SPACE)
|
|
.attr("x2", XPAD + i * VERT_SPACE)
|
|
.attr("y2", YPAD + data.length * (MESSAGE_SPACE + 5))
|
|
});
|
|
|
|
// Draw class labels
|
|
nodes.forEach(function(c, i) {
|
|
var x = XPAD + i * VERT_SPACE;
|
|
var g1 = header.append("g")
|
|
.attr("transform", "translate(" + x + "," + YPAD + ")")
|
|
.attr("class", "class-rect")
|
|
.append("rect")
|
|
.attr("x", -CLASS_WIDTH/2)
|
|
.attr("y", "0")
|
|
.attr("width", CLASS_WIDTH)
|
|
.attr("height", "24px")
|
|
.on("click", function() { classClick(c) })
|
|
|
|
var g2 = header.append("g")
|
|
.attr("transform", "translate(" + x + "," + YPAD + ")")
|
|
.append("text")
|
|
.attr("class", "class-label")
|
|
.attr("text-anchor", "middle")
|
|
.text(function (d) { return classToAlias(c); })
|
|
.attr("dy", "16px")
|
|
.on("click", function() { classClick(c) })
|
|
});
|
|
|
|
var i = -1;
|
|
var message_number = 0;
|
|
|
|
data.forEach(function(m, c) {
|
|
|
|
// FIXME var lcolor = line_color(m.session_id);
|
|
var lcolor = line_color(0);
|
|
var tcolor = "black";
|
|
|
|
if (!m.drawable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
i++;
|
|
|
|
if (m.hidden)
|
|
{
|
|
lcolor = "lightgrey";
|
|
tcolor = "lightgrey";
|
|
}
|
|
|
|
// draw packet number
|
|
var xPos = 0;
|
|
var yPos = MESSAGE_LABEL_Y_OFFSET + i * MESSAGE_SPACE;
|
|
var classes = listClasses(m, considerports);
|
|
|
|
var g1 = svg.append("g")
|
|
.attr("transform", "translate(" + xPos + "," + yPos + ")")
|
|
.attr("text-anchor", "left")
|
|
.attr("class", classes)
|
|
.attr("class", "message-number")
|
|
.append("text")
|
|
.style("fill", tcolor)
|
|
.text(message_number++);
|
|
|
|
|
|
// draw timestamp
|
|
var xPos = XPAD/2;
|
|
var yPos = MESSAGE_LABEL_Y_OFFSET + i * MESSAGE_SPACE;
|
|
|
|
g1 = svg.append("g")
|
|
.attr("transform", "translate(" + xPos + "," + yPos + ")")
|
|
.attr("text-anchor", "middle")
|
|
.attr("class", classes)
|
|
.append("text")
|
|
.style("fill", tcolor)
|
|
.style("font-size", "10px")
|
|
.text(m.timestamp);
|
|
|
|
// draw message labels
|
|
xPos = XPAD + MESSAGE_LABEL_X_OFFSET + (((nodes.indexOf(receiver(m, considerports)) - nodes.indexOf(sender(m, considerports))) * VERT_SPACE) / 2) + (nodes.indexOf(sender(m, considerports)) * VERT_SPACE);
|
|
yPos = MESSAGE_LABEL_Y_OFFSET + i * MESSAGE_SPACE;
|
|
|
|
// draw message labels
|
|
g1 = svg.append("g")
|
|
.attr("transform", "translate(" + xPos + "," + yPos + ")")
|
|
.append("text")
|
|
.attr("dx", "5px")
|
|
.attr("dy", "-2px")
|
|
.attr("text-anchor", "begin")
|
|
.style("fill", tcolor)
|
|
.attr("class", classes)
|
|
.on("click", function() { showMessageBody(m) })
|
|
.text(m.method + " " + m.request_uri);
|
|
|
|
// draw line
|
|
var y = MESSAGE_ARROW_Y_OFFSET + (i) * MESSAGE_SPACE;
|
|
var line = svg.append("line")
|
|
.style("stroke", lcolor)
|
|
.attr("x1", XPAD + nodes.indexOf(sender(m, considerports)) * VERT_SPACE)
|
|
.attr("y1", y)
|
|
.attr("x2", XPAD + nodes.indexOf(receiver(m, considerports)) * VERT_SPACE)
|
|
.attr("y2", y)
|
|
.attr("marker-end", "url(#end)")
|
|
.on("click", function() { showMessageBody(m) })
|
|
|
|
if (m.hidden)
|
|
{
|
|
line.attr("marker-end", "url(#hidden)");
|
|
}
|
|
else
|
|
{
|
|
line.attr("marker-end", "url(#end)");
|
|
}
|
|
});
|
|
|
|
// Arrow style
|
|
svg.append("svg:defs").selectAll("marker")
|
|
.data(["end"])
|
|
.enter().append("svg:marker")
|
|
.attr("id", String)
|
|
.attr("viewBox", "0 -5 10 10")
|
|
.attr("refX", 10)
|
|
.attr("refY", 0)
|
|
.attr("markerWidth", 10)
|
|
.attr("markerHeight", 10)
|
|
.attr("orient", "auto")
|
|
.attr("fill", "blue")
|
|
.append("svg:path")
|
|
.style("stroke", "blue")
|
|
.attr("d", "M0,-3L10,0L0,3");
|
|
|
|
// Arrow style
|
|
svg.append("svg:defs").selectAll("marker")
|
|
.data(["hidden"])
|
|
.enter().append("svg:marker")
|
|
.attr("id", String)
|
|
.attr("viewBox", "0 -5 10 10")
|
|
.attr("refX", 10)
|
|
.attr("refY", 0)
|
|
.attr("markerWidth", 10)
|
|
.attr("markerHeight", 10)
|
|
.attr("orient", "auto")
|
|
.attr("fill", "lightgrey")
|
|
.append("svg:path")
|
|
.style("stroke", "lightgrey")
|
|
.attr("d", "M0,-3L10,0L0,3");
|
|
|
|
showMessageBody(data[0]);
|
|
}
|