package main import ( "docker-manager/docker" "docker-manager/handlers" "fmt" "net/http" "os" "strings" ) func main() { // 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 }