package handlers import ( "docker-manager/docker" "encoding/json" "fmt" "io" "net/http" ) func ListContainersHandler(w http.ResponseWriter, r *http.Request, client *docker.Client) { var containers []map[string]interface{} if err := client.GetJSON("/containers/json?all=true", &containers); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") if containers == nil { w.Write([]byte("[]")) } else { json.NewEncoder(w).Encode(containers) } } func StartContainerHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) { if resp, err := client.Do("POST", fmt.Sprintf("/containers/%s/start", id), nil); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { defer resp.Body.Close() w.WriteHeader(resp.StatusCode) } } func StopContainerHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) { if resp, err := client.Do("POST", fmt.Sprintf("/containers/%s/stop", id), nil); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { defer resp.Body.Close() w.WriteHeader(resp.StatusCode) } } func RestartContainerHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) { if resp, err := client.Do("POST", fmt.Sprintf("/containers/%s/restart", id), nil); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { defer resp.Body.Close() w.WriteHeader(resp.StatusCode) } } func RemoveContainerHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) { if resp, err := client.Do("DELETE", fmt.Sprintf("/containers/%s?force=true", id), nil); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { defer resp.Body.Close() w.WriteHeader(resp.StatusCode) } } func GetLogsHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) { body, err := client.DoStream("GET", fmt.Sprintf("/containers/%s/logs?stdout=true&stderr=true&tail=200", id), nil) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer body.Close() // Docker logs returns docker stream format, need to parse it logs := parseLogs(body) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{"logs": logs}) } // Docker log stream format: [8 bytes header][payload] // Header: [1 byte stream type][3 bytes padding][4 bytes payload length] func parseLogs(body io.Reader) string { var result string buffer := make([]byte, 4096) for { n, err := body.Read(buffer) if err != nil && err != io.EOF { break } if n == 0 { break } // Parse docker stream format data := buffer[:n] for i := 0; i < len(data); { if i+8 > len(data) { break } // Skip 8-byte header i += 8 // Read until next header or end start := i for i < len(data) && i+8 <= len(data) { i += 8 if i > len(data) { i = len(data) break } } if start < len(data) { result += string(data[start : len(data)]) i = len(data) } } } // Fallback: if stream format parsing fails, just return the raw data as text if result == "" { return string(buffer) } return result }