mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-16 19:59:56 +02:00
La façade sert /api/internet (moteur web, serveur Crawl4AI et sa clé jamais rendue, joignabilité avec son cache de 30 s), /api/computer (interrupteur du navigateur, binaire trouvé, vision), /api/apikey (clé de complétion, repli sur config.env, adresse /v1 à coller dans un client tiers) et /api/network (écoute du moteur) quand LOKI_SYSTEM=rust (expérimental ; le Go reste le défaut). Restent au Go derrière son API interne (facade_system.go) : le cache de joignabilité de ses outils web (/internal/v1/web/reach/reset), le Chromium des outils browser_* (/internal/v1/cdp/shutdown) et le redémarrage qui applique une clé neuve quand la façade ne pilote pas le moteur (/internal/v1/service/action). Le relais du tunnel garde l'hôte et X-Forwarded-Proto du client. Correction en passant : maskAPIKey paniquait sur une clé d'un octet, et /api/apikey tombait à chaque lecture. Parité : parity_system_test.go tire du Go 61 appels de route avec la base et les sondes reçues par trois faux Crawl4AI après chacun, et huit dispositions du dossier de Playwright, rejoués par tests/system.rs ; ce qui reste au Go vérifié de bout en bout ; TestFacadeSysteme, TestFacadeRelaisGardeHote et TestMaskAPIKeyCourte côté Go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
99 lines
3.3 KiB
Go
99 lines
3.3 KiB
Go
package loki
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// facade_system.go — interrupteurs système tenus par la façade Rust
|
|
// (LOKI_SYSTEM=rust, lot 17 de la migration ; expérimental, le Go reste le
|
|
// défaut) : accès internet (/api/internet), pilotage du navigateur
|
|
// (/api/computer), clé de complétion (/api/apikey) et écoute réseau du moteur
|
|
// (/api/network).
|
|
//
|
|
// Les réglages restent des clés de la base. Ce qui vit dans ce processus reste
|
|
// ici, derrière l'API interne :
|
|
//
|
|
// - le cache de joignabilité de Crawl4AI des outils web, vidé quand l'URL, la
|
|
// clé ou le moteur changent (/internal/v1/web/reach/reset) ;
|
|
// - le Chromium piloté par les outils browser_*, fermé quand l'interrupteur
|
|
// se coupe (/internal/v1/cdp/shutdown) ;
|
|
// - le redémarrage du moteur qui applique une nouvelle clé, quand la façade
|
|
// ne pilote pas le moteur (/internal/v1/service/action).
|
|
|
|
const facadeSystemEnv = "LOKI_SYSTEM"
|
|
|
|
// facadeSystem : la façade tient-elle les interrupteurs système ?
|
|
func facadeSystem() bool {
|
|
return strings.EqualFold(strings.TrimSpace(os.Getenv(facadeSystemEnv)), "rust") &&
|
|
facadeAddr() != "" && internalToken() != ""
|
|
}
|
|
|
|
// facadeSystemRoutes : les routes que la façade sert alors (system.rs).
|
|
var facadeSystemRoutes = map[string]bool{
|
|
"/api/internet": true,
|
|
"/api/computer": true,
|
|
"/api/apikey": true,
|
|
"/api/network": true,
|
|
}
|
|
|
|
// handleInternalReachReset : POST → 204 — le prochain tour reteste Crawl4AI.
|
|
func handleInternalReachReset(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
sendJSON(w, http.StatusMethodNotAllowed, map[string]any{"error": "POST attendu"})
|
|
return
|
|
}
|
|
reachMu.Lock()
|
|
reachURL = ""
|
|
reachMu.Unlock()
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// handleInternalCDPShutdown : POST → 204 — ferme le navigateur piloté.
|
|
func handleInternalCDPShutdown(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
sendJSON(w, http.StatusMethodNotAllowed, map[string]any{"error": "POST attendu"})
|
|
return
|
|
}
|
|
cdpShutdown()
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// internalServiceAction : serviceAction, variable pour les tests.
|
|
var internalServiceAction = serviceAction
|
|
|
|
// handleInternalServiceAction : POST {action, if_active} → 200 {ran, error}.
|
|
// if_active : seulement si le moteur tourne (une clé neuve ne s'applique qu'au
|
|
// redémarrage, inutile de démarrer un moteur arrêté pour elle).
|
|
func handleInternalServiceAction(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
sendJSON(w, http.StatusMethodNotAllowed, map[string]any{"error": "POST attendu"})
|
|
return
|
|
}
|
|
var in struct {
|
|
Action string `json:"action"`
|
|
IfActive bool `json:"if_active"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
|
|
sendJSON(w, http.StatusBadRequest, map[string]any{"error": err.Error()})
|
|
return
|
|
}
|
|
switch in.Action {
|
|
case "start", "stop", "restart":
|
|
default:
|
|
sendJSON(w, http.StatusBadRequest, map[string]any{"error": "action inconnue : " + in.Action})
|
|
return
|
|
}
|
|
if in.IfActive && !serviceIsActive() {
|
|
sendJSON(w, http.StatusOK, map[string]any{"ran": false, "error": ""})
|
|
return
|
|
}
|
|
msg := ""
|
|
if err := internalServiceAction(in.Action); err != nil {
|
|
msg = err.Error()
|
|
}
|
|
sendJSON(w, http.StatusOK, map[string]any{"ran": true, "error": msg})
|
|
}
|