Compare commits
3 Commits
04deb1d89c
...
2aedf86736
Author | SHA1 | Date | |
---|---|---|---|
2aedf86736 | |||
e609cb0f44 | |||
75c12677d9 |
16
build.rs
16
build.rs
@ -2,9 +2,10 @@ fn main() {
|
||||
#[cfg(feature = "debug_server")]
|
||||
pack_debug_page().unwrap();
|
||||
|
||||
println!("cargo:rerun-if-changed=main.js");
|
||||
println!("cargo:rerun-if-changed=index.html");
|
||||
println!("cargo:rerun-if-changed=main.css");
|
||||
println!("cargo:rerun-if-changed=web/main.js");
|
||||
println!("cargo:rerun-if-changed=web/index.html");
|
||||
println!("cargo:rerun-if-changed=web/main.css");
|
||||
println!("cargo:rerun-if-changed=web/connected.svg");
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug_server")]
|
||||
@ -17,6 +18,7 @@ fn pack_debug_page() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let js = std::fs::read_to_string("web/main.js").unwrap();
|
||||
let html = std::fs::read_to_string("web/index.html").unwrap();
|
||||
let css = std::fs::read_to_string("web/main.css").unwrap();
|
||||
let svg = std::fs::read_to_string("web/connected.svg").unwrap();
|
||||
|
||||
let mut out = Vec::new();
|
||||
minify_js::minify(
|
||||
@ -30,9 +32,15 @@ fn pack_debug_page() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let css = Minifier::default().minify(&css, Level::Three).unwrap();
|
||||
|
||||
let (start, end) = html
|
||||
.split_once("<!--INSERT SVG HERE-->")
|
||||
.expect("did not find svg split point in html");
|
||||
|
||||
let html = format!("{start}{svg}{end}");
|
||||
|
||||
let (head, body) = html
|
||||
.split_once("<!--INSERT HEAD CONTENT HERE-->")
|
||||
.expect("did not find split point in html");
|
||||
.expect("did not find head split point in html");
|
||||
|
||||
let html = minify_html::minify(
|
||||
format!("{head}<style>{css}</style><script>{js}</script>{body}").as_bytes(),
|
||||
|
13
src/ports.rs
13
src/ports.rs
@ -21,7 +21,7 @@ use tracing::{debug, error, info, instrument, warn};
|
||||
|
||||
use crate::{
|
||||
constants::{CACHE_STORE_INTERVAL, PORT_OWNERSHIP_TIMEOUT, PORT_RETRY_TIME},
|
||||
packets::{Packet, PacketKind},
|
||||
packets::Packet,
|
||||
spawn, Config, Number, Port, UnixTimestamp,
|
||||
};
|
||||
|
||||
@ -302,17 +302,10 @@ impl Serialize for Rejector {
|
||||
S: Serializer,
|
||||
{
|
||||
let packet = &self.state.1;
|
||||
let kind = match packet.kind() {
|
||||
PacketKind::End => "end",
|
||||
PacketKind::Reject => "reject",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
match packet.as_string() {
|
||||
Some(string) if string.chars().all(|c| !c.is_control()) => {
|
||||
(kind, string).serialize(serializer)
|
||||
}
|
||||
_ => (kind, packet.data()).serialize(serializer),
|
||||
Some(string) if string.chars().all(|c| !c.is_control()) => string.serialize(serializer),
|
||||
_ => packet.data().serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1
web/connected.svg
Normal file
1
web/connected.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg><g transform="translate(-38.3 -51.4)"><path d="m98.8 55.1-6.52 6.52-3.78-3.78 6.52-6.52zm-7.49 20.5-8.5 8.5-16.8-16.8 8.5-8.5zm-16.9 0.0741a11.9 11.9 45 0 1 0.0256-16.8 11.9 11.9 45 0 1 16.8-0.0256 11.9 11.9 45 0 1-0.0256 16.8 11.9 11.9 45 0 1-16.8 0.0256zm-36.2 32.6 6.52-6.52 3.78 3.78-6.52 6.52zm19.7-25.3 8.39-8.39 1.88 1.88-8.39 8.39zm7.46 7.5 8.39-8.39 1.88 1.88-8.39 8.39zm-19.7-2.72 8.5-8.5 16.8 16.8-8.5 8.5zm16.9-0.0741a11.9 11.9 45 0 1-0.0256 16.8 11.9 11.9 45 0 1-16.8 0.0256 11.9 11.9 45 0 1 0.0256-16.8 11.9 11.9 45 0 1 16.8-0.0256z"/></g></svg>
|
After Width: | Height: | Size: 564 B |
@ -2,6 +2,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<link rel="icon" href="data:,">
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<title>Centralex State</title>
|
||||
@ -9,10 +10,22 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<p id="free_ports" />
|
||||
<div id="connected_box">
|
||||
<div id="connected" class="hidden"><!--INSERT SVG HERE--></div>
|
||||
<p id="last_update" />
|
||||
<pre id="data"></pre>
|
||||
<list id="list" />
|
||||
</div>
|
||||
|
||||
<table id="table">
|
||||
<tr>
|
||||
<th>Nummer</th>
|
||||
<th>Port</th>
|
||||
<th>Zustand</th>
|
||||
<th>Name</th>
|
||||
<th>Meldung</th>
|
||||
<th>Letzte Änderung</th>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
37
web/main.css
37
web/main.css
@ -1,3 +1,40 @@
|
||||
body {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
#connected_box {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
right: 5%;
|
||||
width: 5%;
|
||||
height: 5%;
|
||||
}
|
||||
|
||||
|
||||
td,
|
||||
th {
|
||||
border: 1px solid black;
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.number {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.visible {
|
||||
opacity: 1;
|
||||
transition: opacity 500ms linear;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
opacity: 0.2;
|
||||
transition: opacity 6000ms linear;
|
||||
}
|
133
web/main.js
133
web/main.js
@ -1,28 +1,127 @@
|
||||
window.onload = () => {
|
||||
const evtSource = new EventSource("/events");
|
||||
const data = document.getElementById("data");
|
||||
const table_elem = document.getElementById("table");
|
||||
const last_update = document.getElementById("last_update");
|
||||
const connected = document.getElementById("connected");
|
||||
const free_ports = document.getElementById("free_ports");
|
||||
|
||||
const timeout_duration = 10*1000;
|
||||
const retry_timeout = 5*1000;
|
||||
|
||||
let reconnect_timeout;
|
||||
let ping_timeout;
|
||||
let evtSource;
|
||||
let table = [];
|
||||
|
||||
let format_date = date => date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
|
||||
|
||||
let print_table = () => {
|
||||
while(table_elem.children.length > 1) {
|
||||
table_elem.removeChild(table_elem.lastChild);
|
||||
}
|
||||
|
||||
for (let row of table) {
|
||||
|
||||
let tr = document.createElement("tr");
|
||||
|
||||
let values = [
|
||||
row.number,
|
||||
row.port,
|
||||
row.status,
|
||||
row.name || "?",
|
||||
row.rejector || "",
|
||||
format_date(row.last_change)
|
||||
];
|
||||
|
||||
for(let value of values) {
|
||||
let td = document.createElement("td");
|
||||
td.innerText = value;
|
||||
td.className = Number.isInteger(value) ? "number" : "text";
|
||||
tr.appendChild(td);
|
||||
}
|
||||
|
||||
table_elem.appendChild(tr)
|
||||
}
|
||||
};
|
||||
|
||||
let update_table = data => {
|
||||
console.log(data);
|
||||
|
||||
const allowed_ports = data.allowed_ports.map(x => x.end - x.start + 1).reduce((a,b) => a + b, 0);
|
||||
free_ports.innerText = `Freie Ports: ${allowed_ports - Object.keys(data.allocated_ports).length - data.errored_ports.length}`;
|
||||
|
||||
|
||||
table = [];
|
||||
|
||||
for(let number in data.allocated_ports) {
|
||||
let port = data.allocated_ports[number];
|
||||
number = +number;
|
||||
let {status, last_change} = data.port_state[port];
|
||||
|
||||
let rejector = data.rejectors[port] || null;
|
||||
|
||||
if (rejector && rejector instanceof Array) {
|
||||
rejector = rejector.map(x => "0x"+x.toString(16).padStart(2, 0)).join(" ")
|
||||
}
|
||||
|
||||
last_change = new Date(last_change * 1000);
|
||||
|
||||
let name = data.names[number] || null;
|
||||
|
||||
switch(status) {
|
||||
case "disconnected":
|
||||
status = "getrennt";
|
||||
break;
|
||||
case "idle":
|
||||
status = "bereit";
|
||||
break;
|
||||
case "in_call":
|
||||
status = "anruf";
|
||||
break;
|
||||
}
|
||||
|
||||
table.push({port, number, status, last_change, rejector, name})
|
||||
}
|
||||
|
||||
console.log(table);
|
||||
|
||||
print_table();
|
||||
};
|
||||
|
||||
let connect_event_source = () => {
|
||||
|
||||
clearTimeout(reconnect_timeout);
|
||||
clearTimeout(ping_timeout);
|
||||
ping_timeout = setTimeout(connect_event_source, timeout_duration);
|
||||
|
||||
evtSource && evtSource.close && evtSource.close();
|
||||
|
||||
evtSource = new EventSource("/events");
|
||||
evtSource.addEventListener("change", event => {
|
||||
console.log(event);
|
||||
last_update.innerText = `Letzte Änderung: ${format_date(new Date(+event.data * 1000))}`;
|
||||
|
||||
last_update.innerText = `last update at ${new Date(+event.data * 1000)}`;
|
||||
|
||||
const newElement = document.createElement("li");
|
||||
const eventList = document.getElementById("list");
|
||||
newElement.textContent = `change at ${+event.data}`;
|
||||
eventList.appendChild(newElement);
|
||||
|
||||
fetch("/data").then(res => res.json().then(res => data.innerText = JSON.stringify(res, null, 1)));
|
||||
fetch("/data")
|
||||
.then(res => res.json())
|
||||
.then(update_table);
|
||||
});
|
||||
|
||||
evtSource.addEventListener("ping", event => {
|
||||
console.log(event);
|
||||
clearTimeout(ping_timeout);
|
||||
ping_timeout = setTimeout(connect_event_source, timeout_duration);
|
||||
|
||||
last_update.innerText = `last update at ${new Date(+event.data * 1000)}`;
|
||||
|
||||
const newElement = document.createElement("li");
|
||||
const eventList = document.getElementById("list");
|
||||
newElement.textContent = `ping at ${+event.data}`;
|
||||
eventList.appendChild(newElement);
|
||||
last_update.innerText = `Letzte Änderung: ${format_date(new Date(+event.data * 1000))}`;
|
||||
connected.className = "visible";
|
||||
setTimeout(() => connected.className = "hidden", 1000);
|
||||
});
|
||||
|
||||
|
||||
evtSource.onerror = () => {
|
||||
clearTimeout(reconnect_timeout);
|
||||
reconnect_timeout = setTimeout(connect_event_source, retry_timeout);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
connect_event_source();
|
||||
|
||||
};
|
Loading…
Reference in New Issue
Block a user