mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Initial try at a tree view. Includes a few formatting options that will be useful elsewhere.
This commit is contained in:
parent
d03a4f5b19
commit
0f759cbe5c
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
scripts=( index.js template.js login.js first-run.js shaped-devices.js )
|
scripts=( index.js template.js login.js first-run.js shaped-devices.js tree.js )
|
||||||
for script in "${scripts[@]}"
|
for script in "${scripts[@]}"
|
||||||
do
|
do
|
||||||
echo "Building {$script}"
|
echo "Building {$script}"
|
||||||
|
@ -52,4 +52,53 @@ export function lerpGreenToRedViaOrange(value, max) {
|
|||||||
g = 255;
|
g = 255;
|
||||||
}
|
}
|
||||||
return `rgb(${r}, ${g}, ${b})`;
|
return `rgb(${r}, ${g}, ${b})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatThroughput(throughput, limitInMbps) {
|
||||||
|
let limitBits = limitInMbps * 1000 * 1000;
|
||||||
|
let percent = 0;
|
||||||
|
if (limitBits > 0) {
|
||||||
|
percent = (throughput / limitBits) * 100;
|
||||||
|
}
|
||||||
|
let blob = "<span class='overlayThroughputWrapper'>";
|
||||||
|
blob += "<span class='overlayThroughputBar'>";
|
||||||
|
for (let i=0; i<100; i+=10) {
|
||||||
|
let color = lerpGreenToRedViaOrange(100-i, 100);
|
||||||
|
if (percent < i) {
|
||||||
|
blob += "░";
|
||||||
|
} else {
|
||||||
|
blob += "<span style='color: " + color + "'>█</span>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blob += "</span>";
|
||||||
|
|
||||||
|
blob += "<span class='overlayThroughputNumber' style='color: white; font-weight: bold;'>" + scaleNumber(throughput * 8, 1) + "bps</span>";
|
||||||
|
blob += "</span>";
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatRtt(rtt) {
|
||||||
|
if (rtt === undefined) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
const limit = 200;
|
||||||
|
let percent = 0;
|
||||||
|
if (limit > 0) {
|
||||||
|
percent = (rtt / limit) * 100;
|
||||||
|
}
|
||||||
|
let blob = "<span class='overlayThroughputWrapper'>";
|
||||||
|
blob += "<span class='overlayThroughputBar'>";
|
||||||
|
for (let i=0; i<100; i+=10) {
|
||||||
|
let color = lerpGreenToRedViaOrange(100-i, 100);
|
||||||
|
if (percent < i) {
|
||||||
|
blob += "░";
|
||||||
|
} else {
|
||||||
|
blob += "<span style='color: " + color + "'>█</span>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blob += "</span>";
|
||||||
|
|
||||||
|
blob += "<span class='overlayThroughputNumber' style='color: white; font-weight: bold;'>" + parseFloat(rtt).toFixed(0) + " ms</span>";
|
||||||
|
blob += "</span>";
|
||||||
|
return blob;
|
||||||
}
|
}
|
292
src/rust/lqosd/src/node_manager/js_build/src/tree.js
Normal file
292
src/rust/lqosd/src/node_manager/js_build/src/tree.js
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
import {clearDiv, theading} from "./helpers/builders";
|
||||||
|
import {formatRtt, formatThroughput, lerpGreenToRedViaOrange, scaleNumber} from "./helpers/scaling";
|
||||||
|
import {subscribeWS} from "./pubsub/ws";
|
||||||
|
|
||||||
|
var tree = null;
|
||||||
|
var parent = 0;
|
||||||
|
|
||||||
|
// This runs first and builds the initial structure on the page
|
||||||
|
function getInitialTree() {
|
||||||
|
$.get("/local-api/networkTree/0", (data) => {
|
||||||
|
//console.log(data);
|
||||||
|
tree = data;
|
||||||
|
|
||||||
|
let treeTable = document.createElement("table");
|
||||||
|
treeTable.classList.add("table", "table-striped", "table-bordered");
|
||||||
|
let thead = document.createElement("thead");
|
||||||
|
thead.appendChild(theading("Name"));
|
||||||
|
thead.appendChild(theading("Limit"));
|
||||||
|
thead.appendChild(theading("⬇️"));
|
||||||
|
thead.appendChild(theading("⬆️"));
|
||||||
|
thead.appendChild(theading("RTT ⬇️"));
|
||||||
|
thead.appendChild(theading("RTT ⬆️"));
|
||||||
|
thead.appendChild(theading("Re-xmit ⬇️"));
|
||||||
|
thead.appendChild(theading("Re-xmit ⬆️"));
|
||||||
|
thead.appendChild(theading("ECN ⬇️"));
|
||||||
|
thead.appendChild(theading("ECN ⬆️"));
|
||||||
|
thead.appendChild(theading("Drops ⬇️"));
|
||||||
|
thead.appendChild(theading("Drops ⬆️"));
|
||||||
|
|
||||||
|
treeTable.appendChild(thead);
|
||||||
|
let tbody = document.createElement("tbody");
|
||||||
|
for (let i=0; i<tree.length; i++) {
|
||||||
|
let nodeId = tree[i][0];
|
||||||
|
let node = tree[i][1];
|
||||||
|
|
||||||
|
if (nodeId === parent) {
|
||||||
|
$("#nodeName").text(node.name);
|
||||||
|
let limit = "";
|
||||||
|
if (node.max_throughput[0] === 0) {
|
||||||
|
limit = "Unlimited";
|
||||||
|
} else {
|
||||||
|
limit = scaleNumber(node.max_throughput[0] * 1000 * 1000, 0);
|
||||||
|
}
|
||||||
|
limit += " / ";
|
||||||
|
if (node.max_throughput[1] === 0) {
|
||||||
|
limit += "Unlimited";
|
||||||
|
} else {
|
||||||
|
limit += scaleNumber(node.max_throughput[1] * 1000 * 1000, 0);
|
||||||
|
}
|
||||||
|
$("#parentLimits").text(limit);
|
||||||
|
$("#parentTpD").html(formatThroughput(node.current_throughput[0] * 8, node.max_throughput[0]));
|
||||||
|
$("#parentTpU").html(formatThroughput(node.current_throughput[1] * 8, node.max_throughput[1]));
|
||||||
|
console.log(node);
|
||||||
|
$("#parentRttD").html(formatRtt(node.rtts[0]));
|
||||||
|
$("#parentRttU").html(formatRtt(node.rtts[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.immediate_parent !== null && node.immediate_parent === parent) {
|
||||||
|
let row = buildRow(i);
|
||||||
|
tbody.appendChild(row);
|
||||||
|
iterateChildren(i, tbody, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
treeTable.appendChild(tbody);
|
||||||
|
|
||||||
|
// Clear and apply
|
||||||
|
let target = document.getElementById("tree");
|
||||||
|
clearDiv(target)
|
||||||
|
target.appendChild(treeTable);
|
||||||
|
|
||||||
|
subscribeWS(["NetworkTree"], onMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function iterateChildren(idx, tBody, depth) {
|
||||||
|
for (let i=0; i<tree.length; i++) {
|
||||||
|
let node = tree[i][1];
|
||||||
|
if (node.immediate_parent !== null && node.immediate_parent === tree[idx][0]) {
|
||||||
|
let row = buildRow(i, depth);
|
||||||
|
tBody.appendChild(row);
|
||||||
|
iterateChildren(i, tBody, depth+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRow(i, depth=0) {
|
||||||
|
let node = tree[i][1];
|
||||||
|
let nodeId = tree[i][0];
|
||||||
|
let row = document.createElement("tr");
|
||||||
|
row.classList.add("small");
|
||||||
|
let col = document.createElement("td");
|
||||||
|
let nodeName = "";
|
||||||
|
if (depth > 0) {
|
||||||
|
nodeName += "└";
|
||||||
|
}
|
||||||
|
for (let j=1; j<depth; j++) {
|
||||||
|
nodeName += "─";
|
||||||
|
}
|
||||||
|
if (depth > 0) nodeName += " ";
|
||||||
|
nodeName += "<a href='/tree.html?parent=" + nodeId + "'>";
|
||||||
|
nodeName += node.name;
|
||||||
|
nodeName += "</a>";
|
||||||
|
if (node.type !== null) {
|
||||||
|
nodeName += " (" + node.type + ")";
|
||||||
|
}
|
||||||
|
col.innerHTML = nodeName;
|
||||||
|
col.classList.add("small", "redactable");
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "limit-" + nodeId;
|
||||||
|
col.classList.add("small");
|
||||||
|
let limit = "";
|
||||||
|
if (node.max_throughput[0] === 0) {
|
||||||
|
limit = "Unlimited";
|
||||||
|
} else {
|
||||||
|
limit = scaleNumber(node.max_throughput[0] * 1000 * 1000, 0);
|
||||||
|
}
|
||||||
|
limit += " / ";
|
||||||
|
if (node.max_throughput[1] === 0) {
|
||||||
|
limit += "Unlimited";
|
||||||
|
} else {
|
||||||
|
limit += scaleNumber(node.max_throughput[0] * 1000 * 1000, 0);
|
||||||
|
}
|
||||||
|
col.textContent = limit;
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "down-" + nodeId;
|
||||||
|
col.classList.add("small");
|
||||||
|
col.innerHTML = formatThroughput(node.current_throughput[0] * 8, node.max_throughput[0]);
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "up-" + nodeId;
|
||||||
|
col.classList.add("small");
|
||||||
|
col.innerHTML = formatThroughput(node.current_throughput[1] * 8, node.max_throughput[1]);
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "rtt-down-" + nodeId;
|
||||||
|
col.innerHTML = formatRtt(node.rtts[0]);
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "rtt-up-" + nodeId;
|
||||||
|
col.innerHTML = formatRtt(node.rtts[1]);
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "re-xmit-down-" + nodeId;
|
||||||
|
if (node.current_retransmits[0] !== undefined) {
|
||||||
|
col.textContent = node.current_retransmits[0];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "re-xmit-up-" + nodeId;
|
||||||
|
if (node.current_retransmits[1] !== undefined) {
|
||||||
|
col.textContent = node.current_retransmits[1];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "ecn-down-" + nodeId;
|
||||||
|
if (node.current_marks[0] !== undefined) {
|
||||||
|
col.textContent = node.current_marks[0];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "ecn-up-" + nodeId;
|
||||||
|
if (node.current_marks[1] !== undefined) {
|
||||||
|
col.textContent = node.current_marks[1];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "drops-down-" + nodeId;
|
||||||
|
if (node.current_drops[0] !== undefined) {
|
||||||
|
col.textContent = node.current_drops[0];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
col = document.createElement("td");
|
||||||
|
col.id = "drops-up-" + nodeId;
|
||||||
|
if (node.current_drops[1] !== undefined) {
|
||||||
|
col.textContent = node.current_drops[1];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
row.appendChild(col);
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMessage(msg) {
|
||||||
|
if (msg.event === "NetworkTree") {
|
||||||
|
//console.log(msg);
|
||||||
|
msg.data.forEach((n) => {
|
||||||
|
let nodeId = n[0];
|
||||||
|
let node = n[1];
|
||||||
|
|
||||||
|
let col = document.getElementById("down-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
col.innerHTML = formatThroughput(node.current_throughput[0] * 8, node.max_throughput[0]);
|
||||||
|
}
|
||||||
|
col = document.getElementById("up-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
col.innerHTML = formatThroughput(node.current_throughput[1] * 8, node.max_throughput[1]);
|
||||||
|
}
|
||||||
|
col = document.getElementById("rtt-down-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
col.innerHTML = formatRtt(node.rtts[0]);
|
||||||
|
}
|
||||||
|
col = document.getElementById("rtt-up-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
col.innerHTML = formatRtt(node.rtts[1]);
|
||||||
|
}
|
||||||
|
col = document.getElementById("re-xmit-down-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
if (node.current_retransmits[0] !== undefined) {
|
||||||
|
col.textContent = node.current_retransmits[0];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col = document.getElementById("re-xmit-up-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
if (node.current_retransmits[1] !== undefined) {
|
||||||
|
col.textContent = node.current_retransmits[1];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col = document.getElementById("ecn-down-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
if (node.current_marks[0] !== undefined) {
|
||||||
|
col.textContent = node.current_marks[0];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col = document.getElementById("ecn-up-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
if (node.current_marks[1] !== undefined) {
|
||||||
|
col.textContent = node.current_marks[1];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col = document.getElementById("drops-down-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
if (node.current_drops[0] !== undefined) {
|
||||||
|
col.textContent = node.current_drops[0];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
col = document.getElementById("drops-up-" + nodeId);
|
||||||
|
if (col !== null) {
|
||||||
|
if (node.current_drops[1] !== undefined) {
|
||||||
|
col.textContent = node.current_drops[1];
|
||||||
|
} else {
|
||||||
|
col.textContent = "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = new Proxy(new URLSearchParams(window.location.search), {
|
||||||
|
get: (searchParams, prop) => searchParams.get(prop),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (params.parent !== null) {
|
||||||
|
parent = parseInt(params.parent);
|
||||||
|
} else {
|
||||||
|
parent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInitialTree();
|
@ -2,6 +2,7 @@ mod dashboard_themes;
|
|||||||
mod version_check;
|
mod version_check;
|
||||||
mod device_counts;
|
mod device_counts;
|
||||||
mod shaped_device_api;
|
mod shaped_device_api;
|
||||||
|
mod network_tree;
|
||||||
|
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
use axum::routing::{get, post};
|
use axum::routing::{get, post};
|
||||||
@ -15,4 +16,5 @@ pub fn local_api() -> Router {
|
|||||||
.route("/versionCheck", get(version_check::version_check))
|
.route("/versionCheck", get(version_check::version_check))
|
||||||
.route("/deviceCount", get(device_counts::count_users))
|
.route("/deviceCount", get(device_counts::count_users))
|
||||||
.route("/devicesAll", get(shaped_device_api::all_shaped_devices))
|
.route("/devicesAll", get(shaped_device_api::all_shaped_devices))
|
||||||
|
.route("/networkTree/:parent", get(network_tree::get_network_tree))
|
||||||
}
|
}
|
20
src/rust/lqosd/src/node_manager/local_api/network_tree.rs
Normal file
20
src/rust/lqosd/src/node_manager/local_api/network_tree.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use axum::extract::Path;
|
||||||
|
use axum::Json;
|
||||||
|
use lqos_bus::BusResponse;
|
||||||
|
use lqos_config::NetworkJsonTransport;
|
||||||
|
use crate::shaped_devices_tracker;
|
||||||
|
use crate::shaped_devices_tracker::NETWORK_JSON;
|
||||||
|
|
||||||
|
pub async fn get_network_tree(
|
||||||
|
Path(parent): Path<usize>
|
||||||
|
) -> Json<Vec<(usize, NetworkJsonTransport)>> {
|
||||||
|
let net_json = NETWORK_JSON.read().unwrap();
|
||||||
|
let result: Vec<(usize, NetworkJsonTransport)> = net_json
|
||||||
|
.nodes
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, n) | (i, n.clone_to_transit()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Json(result)
|
||||||
|
}
|
@ -79,4 +79,22 @@ body.dark-mode {
|
|||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
}
|
}
|
||||||
.dashEditButton { }
|
.dashEditButton { }
|
||||||
.redactable { }
|
.redactable { }
|
||||||
|
.small { font-size: 8pt; }
|
||||||
|
|
||||||
|
/* Funky tricks for the tree view */
|
||||||
|
.overlayThroughputWrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.overlayThroughputNumber {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: white;
|
||||||
|
text-shadow: 2px 2px 4px #000000;
|
||||||
|
}
|
@ -49,7 +49,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<!-- Tree -->
|
<!-- Tree -->
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link">
|
<a class="nav-link" href="tree.html?parent=0">
|
||||||
<i class="fa fa-tree nav-icon"></i> Tree
|
<i class="fa fa-tree nav-icon"></i> Tree
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
29
src/rust/lqosd/src/node_manager/static2/tree.html
Normal file
29
src/rust/lqosd/src/node_manager/static2/tree.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-4">
|
||||||
|
<h5><i class="fa fa-tree"></i> Network Tree (<span id="nodeName"></span>)</h5>
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<td style="font-weight: bold;">Limits:</td>
|
||||||
|
<td class="small"><span id="parentLimits"></span></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-weight: bold;">Throughput:</td>
|
||||||
|
<td><span id="parentTpD"></span></td>
|
||||||
|
<td><span id="parentTpU"></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-weight: bold;">RTT:</td>
|
||||||
|
<td><span id="parentRttD"></span></td>
|
||||||
|
<td><span id="parentRttU"></span></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12" id="tree">
|
||||||
|
<p><i class="fa fa-spin fa-spinner"></i> Loading, Please Wait</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="tree.js"></script>
|
@ -29,7 +29,7 @@ pub(super) fn static_routes() -> Result<Router> {
|
|||||||
// Add HTML pages to serve directly to this list, otherwise
|
// Add HTML pages to serve directly to this list, otherwise
|
||||||
// they won't have template + authentication applied to them.
|
// they won't have template + authentication applied to them.
|
||||||
let html_pages = [
|
let html_pages = [
|
||||||
"index.html", "shaped_devices.html"
|
"index.html", "shaped_devices.html", "tree.html"
|
||||||
];
|
];
|
||||||
|
|
||||||
// Iterate through pages and construct the router
|
// Iterate through pages and construct the router
|
||||||
|
@ -19,4 +19,5 @@ pub enum PublishedChannels {
|
|||||||
Ram,
|
Ram,
|
||||||
TreeSummary,
|
TreeSummary,
|
||||||
QueueStatsTotal,
|
QueueStatsTotal,
|
||||||
|
NetworkTree,
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ mod flow_endpoints;
|
|||||||
pub mod system_info;
|
pub mod system_info;
|
||||||
mod tree_summary;
|
mod tree_summary;
|
||||||
mod queue_stats_total;
|
mod queue_stats_total;
|
||||||
|
mod network_tree;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::node_manager::ws::publish_subscribe::PubSub;
|
use crate::node_manager::ws::publish_subscribe::PubSub;
|
||||||
@ -36,6 +37,7 @@ pub(super) async fn channel_ticker(channels: Arc<PubSub>) {
|
|||||||
system_info::ram_info(channels.clone()),
|
system_info::ram_info(channels.clone()),
|
||||||
tree_summary::tree_summary(channels.clone()),
|
tree_summary::tree_summary(channels.clone()),
|
||||||
queue_stats_total::queue_stats_totals(channels.clone()),
|
queue_stats_total::queue_stats_totals(channels.clone()),
|
||||||
|
network_tree::network_tree(channels.clone()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
31
src/rust/lqosd/src/node_manager/ws/ticker/network_tree.rs
Normal file
31
src/rust/lqosd/src/node_manager/ws/ticker/network_tree.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use serde_json::json;
|
||||||
|
use tokio::task::spawn_blocking;
|
||||||
|
use lqos_config::NetworkJsonTransport;
|
||||||
|
use crate::node_manager::ws::publish_subscribe::PubSub;
|
||||||
|
use crate::node_manager::ws::published_channels::PublishedChannels;
|
||||||
|
use crate::shaped_devices_tracker::NETWORK_JSON;
|
||||||
|
|
||||||
|
pub async fn network_tree(channels: Arc<PubSub>) {
|
||||||
|
if !channels.is_channel_alive(PublishedChannels::NetworkTree).await {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: Vec<(usize, NetworkJsonTransport)> = spawn_blocking(|| {
|
||||||
|
let net_json = NETWORK_JSON.read().unwrap();
|
||||||
|
net_json
|
||||||
|
.nodes
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, n) | (i, n.clone_to_transit()))
|
||||||
|
.collect()
|
||||||
|
}).await.unwrap();
|
||||||
|
|
||||||
|
let message = json!(
|
||||||
|
{
|
||||||
|
"event": PublishedChannels::NetworkTree.to_string(),
|
||||||
|
"data": data,
|
||||||
|
}
|
||||||
|
).to_string();
|
||||||
|
channels.send(PublishedChannels::NetworkTree, message).await;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user