Lot 4 : /api/ram et /api/vram servis par Rust

RAM lue dans /proc/meminfo, jauges des cartes par un seul nvidia-smi
partagé entre tous les onglets (cache de deux secondes, une minute quand
nvidia-smi est absent), comme le Go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5.5 committed 2026-10-14 17:48:58 +02:00
1 parent dc6a001581
commit b98ee5c3e7
2 files changed
+36 -1

No files matched your search

+21 -1
View File
@@ -14,6 +14,7 @@ use crate::auth::{self, HostEnv, InternalClient};
use crate::engine;
use crate::proxy::Body;
use crate::store::{BK_STATE, Store};
use crate::sysinfo;
use std::collections::BTreeMap;
/// Ce dont les routes ont besoin, partagé par toutes les connexions.
@@ -39,7 +40,10 @@ impl Ctx {
/// Cette route est-elle servie par Rust ?
pub fn handles(_method: &Method, path: &str) -> bool {
matches!(path, "/api/ping" | "/api/config" | "/api/engine/cmdline")
matches!(
path,
"/api/ping" | "/api/config" | "/api/engine/cmdline" | "/api/ram" | "/api/vram"
)
}
pub async fn serve(ctx: &Ctx, req: Request<Incoming>) -> Response<Body> {
@@ -65,6 +69,22 @@ pub async fn serve(ctx: &Ctx, req: Request<Incoming>) -> Response<Body> {
let cmdline = ctx.store.get_str(BK_STATE, "engine_cmdline").await;
auth::json(StatusCode::OK, &json!({ "ok": true, "cmdline": cmdline }))
}
// RAM système en Mo (total = 0 : l'UI masque le bloc).
"/api/ram" => {
let (used, total) = sysinfo::ram_usage_mb();
auth::json(StatusCode::OK, &json!({ "used": used, "total": total }))
}
// Jauges des cartes : un seul nvidia-smi partagé par tous les onglets.
"/api/vram" => {
let gpus: Vec<_> = sysinfo::gpu_stats_cached()
.await
.into_iter()
.map(|g| {
json!({ "name": g.name, "used": g.used, "total": g.total, "util": g.util, "temp": g.temp })
})
.collect();
auth::json(StatusCode::OK, &json!(gpus))
}
_ => not_found(),
}
}
+15
View File
@@ -65,3 +65,18 @@ async fn routes_portees_protegees_par_la_cle() {
assert_eq!(code, StatusCode::OK, "{path}");
}
}
#[tokio::test]
async fn ram_et_vram() {
let t = tempfile::tempdir().unwrap();
let (f, go, _stop) = fakego::start(t.path().into()).await;
let (code, _, body) = fakego::get(f, "/api/ram", &[]).await;
assert_eq!(code, StatusCode::OK);
let v: serde_json::Value = serde_json::from_slice(&body).unwrap();
assert!(v["used"].is_i64() && v["total"].is_i64(), "{v}");
let (code, _, body) = fakego::get(f, "/api/vram", &[]).await;
assert_eq!(code, StatusCode::OK);
let v: serde_json::Value = serde_json::from_slice(&body).unwrap();
assert!(v.is_array(), "{v}");
assert!(go.relayed.lock().unwrap().is_empty());
}