df7bf5db |
<?php
date_default_timezone_set('America/Los_Angeles'); ?><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Mesh Network Topo Map</title>
<!--
&, /@ #@ @
/@@/@* @%@@@
# ,
@
@ # % ,/ ./
.@@@@& /& @@@@@
*. , &&/ # *.
#@@
@#%#.
@(@#@
@*.@#.,
,/.#@#%@
@@#@@#&@#
#.@&.@ %/&. CQ CQ de K9RCP
,%.,(*@ @@ @
@( %@@ (*%
@@(@&*@@#(@&(@/
&/#. @ %@ /* # @
*@ %( %@ @, @
.@ #* .& %@. @ % .@
@*( @%@*@ @#&
@(#/%@@&%(@@%%&@@@#/@&#
@( .& @.&@/(% @ @/
@@ @@. @@/ ##@ @.
#@ @. @ @@% ,% (% .@
/@ @. &. @@% #/ (%*@
& #* @@% @. /*
*%@@&@
.@@@.//
-->
<style>
#app {
display: flex;
display: -webkit-flex;
flex-direction: column;
-webkit-flex-direction: column;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#header {
flex: 0 0 auto;
-webkit-flex: 0 0 auto;
line-height: 1.3;
}
#panes {
display: flex;
display: -webkit-flex;
flex: 1 1 auto;
-webkit-flex: 1 1 auto;
}
#graph {
display: flex;
display: -webkit-flex;
flex-direction: column;
-webkit-flex-direction: column;
}
#options {
flex: 0 0 auto;
-webkit-flex: 0 0 auto;
}
#output {
flex: 1 1 auto;
-webkit-flex: 1 1 auto;
position: relative;
overflow: auto;
}
#editor {
border-right: 1px solid #ccc;
}
#header {
background: #eee;
border-bottom: 1px solid #ccc;
padding: 8px;
text-align: center;
}
#header b {
font-size: 18px;
}
#options {
background: #eee;
border-bottom: 1px solid #ccc;
padding: 8px;
}
#options label {
margin-right: 8px;
}
#options #raw.disabled {
opacity: 0.5;
}
#output svg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#output #text {
font-size: 12px;
font-family: monaco, courier, monospace;
white-space: pre;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: auto;
}
#output img {
display: block;
margin: 0 auto;
}
#output.working svg, #output.error svg,
#output.working #text, #output.error #text,
#output.working img, #output.error img {
opacity: 0.4;
}
#output.error #error {
display: inherit;
}
#output #error {
display: none;
position: absolute;
top: 20px;
left: 20px;
margin-right: 20px;
background: red;
color: white;
z-index: 1;
}
.gutter {
background-color: #eee;
background-repeat: no-repeat;
background-position: 50%;
}
.gutter.gutter-horizontal {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
cursor: ew-resize;
}
.split {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
}
.split.split-horizontal, .gutter.gutter-horizontal {
height: 100%;
float: left;
}
</style>
</head>
<body>
<div id="app">
<div id="header">
<b>WVMN Topology - <?php echo date("F j, Y, g:i a"); ?></b>
</div>
<div id="panes">
<div id="editor" hidden>
<?php
$fp = fsockopen("10.204.114.225", 2004, $errno, $errstr, 30);
$data = "";
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
while (!feof($fp)) {
$data .= fgets($fp, 128);
}
fclose($fp);
}
if (!function_exists('str_contains')) {
function str_contains($haystack, $needle): bool {
if ( is_string($haystack) && is_string($needle) ) {
return '' === $needle || false !== strpos($haystack, $needle);
} else {
return false;
}
}
}
$ips = json_decode(file_get_contents("./ips.host"), TRUE);
$ar = explode("\n", $data);
$checkNodes = array();
$data = "";
foreach ($ar as &$value) {
$ip = explode('"', $value)[1];
if (filter_var($ip, FILTER_VALIDATE_IP && !isset($ips[$ip]))) {
$ips[$ip] = "NULL";
}
if (!str_contains($value, 'HNA') && !str_contains($value, 'diamond')) {
if (str_contains($value, 'label')) {
$dr = explode('];', $value);
$val = explode('"', explode('label="', $value)[1])[0];
if ($val < 0.98) { $color = "blue"; $pwidth = 1; }
if ($val > 0.99) { $color = "green"; $pwidth = 2.5; }
if ($val > 3.00) { $color = "yellow";$pwidth = 2.5; }
if ($val > 4.00) { $color = "orange"; $pwidth = 3.5; }
if ($val > 6.00) { $color = "red"; $pwidth = 5; }
if ($val == "INFINITE") { $color = "red"; $pwidth = 8; }
//$dr[0] = "10.166.72.127" -> "10.138.41.208"[label="0.100"];
$da = explode('"', $dr[0]);
if (!isset($checkNodes[$da[3]."-".$da[1]])) {
$data .= $dr[0].', penwidth='.$pwidth.' color="'.$color.'"];'."\n";
$checkNodes[$da[1]."-".$da[3]] = "TRUE";
} else {
$data .= $dr[0].', penwidth='.$pwidth.' color="'.$color.'"];'."\n";
}
} else {
$data .= $value."\n";
}
}
}
foreach ($ips as $key => $value) {
if(filter_var($ips[$key], FILTER_VALIDATE_IP) || $ips[$key] == "NULL") {
$ips[$key] = gethostbyaddr($key);
}
$data = str_replace($key, $ips[$key], $data);
}
file_put_contents("./ips.host", json_encode($ips));
//print_r($checkNodes);
echo $data;
?>
</div>
<div id="graph">
<div id="options" hidden>
<label id="engine">
Engine:
<select>
<option>circo</option>
<option selected>dot</option>
<option>fdp</option>
<option>neato</option>
<option>osage</option>
<option>twopi</option>
</select>
</label>
<label id="format">
Format:
<select>
<option selected>svg</option>
<option>png-image-element</option>
<option>json</option>
<option>xdot</option>
<option>plain</option>
<option>ps</option>
</select>
</label>
<label id="raw">
<input type="checkbox"> Show raw output
</label>
</div>
<div id="output">
<div id="error"></div>
</div>
</div>
</div>
</div>
<script src="./js/ace.js"></script>
<script src="./js/viz.js"></script>
<script src="./js/fabric.min.js"></script>
<script src="./js/split.min.js"></script>
<script src="./js/svg-pan-zoom.min.js"></script>
<script>
var beforeUnloadMessage = null;
var resizeEvent = new Event("paneresize");
Split(['#editor', '#graph'], {
sizes: [0, 100],
onDragEnd: function() {
var svgOutput = document.getElementById("svg_output");
if (svgOutput != null) {
svgOutput.dispatchEvent(resizeEvent);
}
}
});
var editor = ace.edit("editor");
editor.getSession().setMode("ace/mode/dot");
var parser = new DOMParser();
var worker;
var result;
function updateGraph() {
if (worker) {
worker.terminate();
}
document.querySelector("#output").classList.add("working");
document.querySelector("#output").classList.remove("error");
worker = new Worker("./worker.js");
worker.onmessage = function(e) {
document.querySelector("#output").classList.remove("working");
document.querySelector("#output").classList.remove("error");
result = e.data;
updateOutput();
}
worker.onerror = function(e) {
document.querySelector("#output").classList.remove("working");
document.querySelector("#output").classList.add("error");
var message = e.message === undefined ? "An error occurred while processing the graph input." : e.message;
var error = document.querySelector("#error");
while (error.firstChild) {
error.removeChild(error.firstChild);
}
document.querySelector("#error").appendChild(document.createTextNode(message));
console.error(e);
e.preventDefault();
}
var params = {
src: editor.getSession().getDocument().getValue(),
options: {
engine: document.querySelector("#engine select").value,
format: document.querySelector("#format select").value
}
};
// Instead of asking for png-image-element directly, which we can't do in a worker,
// ask for SVG and convert when updating the output.
if (params.options.format == "png-image-element") {
params.options.format = "svg";
}
worker.postMessage(params);
}
function updateOutput() {
var graph = document.querySelector("#output");
var svg = graph.querySelector("svg");
if (svg) {
graph.removeChild(svg);
}
var text = graph.querySelector("#text");
if (text) {
graph.removeChild(text);
}
var img = graph.querySelector("img");
if (img) {
graph.removeChild(img);
}
if (!result) {
return;
}
if (document.querySelector("#format select").value == "svg" && !document.querySelector("#raw input").checked) {
var svg = parser.parseFromString(result, "image/svg+xml").documentElement;
svg.id = "svg_output";
graph.appendChild(svg);
panZoom = svgPanZoom(svg, {
zoomEnabled: true,
controlIconsEnabled: true,
fit: true,
center: true,
minZoom: 0.1
});
svg.addEventListener('paneresize', function(e) {
panZoom.resize();
}, false);
window.addEventListener('resize', function(e) {
panZoom.resize();
});
} else if (document.querySelector("#format select").value == "png-image-element") {
var image = Viz.svgXmlToPngImageElement(result);
graph.appendChild(image);
} else {
var text = document.createElement("div");
text.id = "text";
text.appendChild(document.createTextNode(result));
graph.appendChild(text);
}
}
editor.on("change", function() {
updateGraph();
beforeUnloadMessage = "Your changes will not be saved.";
});
window.addEventListener("beforeunload", function(e) {
return beforeUnloadMessage;
});
document.querySelector("#engine select").addEventListener("change", function() {
updateGraph();
});
document.querySelector("#format select").addEventListener("change", function() {
if (document.querySelector("#format select").value === "svg") {
document.querySelector("#raw").classList.remove("disabled");
document.querySelector("#raw input").disabled = false;
} else {
document.querySelector("#raw").classList.add("disabled");
document.querySelector("#raw input").disabled = true;
}
updateGraph();
});
document.querySelector("#raw input").addEventListener("change", function() {
updateOutput();
});
updateGraph();
</script>
</body>
</html>
|