Add initial project files
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"docker-manager/docker"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ListImagesHandler(w http.ResponseWriter, r *http.Request, client *docker.Client) {
|
||||
var images []map[string]interface{}
|
||||
if err := client.GetJSON("/images/json", &images); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if images == nil {
|
||||
w.Write([]byte("[]"))
|
||||
} else {
|
||||
json.NewEncoder(w).Encode(images)
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveImageHandler(w http.ResponseWriter, r *http.Request, client *docker.Client, id string) {
|
||||
if resp, err := client.Do("DELETE", fmt.Sprintf("/images/%s?force=true", id), nil); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
} else {
|
||||
defer resp.Body.Close()
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func PullImageHandler(w http.ResponseWriter, r *http.Request, client *docker.Client) {
|
||||
name := r.URL.Query().Get("name")
|
||||
if name == "" {
|
||||
http.Error(w, "name parameter required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Strip tag if contains ":"
|
||||
ref := name
|
||||
if strings.Contains(name, ":") {
|
||||
parts := strings.Split(name, ":")
|
||||
ref = parts[0]
|
||||
}
|
||||
|
||||
body, err := client.DoStream("POST", fmt.Sprintf("/images/create?fromImage=%s", ref), nil)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
|
||||
// Stream pull progress as JSON lines
|
||||
decoder := json.NewDecoder(body)
|
||||
for {
|
||||
var line map[string]interface{}
|
||||
if err := decoder.Decode(&line); err != nil {
|
||||
break
|
||||
}
|
||||
json.NewEncoder(w).Encode(line)
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"docker-manager/docker"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func InfoHandler(w http.ResponseWriter, r *http.Request, client *docker.Client) {
|
||||
var info map[string]interface{}
|
||||
if err := client.GetJSON("/info", &info); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(info)
|
||||
}
|
||||
Reference in New Issue
Block a user