1.4. Rust JavaScript Einbindung
async fn get_mjs() -> impl IntoResponse {
Response::builder()
.header("content-type", "application/javascript;charset=utf-8")
.body(tokio::fs::read_to_string("src/index.mjs").await.unwrap())
.unwrap()
}
Der Code definiert eine asynchrone Funktion mit dem Namen get_mjs()
, die ein
impl IntoResponse
-Objekt zurückgibt. Der IntoResponse
-Trait ermöglicht es, einen Typen in
einen HTTP-Response-Typen zu konvertieren, den der Webserver senden kann.
Im professionellen betrieb sollte impl IntoResponse
vermieden werden, da die
Fehlerbehandlung schnell unübersichtlich werden kann.
Da wir unser Projekt in kleinem Rahmen halten, ist es in Ordnung diese Methodik anzuwenden.
In der Funktion wird zuerst ein ResponseBuilder
-Objekt erstellt, das eine
content-type
-Headerzeile mit dem MIME-Typ application/javascript
und Zeichensatz utf-8
enthält.
Anschließend wird der Inhalt der Datei src/index.mjs
asynchron aus dem Dateisystem gelesen
und als Body der HTTP-Responses festgelegt.
Schließlich wird die vollständige HTTP-Response mit unwrap()
zurückgegeben.
Wenn das Lesen der Datei fehlschlägt, wird eine panic!()
-Meldung ausgegeben.
An dieser Stelle könnte man den Quellcode durch besseres Error-Handling verbessern, da
panics
im Nutzergebrauch in der Regel nicht zu hilfreicher Fehlerbehandlung führen.
Das Skript in src/index.mjs
zur Beschreibung:
import { h, render } from "https://unpkg.com/preact?module"; // Import Preact
import htm from "https://unpkg.com/htm?module"; // Import htm
const html = htm.bind(h);
// Render CPU Stats
function CpuStats(props) {
return html`
${props.cpus.map((cpu, index) => {
// Create a Graph for every CPU
return html`
<div class="full">
<div class="free" style="height: ${100-cpu.toFixed(2)}%"><div class="core-sign">Core ${index}</div></div>
<div class="busy" style="height: ${cpu}%"></div>
<div class="sign">${cpu.toFixed(2)}%</div>
</div>
`;
})}
`;
}
// Render Memory Usage
function MemStats(props) {
// Create the Memory Graph
return html`
<div style='text-align: center; font-size: 25px;color: red;'>
Total Memory: ${(props.memory["totalMemory"]/1000000).toFixed(0)} Mb
</div>
<div style='background-color:yellow; height: 50px; width: 100%'>
<div style='background-color:green; height: 50px; width: ${(props.memory["usedMemory"]/props.memory["totalMemory"]*100).toFixed(2)}%'></div>
</div>
<div style='display: flex;justify-content: space-between;'>
<div style="font-size: 25px;color: blue;">
Used Memory: ${(props.memory["usedMemory"]/1000000).toFixed(0)} Mb
</div>
<div style="font-size: 25px;color: blue;">
Free Memory: ${((props.memory["totalMemory"]-props.memory["usedMemory"])/1000000).toFixed(0)} Mb
</div>
</div>
`;
}
// Update the page
let update = async () => {
let response = await fetch("/rest/cpu");
let cpujson = await response.json();
render(html`<${CpuStats} cpus=${cpujson}></${CpuStats}>`, document.getElementById("cpu_stats"))
response = await fetch("/rest/memory");
let memoryjson = await response.json();
render(html`<${MemStats} memory=${memoryjson}></${MemStats}>`, document.getElementById("mem_stats"))
}
update()
// Update the page every 200ms.
// This could be improved by using a sender-receiver architecture
// using a websocket.
// Unfortunately, time is precious in this project and this method will do.
setInterval(update, 200);
Dieser Code verwendet die Bibliotheken preact
und htm und definiert eine Funktionen CpuStats
und
MemStats
, die eine Liste von Memory- und CPU-Auslastungswerten als Eingabe erhält und eine
HTML-Darstellung dieser Werte erstellt.
Die Funktion update
ruft die REST endpunkte vom Server ab und benutztz die eben genannten
Funktionen, um die HTML-Darstellung zu erstellen.
Die setInterval
-Funktion ruft die “update” -Funktion alle 200 Millisekunden auf, um die
CPU-Auslastung zu aktualisieren.
Die “console.log” -Anweisung dient lediglich zur Ausgabe einer Meldung in der Browserkonsole.
Wie im Code Beispiel schon genannt, ist setInterval
nicht die optimale Lösung in dieser
situation, da die Werte von Hand abgefragt werden müssen.
Eine elegantere Methode wäre die Verwendung eines Web Sockets, der die Seite wenn neue CPU
Werte vorliegen, aktualisiert.
Die HTML Seite zum eben genannten Javascript code ist kurz und beinhaltet nur die statischen Elemente, wie Überschrift, Hilfetext und Header.
<!DOCTYPE html>
<html lang="de">
<head>
<title>Webserver</title>
<script type="module" src="/index.mjs"></script>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1 class="title">Computer Statistics</h1>
<div style="font-size:23px">
<p style="font-size:23px">On this page you can get up-to-date information about the performance of your system.
<br> Use this information to monitor performance and resources.</p>
</div>
<h2>CPU</h2>
<div class="container" id="cpu_stats">
</div>
<div style="margin-top:100px;">
<h2>Memory</h2>
<div id="mem_stats">
</div>
</div>
</body>
</html>