Lot 8 : téléchargements de modèles tenus par la façade (LOKI_DOWNLOADS=rust)

La façade Rust mène les téléchargements de .gguf quand LOKI_DOWNLOADS=rust
(expérimental ; le Go reste le défaut) : sonde, lancement, suivi,
annulation, avec les mêmes contrats et la même mécanique que le Go
(tranches rapatriées en entier, plages d'octets parallèles, reprise, place
disque vérifiée sur le total, jeton réservé aux hôtes Hugging Face, refus
traduits, .part vidés au démarrage).

Côté Go : facade_downloads.go remet ces routes à la façade quand elles
arrivent par le tunnel du relais, et le Go ne vide plus les .part qu'elle
mène.

Parité : journal des fonctions pures tiré du Go (parity_dl_test.go) et
rejoué en Rust ; téléchargements de bout en bout contre un faux Hugging
Face (tests/downloads.rs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
Claude committed 2026-10-15 13:11:07 +00:00
1 parent 98196e1730
commit bbea5fcd3f
20 files changed
+2820 -17

No files matched your search

+15 -8
View File
@@ -141,23 +141,30 @@ var facadeChatRoutes = map[string]bool{
}
// withFacadeChat remet la requête à la façade quand elle tient la
// conversation. Posé APRÈS requireWebAuth : seule une requête authentifiée
// ici part, avec le jeton interne qui en tient lieu là-bas.
// conversation — ou les téléchargements de modèles (facade_downloads.go).
// Posé APRÈS requireWebAuth : seule une requête authentifiée ici part, avec le
// jeton interne qui en tient lieu là-bas.
func withFacadeChat(path string, h http.HandlerFunc) http.HandlerFunc {
if !facadeChatRoutes[path] {
held, unavailable := facadeChat, "conversation indisponible : "
switch {
case facadeChatRoutes[path]:
case facadeDownloadRoutes[path]:
held, unavailable = facadeDownloads, "téléchargements indisponibles : "
default:
return h
}
return func(w http.ResponseWriter, r *http.Request) {
if !facadeChat() {
if !held() {
h(w, r)
return
}
facadeRelay(w, r)
facadeRelayAs(w, r, unavailable)
}
}
// facadeRelay : relais transparent (flux compris) vers la façade.
func facadeRelay(w http.ResponseWriter, r *http.Request) {
// facadeRelayAs : relais transparent (flux compris) vers la façade ;
// unavailable préfixe l'erreur si elle ne répond pas.
func facadeRelayAs(w http.ResponseWriter, r *http.Request, unavailable string) {
rp := &httputil.ReverseProxy{
Rewrite: func(pr *httputil.ProxyRequest) {
pr.SetURL(&url.URL{Scheme: "http", Host: facadeAddr()})
@@ -165,7 +172,7 @@ func facadeRelay(w http.ResponseWriter, r *http.Request) {
},
FlushInterval: -1, // SSE : chaque trame part aussitôt
ErrorHandler: func(w http.ResponseWriter, _ *http.Request, err error) {
sendJSON(w, http.StatusBadGateway, map[string]any{"ok": false, "error": "conversation indisponible : " + err.Error()})
sendJSON(w, http.StatusBadGateway, map[string]any{"ok": false, "error": unavailable + err.Error()})
},
}
rp.ServeHTTP(w, r)