<?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>