mirror of
https://github.com/Noratrieb/haesli.git
synced 2026-01-14 19:55:03 +01:00
add dashboard
This commit is contained in:
parent
077b6fd633
commit
dc8efd4e4e
13 changed files with 777 additions and 33 deletions
14
amqp_dashboard/Cargo.toml
Normal file
14
amqp_dashboard/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "amqp_dashboard"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
amqp_core = { path = "../amqp_core" }
|
||||
axum = "0.4.5"
|
||||
serde = { version = "1.0.136", features = ["derive"] }
|
||||
tokio = { version = "1.17.0", features = ["full"] }
|
||||
tower-http = { version = "0.2.3", features = ["fs"] }
|
||||
tracing = "0.1.31"
|
||||
19
amqp_dashboard/assets/index.html
Normal file
19
amqp_dashboard/assets/index.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>AMQP Data</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>AMQP Data</h1>
|
||||
<h2>Connections</h2>
|
||||
<div id="connection-wrapper">
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
41
amqp_dashboard/assets/script.js
Normal file
41
amqp_dashboard/assets/script.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
const renderTable = (colNames, rows) => {
|
||||
const table = document.createElement("table");
|
||||
|
||||
const headerRow = document.createElement("tr");
|
||||
|
||||
colNames.forEach((name) => {
|
||||
const th = document.createElement("th");
|
||||
th.innerText = name;
|
||||
|
||||
headerRow.append(th);
|
||||
});
|
||||
table.append(headerRow);
|
||||
|
||||
rows.forEach((row) => {
|
||||
const contentRow = document.createElement("tr");
|
||||
row.forEach((cell) => {
|
||||
const td = document.createElement("td");
|
||||
td.innerText = cell;
|
||||
contentRow.append(td);
|
||||
});
|
||||
table.append(contentRow);
|
||||
})
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
const renderConnections = (connections) => {
|
||||
const wrapper = document.getElementById("connection-wrapper");
|
||||
|
||||
const table = renderTable(['Connection ID', 'Client Address'], connections.map((conn) =>
|
||||
[conn.id, conn.peer_addr]));
|
||||
wrapper.replaceChildren(table)
|
||||
}
|
||||
|
||||
const refresh = async () => {
|
||||
const fetched = await fetch('http://localhost:3000/api/data');
|
||||
const data = await fetched.json();
|
||||
renderConnections(data.connections);
|
||||
}
|
||||
|
||||
setInterval(refresh, 1000);
|
||||
10
amqp_dashboard/assets/style.css
Normal file
10
amqp_dashboard/assets/style.css
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
html {
|
||||
font-family: arial, sans-serif;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
padding: 10px;
|
||||
}
|
||||
78
amqp_dashboard/src/lib.rs
Normal file
78
amqp_dashboard/src/lib.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
use amqp_core::GlobalData;
|
||||
use axum::body::{boxed, Full};
|
||||
use axum::response::{Html, IntoResponse, Response};
|
||||
use axum::routing::get;
|
||||
use axum::{Json, Router};
|
||||
use serde::Serialize;
|
||||
use tracing::info;
|
||||
|
||||
const INDEX_HTML: &str = include_str!("../assets/index.html");
|
||||
const SCRIPT_JS: &str = include_str!("../assets/script.js");
|
||||
const STYLE_CSS: &str = include_str!("../assets/style.css");
|
||||
|
||||
pub async fn dashboard(global_data: GlobalData) {
|
||||
let app = Router::new()
|
||||
.route("/", get(get_index_html))
|
||||
.route("/script.js", get(get_script_js))
|
||||
.route("/style.css", get(get_style_css))
|
||||
.route("/api/data", get(move || get_data(global_data)));
|
||||
|
||||
let socket_addr = "0.0.0.0:3000".parse().unwrap();
|
||||
|
||||
info!(%socket_addr, "Starting up dashboard on address");
|
||||
|
||||
axum::Server::bind(&socket_addr)
|
||||
.serve(app.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
async fn get_index_html() -> impl IntoResponse {
|
||||
info!("Requesting index.html");
|
||||
Html(INDEX_HTML)
|
||||
}
|
||||
|
||||
async fn get_script_js() -> Response {
|
||||
Response::builder()
|
||||
.header("content-type", "application/javascript")
|
||||
.body(boxed(Full::from(SCRIPT_JS)))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
async fn get_style_css() -> Response {
|
||||
Response::builder()
|
||||
.header("content-type", "text/css")
|
||||
.body(boxed(Full::from(STYLE_CSS)))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Data {
|
||||
connections: Vec<Connection>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Connection {
|
||||
id: String,
|
||||
peer_addr: String,
|
||||
}
|
||||
|
||||
async fn get_data(global_data: GlobalData) -> impl IntoResponse {
|
||||
let global_data = global_data.lock();
|
||||
|
||||
let connections = global_data
|
||||
.connections
|
||||
.values()
|
||||
.map(|conn| {
|
||||
let conn = conn.lock();
|
||||
Connection {
|
||||
id: conn.id.to_string(),
|
||||
peer_addr: conn.peer_addr.to_string(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let data = Data { connections };
|
||||
|
||||
Json(data)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue