1 Agent HTTP
GnomeZworc edited this page 2025-04-24 14:16:31 +02:00

Async http server

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "time"
)

// ----------- Types JSON-RPC -----------

type JSONRPCRequest struct {
    JSONRPC string          `json:"jsonrpc"`
    Method  string          `json:"method"`
    Params  json.RawMessage `json:"params"`
    ID      interface{}     `json:"id"`
}

type JSONRPCResponse struct {
    JSONRPC string      `json:"jsonrpc"`
    Result  interface{} `json:"result,omitempty"`
    Error   interface{} `json:"error,omitempty"`
    ID      interface{} `json:"id"`
}

type Task struct {
    Method string
    Params json.RawMessage
    ID     interface{}
}

// ----------- Routine d'exécution -----------

func execRoutine(taskQueue <-chan Task, resultChan chan<- JSONRPCResponse) {
    for task := range taskQueue {
        var result interface{}
        var err error

        switch task.Method {
        case "StartVM":
            result, err = handleStartVM(task.Params)
        case "StopVM":
            result, err = handleStopVM(task.Params)
        case "AttachDisk":
            result, err = handleAttachDisk(task.Params)
        case "RestoreVMs":
            result, err = handleRestoreVMs()
        default:
            err = fmt.Errorf("méthode inconnue : %s", task.Method)
        }

        res := JSONRPCResponse{
            JSONRPC: "2.0",
            ID:      task.ID,
        }

        if err != nil {
            res.Error = map[string]interface{}{
                "code":    -32601,
                "message": err.Error(),
            }
        } else {
            res.Result = result
        }

        resultChan <- res
    }
}

// ----------- Fonctions simulées -----------

func handleStartVM(params json.RawMessage) (string, error) {
    var args []string
    if err := json.Unmarshal(params, &args); err != nil {
        return "", err
    }
    log.Println("→ StartVM", args)
    return "VM démarrée : " + fmt.Sprint(args), nil
}

func handleStopVM(params json.RawMessage) (string, error) {
    var args []string
    if err := json.Unmarshal(params, &args); err != nil {
        return "", err
    }
    log.Println("→ StopVM", args)
    return "VM arrêtée : " + fmt.Sprint(args), nil
}

func handleAttachDisk(params json.RawMessage) (string, error) {
    var args []string
    if err := json.Unmarshal(params, &args); err != nil {
        return "", err
    }
    log.Println("→ AttachDisk", args)
    return "Disque attaché : " + fmt.Sprint(args), nil
}

func handleRestoreVMs() (string, error) {
    log.Println("→ RestoreVMs")
    return "VMs restaurées", nil
}

// ----------- Serveur JSON-RPC -----------

func rpcHandler(taskQueue chan<- Task, resultChan <-chan JSONRPCResponse) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if r.Method != http.MethodPost {
            http.Error(w, "Méthode non autorisée", http.StatusMethodNotAllowed)
            return
        }

        body, err := io.ReadAll(r.Body)
        if err != nil {
            http.Error(w, "Erreur lecture corps", http.StatusBadRequest)
            return
        }

        var req JSONRPCRequest
        if err := json.Unmarshal(body, &req); err != nil {
            http.Error(w, "JSON invalide", http.StatusBadRequest)
            return
        }

        taskQueue <- Task{
            Method: req.Method,
            Params: req.Params,
            ID:     req.ID,
        }

        res := <-resultChan

        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(res)
    }
}

// ----------- Main -----------

func main() {
    log.Println("== Agent Go JSON-RPC ==")

    taskQueue := make(chan Task, 100)
    resultChan := make(chan JSONRPCResponse, 100)

    go execRoutine(taskQueue, resultChan)

    http.HandleFunc("/rpc", rpcHandler(taskQueue, resultChan))


    go func() {
        log.Println("Serveur JSON-RPC sur :8080")
        log.Fatal(http.ListenAndServe(":8080", nil))
    }()

    for {
        time.Sleep(1 * time.Hour)
    }
}