package main import ( "bufio" "encoding/json" "fmt" "io" "log" "net" "net/http" "strings" ) // Configuration const ( TargetTCPAddr = "127.0.0.1:9011" WebPort = ":8088" ) type APIRequest struct { Command string `json:"command"` Args []string `json:"args"` } type APIResponse struct { Status string `json:"status"` Data any `json:"data,omitempty"` Error string `json:"error,omitempty"` } func main() { // Serve static files (HTML) http.HandleFunc("/", handleIndex) // API Endpoint http.HandleFunc("/api/proxy", handleAPI) fmt.Printf("Web Admin started at http://localhost%s\n", WebPort) log.Fatal(http.ListenAndServe(WebPort, nil)) } func handleIndex(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } // Serve the embedded HTML directly http.ServeFile(w, r, "example/web_admin/index.html") } func handleAPI(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } // 1. Parse Request body, _ := io.ReadAll(r.Body) var req APIRequest if err := json.Unmarshal(body, &req); err != nil { jsonResponse(w, APIResponse{Status: "error", Error: "Invalid JSON"}) return } // 2. Get Token from Header token := r.Header.Get("X-Session-Token") // 3. Connect to TCP conn, err := net.Dial("tcp", TargetTCPAddr) if err != nil { jsonResponse(w, APIResponse{Status: "error", Error: "Connection failed: " + err.Error()}) return } defer conn.Close() reader := bufio.NewReader(conn) // 4. Authenticate if token present (Except for LOGIN command itself) if req.Command != "LOGIN" && token != "" { fmt.Fprintf(conn, "AUTH %s\n", token) authResp, _ := reader.ReadString('\n') if !strings.HasPrefix(authResp, "OK") { jsonResponse(w, APIResponse{Status: "error", Error: "Session Expired"}) return } } // 5. Construct TCP Command // Escape args if necessary (simple space joining for now) cmdStr := req.Command if len(req.Args) > 0 { cmdStr += " " + strings.Join(req.Args, " ") } fmt.Fprintf(conn, "%s\n", cmdStr) // 6. Read TCP Response respStr, _ := reader.ReadString('\n') respStr = strings.TrimSpace(respStr) // 7. Parse Response if strings.HasPrefix(respStr, "OK") { // Extract potential data payload payload := strings.TrimPrefix(respStr, "OK ") // If payload looks like JSON, try to parse it var jsonData any if strings.HasPrefix(payload, "[") || strings.HasPrefix(payload, "{") { if err := json.Unmarshal([]byte(payload), &jsonData); err == nil { jsonResponse(w, APIResponse{Status: "ok", Data: jsonData}) return } } // Otherwise return as string jsonResponse(w, APIResponse{Status: "ok", Data: payload}) } else if strings.HasPrefix(respStr, "ERR") { errMsg := strings.TrimPrefix(respStr, "ERR ") jsonResponse(w, APIResponse{Status: "error", Error: errMsg}) } else { jsonResponse(w, APIResponse{Status: "error", Error: "Unknown response: " + respStr}) } } func jsonResponse(w http.ResponseWriter, resp APIResponse) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(resp) }