ff3af39973
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
147 lines
3.8 KiB
Go
147 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"docker-manager/docker"
|
|
"docker-manager/handlers"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"runtime/debug"
|
|
"strings"
|
|
)
|
|
|
|
func main() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
fmt.Fprintf(os.Stderr, "PANIC: %v\n", r)
|
|
debug.PrintStack()
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
|
|
// Detect Docker socket
|
|
socketPath := docker.DetectSocket()
|
|
fmt.Printf("Using Docker socket: %s\n", socketPath)
|
|
|
|
client := docker.NewClient(socketPath)
|
|
|
|
// Create router
|
|
mux := http.NewServeMux()
|
|
|
|
// API routes
|
|
mux.HandleFunc("/api/info", corsMiddleware(func(w http.ResponseWriter, r *http.Request) {
|
|
handlers.InfoHandler(w, r, client)
|
|
}))
|
|
|
|
mux.HandleFunc("/api/containers", corsMiddleware(func(w http.ResponseWriter, r *http.Request) {
|
|
handlers.ListContainersHandler(w, r, client)
|
|
}))
|
|
|
|
mux.HandleFunc("/api/images", corsMiddleware(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "GET" {
|
|
handlers.ListImagesHandler(w, r, client)
|
|
}
|
|
}))
|
|
|
|
mux.HandleFunc("/api/", corsMiddleware(func(w http.ResponseWriter, r *http.Request) {
|
|
handleDynamicRoutes(w, r, client)
|
|
}))
|
|
|
|
// Serve static files
|
|
mux.Handle("/", http.FileServer(http.Dir("static")))
|
|
|
|
// Get port from env or default to 3000
|
|
port := os.Getenv("PORT")
|
|
if port == "" {
|
|
port = "3000"
|
|
}
|
|
|
|
addr := fmt.Sprintf(":%s", port)
|
|
fmt.Printf("Starting server on %s\n", addr)
|
|
if err := http.ListenAndServe(addr, mux); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Server error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func corsMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
|
|
|
if r.Method == "OPTIONS" {
|
|
w.WriteHeader(http.StatusOK)
|
|
return
|
|
}
|
|
|
|
next(w, r)
|
|
}
|
|
}
|
|
|
|
func handleDynamicRoutes(w http.ResponseWriter, r *http.Request, client *docker.Client) {
|
|
path := r.URL.Path
|
|
|
|
// /api/containers/{id}/start
|
|
if strings.HasSuffix(path, "/start") && strings.HasPrefix(path, "/api/containers/") {
|
|
id := extractID(path, "/api/containers/", "/start")
|
|
handlers.StartContainerHandler(w, r, client, id)
|
|
return
|
|
}
|
|
|
|
// /api/containers/{id}/stop
|
|
if strings.HasSuffix(path, "/stop") && strings.HasPrefix(path, "/api/containers/") {
|
|
id := extractID(path, "/api/containers/", "/stop")
|
|
handlers.StopContainerHandler(w, r, client, id)
|
|
return
|
|
}
|
|
|
|
// /api/containers/{id}/restart
|
|
if strings.HasSuffix(path, "/restart") && strings.HasPrefix(path, "/api/containers/") {
|
|
id := extractID(path, "/api/containers/", "/restart")
|
|
handlers.RestartContainerHandler(w, r, client, id)
|
|
return
|
|
}
|
|
|
|
// /api/containers/{id} DELETE
|
|
if strings.HasPrefix(path, "/api/containers/") && r.Method == "DELETE" {
|
|
id := strings.TrimPrefix(path, "/api/containers/")
|
|
id = strings.TrimSuffix(id, "/")
|
|
if id != "" && !strings.Contains(id, "/") {
|
|
handlers.RemoveContainerHandler(w, r, client, id)
|
|
return
|
|
}
|
|
}
|
|
|
|
// /api/containers/{id}/logs
|
|
if strings.HasSuffix(path, "/logs") && strings.HasPrefix(path, "/api/containers/") {
|
|
id := extractID(path, "/api/containers/", "/logs")
|
|
handlers.GetLogsHandler(w, r, client, id)
|
|
return
|
|
}
|
|
|
|
// /api/images/{id} DELETE
|
|
if strings.HasPrefix(path, "/api/images/") && r.Method == "DELETE" {
|
|
id := strings.TrimPrefix(path, "/api/images/")
|
|
id = strings.TrimSuffix(id, "/")
|
|
if id != "" && !strings.Contains(id, "/") {
|
|
handlers.RemoveImageHandler(w, r, client, id)
|
|
return
|
|
}
|
|
}
|
|
|
|
// /api/images/pull POST
|
|
if r.Method == "GET" && strings.HasPrefix(path, "/api/images/pull") {
|
|
handlers.PullImageHandler(w, r, client)
|
|
return
|
|
}
|
|
|
|
http.Error(w, "Not Found", http.StatusNotFound)
|
|
}
|
|
|
|
func extractID(path, prefix, suffix string) string {
|
|
id := strings.TrimPrefix(path, prefix)
|
|
id = strings.TrimSuffix(id, suffix)
|
|
return id
|
|
}
|