From b98ee5c3e77467730603f5b2be1fba252f9a6cc8 Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Wed, 14 Oct 2026 17:48:58 +0200 Subject: [PATCH] Lot 4 : /api/ram et /api/vram servis par Rust MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- rust/loki-rs/src/api.rs | 22 +++++++++++++++++++++- rust/loki-rs/tests/lot4.rs | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/rust/loki-rs/src/api.rs b/rust/loki-rs/src/api.rs index f47f1d7..54578fb 100644 --- a/rust/loki-rs/src/api.rs +++ b/rust/loki-rs/src/api.rs @@ -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) -> Response { @@ -65,6 +69,22 @@ pub async fn serve(ctx: &Ctx, req: Request) -> Response { 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(), } } diff --git a/rust/loki-rs/tests/lot4.rs b/rust/loki-rs/tests/lot4.rs index 4428e96..1db13b9 100644 --- a/rust/loki-rs/tests/lot4.rs +++ b/rust/loki-rs/tests/lot4.rs @@ -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()); +}